[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: Making KMemoryInfo useful (Re: KDE/kdelibs/kdecore)
From: Lubos Lunak <l.lunak () suse ! cz>
Date: 2010-03-20 19:54:59
Message-ID: 201003202054.59814.l.lunak () suse ! cz
[Download RAW message or body]
On Saturday 20 of March 2010, Albert Astals Cid wrote:
> A Dissabte, 20 de març de 2010, Lubos Lunak va escriure:
> > Let's continue only on k-c-d.
> >
> > ... Some bashing ...
I apologize, it wasn't meant to be. And I don't think it was that bad,
although quite possibly I have already seen enough cases of memory measuring
going wrong and really wasn't happy to see kdelibs getting a tool to do it
even easier.
> Ok, so you are the smart dude, how do we solve the problem with
> applications wanting to know how much memory they can use?
See attachment, that is how I would envision the class. I didn't update the
docs and didn't bother with implementing requestMemory() for real, but
otherwise I would hope this is quite clear even without docs:
...
connect( &memoryInfo, SIGNAL( releaseMemoryRequest( size_t )), this, SLOT(
releaseMemory( size_t )));
...
if( I_want_100M_for_cache && memoryInfo.update( KMemoryInfo::AvailableRam ) &&
memoryInfo.detail( KMemoryInfo::AvailableRam ) >= 100 * 1024 * 1024 )
...
if( I_need_300M_to_work )
{
if( memoryInfo.update( KMemoryInfo::AvailableMemory ) &&
memoryInfo.detail( KMemoryInfo::AvailableMemory ) >= 300 * 1024 * 1024 )
do_work();
else if( memoryInfo.requestMemory( 300 * 1024 * 1024 ))
do_work();
...
void Foo::releaseMemory( size_t amount )
{
size_t freed = 0;
while( !cachedObjects.isEmpty() && freed < amount )
{
freed += cachedObjects.first()->size();
delete cachedObjects.takeFirst();
}
}
Any problems with that?
Special bonus: 4.5 release blahblah can somewhere include something along the
lines of "KDE platform now includes support for applications making use of
additional memory when available and keeping their memory usage low when
running short on memory or on low-memory systems". And if people get it wrong
as is the usual case for anything memory-related, with a little luck they may
at least get it wrong the favourable way for a change ("well, yes, my KDE
uses 800M RAM, but that's only because my computer has 2G RAM, see?").
--
Lubos Lunak
openSUSE Boosters team, KDE developer
l.lunak@suse.cz , l.lunak@kde.org
["util.patch" (text/x-diff)]
--- util/kmemoryinfo.h.sav 2010-03-20 20:02:33.014669220 +0100
+++ util/kmemoryinfo.h 2010-03-20 20:35:42.300591488 +0100
@@ -22,6 +22,8 @@
#include <kdecore_export.h>
+#include <QtCore/QObject>
+
class QDateTime;
class KMemoryInfoData;
@@ -47,21 +49,23 @@ class KMemoryInfoData;
*
* @since 4.5
*/
-class KDECORE_EXPORT KMemoryInfo
+class KDECORE_EXPORT KMemoryInfo : public QObject
{
+Q_OBJECT
public:
/**
* A detail of memory.
*/
enum MemoryDetail
{
- TotalRam = 1,
- FreeRam = 2,
- SharedRam = 4,
- BufferRam = 8,
- CachedRam = 16,
- TotalSwap = 32,
- FreeSwap = 64
+ TotalRam = 1 << 0,
+ AvailableRam = 1 << 1,
+ TotalSwap = 1 << 2,
+ AvailableSwap = 1 << 3,
+ TotalMemory = TotalRam | TotalSwap,
+ AvailableMemory = AvailableRam | AvailableSwap,
+ SystemBuffers = 1 << 4,
+ SystemCaches = 1 << 5
};
Q_DECLARE_FLAGS(MemoryDetails, MemoryDetail)
@@ -69,28 +73,19 @@ public:
* Constructs a memory information object which has no updated information.
* @see update()
*/
- explicit KMemoryInfo();
- /**
- * Copy constructor.
- */
- KMemoryInfo(const KMemoryInfo &info);
+ KMemoryInfo();
/**
* Destructor.
*/
~KMemoryInfo();
/**
- * Assignment operator.
- */
- KMemoryInfo& operator=(const KMemoryInfo &info);
-
- /**
* Returns the specified memory @p detail, as it was read by the last
* update().
* @returns the value of the specified detail if available, or -1 if that
* detail was not requested in the last update()
*/
- qint64 detail(MemoryDetail detail) const;
+ size_t detail(MemoryDetail detail) const;
/**
* Returns the timestamp of the last update, or a null one if the current
* memory information was never updated.
@@ -107,6 +102,11 @@ public:
*/
bool update(MemoryDetails details);
+ bool requestMemory( size_t amount );
+
+Q_SIGNALS:
+ void releaseMemoryRequest( size_t amount );
+
private:
KMemoryInfoData *d;
};
--- util/kmemoryinfo_win.cpp.sav 2010-03-20 19:52:41.000000000 +0100
+++ util/kmemoryinfo_win.cpp 2010-03-20 20:15:38.375669732 +0100
@@ -32,18 +32,15 @@ static bool fillMemoryInfo(KMemoryInfoDa
if (data->details & KMemoryInfo::TotalRam) {
data->totalRam = stat.ullTotalPhys;
}
- if (data->details & KMemoryInfo::FreeRam) {
+ if (data->details & KMemoryInfo::AvailableRam) {
data->freeRam = stat.ullAvailPhys;
}
- // the following three are not available
- if (data->details & KMemoryInfo::SharedRam) {
- data->sharedRam = 0;
+ // the following two are not available
+ if (data->details & KMemoryInfo::SystemBuffers) {
+ data->systemBuffers = 0;
}
- if (data->details & KMemoryInfo::BufferRam) {
- data->bufferRam = 0;
- }
- if (data->details & KMemoryInfo::CachedRam) {
- data->cachedRam = 0;
+ if (data->details & KMemoryInfo::SystemCaches) {
+ data->systemCaches = 0;
}
// instead of the size of the swap partition, use the page file instead
if (data->details & KMemoryInfo::TotalSwap) {
--- util/kmemoryinfo.cpp.sav 2010-03-20 19:52:40.000000000 +0100
+++ util/kmemoryinfo.cpp 2010-03-20 20:37:30.551669277 +0100
@@ -33,22 +33,20 @@ struct KMemoryInfoData
KMemoryInfo::MemoryDetails details;
QDateTime lastUpdate;
- qint64 totalRam;
- qint64 freeRam;
- qint64 sharedRam;
- qint64 bufferRam;
- qint64 cachedRam;
- qint64 totalSwap;
- qint64 freeSwap;
+ size_t totalRam;
+ size_t freeRam;
+ size_t systemBuffers;
+ size_t systemCaches;
+ size_t totalSwap;
+ size_t freeSwap;
};
void KMemoryInfoData::clear()
{
totalRam = -1;
freeRam = -1;
- sharedRam = -1;
- bufferRam = -1;
- cachedRam = -1;
+ systemBuffers = -1;
+ systemCaches = -1;
totalSwap = -1;
freeSwap = -1;
}
@@ -61,41 +59,31 @@ KMemoryInfo::KMemoryInfo()
{
}
-KMemoryInfo::KMemoryInfo(const KMemoryInfo &info)
- : d(new KMemoryInfoData(*info.d))
-{
-}
-
KMemoryInfo::~KMemoryInfo()
{
delete d;
}
-KMemoryInfo& KMemoryInfo::operator=(const KMemoryInfo &info)
-{
- if (this != &info) {
- *d = *info.d;
- }
- return *this;
-}
-
-qint64 KMemoryInfo::detail(KMemoryInfo::MemoryDetail detail) const
+size_t KMemoryInfo::detail(KMemoryInfo::MemoryDetail detail) const
{
switch (detail) {
case KMemoryInfo::TotalRam:
return d->totalRam;
- case KMemoryInfo::FreeRam:
- return d->freeRam;
- case KMemoryInfo::SharedRam:
- return d->sharedRam;
- case KMemoryInfo::BufferRam:
- return d->bufferRam;
- case KMemoryInfo::CachedRam:
- return d->cachedRam;
+ case KMemoryInfo::AvailableRam:
+ // the system may free buffers and caches if necessary, so it's available in practice
+ return d->freeRam + d->systemBuffers + d->systemCaches;
+ case KMemoryInfo::SystemBuffers:
+ return d->systemBuffers;
+ case KMemoryInfo::SystemCaches:
+ return d->systemCaches;
case KMemoryInfo::TotalSwap:
return d->totalSwap;
- case KMemoryInfo::FreeSwap:
+ case KMemoryInfo::AvailableSwap:
return d->freeSwap;
+ case KMemoryInfo::TotalMemory:
+ return this->detail( TotalRam ) + this->detail( TotalSwap );
+ case KMemoryInfo::AvailableMemory:
+ return this->detail( AvailableRam ) + this->detail( AvailableSwap );
}
return -1;
@@ -120,6 +108,16 @@ bool KMemoryInfo::update(KMemoryInfo::Me
return res;
}
+bool KMemoryInfo::requestMemory( size_t amount )
+{
+// TODO this should signal to other apps and emit releaseMemoryRequest()
+// in them until available memory is at least the given amount.
+// For now, just check.
+ if( !update( d->details | AvailableRam | AvailableSwap ))
+ return false;
+ return detail( AvailableRam ) + detail( AvailableSwap ) >= amount;
+}
+
#if defined(Q_OS_LINUX)
# include "kmemoryinfo_linux.cpp"
#elif defined(Q_OS_WIN32)
@@ -138,3 +136,4 @@ static bool fillMemoryInfo(KMemoryInfoDa
#endif
+#include "kmemoryinfo.moc"
--- util/kmemoryinfo_linux.cpp.sav 2010-03-20 19:52:40.000000000 +0100
+++ util/kmemoryinfo_linux.cpp 2010-03-20 20:15:30.665669799 +0100
@@ -33,32 +33,29 @@ static bool fillMemoryInfo(KMemoryInfoDa
if (data->details & KMemoryInfo::TotalRam) {
data->totalRam = unit * info.totalram;
}
- if (data->details & KMemoryInfo::FreeRam) {
+ if (data->details & KMemoryInfo::AvailableRam) {
data->freeRam = unit * info.freeram;
}
- if (data->details & KMemoryInfo::SharedRam) {
- data->sharedRam = unit * info.sharedram;
- }
- if (data->details & KMemoryInfo::BufferRam) {
- data->bufferRam = unit * info.bufferram;
+ if (data->details & KMemoryInfo::SystemBuffers) {
+ data->systemBuffers = unit * info.bufferram;
}
if (data->details & KMemoryInfo::TotalSwap) {
data->totalSwap = unit * info.totalswap;
}
- if (data->details & KMemoryInfo::FreeSwap) {
+ if (data->details & KMemoryInfo::AvailableSwap) {
data->freeSwap = unit * info.freeswap;
}
// open meminfo only for reading "cached"
- if (data->details & KMemoryInfo::CachedRam) {
- data->cachedRam = 0;
+ if (data->details & KMemoryInfo::SystemCaches) {
+ data->systemCaches = 0;
FILE *meminfo = fopen("/proc/meminfo", "r");
if (meminfo) {
char buffer[100];
char *end = 0;
while(fgets(buffer, sizeof(buffer) - 1, meminfo)) {
if (memcmp(buffer, "Cached:", 7) == 0) {
- data->cachedRam = strtol(buffer + 7, &end, 10);
+ data->systemCaches = strtol(buffer + 7, &end, 10);
break;
}
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic