Cache space with "inteligent" swap mechanism. More...
#include <Cache.h>
Public Member Functions | |
Cache () | |
bool | enlarge (CacheItem *item, double finalSize) |
void | free (CacheItem *item, bool saveTemp=true) |
double | freeBytes () const |
double | freeMegaBytes () const |
bool | makeAvailable (const CacheItem *item) |
void | setSize (double nMegaBytes) |
void | setSwapDir (const QDir &d) |
~Cache () | |
Friends | |
class | CacheItem |
Cache space with "inteligent" swap mechanism.
CacheItem can allocate data vectors into a Cache. Cache controls that the total memory does not exceed a maximum number of bytes. If so, already allocated blocks are automatically deallocated if they are not locked.
Contrary to most of the system swaps, this swap mechanism knows what the item usage will be in the next operations avoiding unefficient deallocation of blocks. This "intelligent" deallocation is performed thanks to CacheProcess. They can be created for any process that use a sequence of items. The order of signal usage is stored in advance and it is used to predict the time of next usage. Items that will be used in a far future are preference for deallocation. Items already processed or not included in a CacheProcess have a predicted time set to almost infinite, hence they are deallocated first.
Initializes a cache that manages allocation and deallocation of memory.
The two parameters of a cache are its size in byte and the path of a temporary directory used for swapping if the requested memory for data exceed its size.
References TRACE.
: _mutex(QMutex::Recursive) { TRACE; _loadedBytes=0; _maxLoadedBytes=0; }
QGpCoreTools::Cache::~Cache | ( | ) | [inline] |
It does nothing because the removal of data is the responsability of the CacheItem
{}
bool QGpCoreTools::Cache::enlarge | ( | CacheItem * | item, |
double | finalSize | ||
) |
In all cases the data must be still allocated with its original size. This is not double checked.
References QGpCoreTools::CacheItem::dataSize(), QGpCoreTools::endl(), free(), freeBytes(), QGpCoreTools::AllocatedCacheItem::humanInfo(), QGpCoreTools::CoreApplication::instance(), QGpCoreTools::CoreApplicationPrivate::reportBug(), QGpCoreTools::App::stream(), QGpCoreTools::tr(), TRACE, and QGpCoreTools::Message::Warning.
{ TRACE; // Process low level allocation of data double neededSize=finalSize - (double) item->dataSize(); QMutexLocker ml(&_mutex); if(neededSize>freeBytes()) { // Not enough space in cache if(!free(neededSize)) { QString msg=tr( "Impossible to allocate new data\n" " current used space: %1 Kb\n" " current free space: %2 Kb\n" " current buffer size: %3 Kb\n" " required space: %4 Kb\n" "Increase buffer size, a good compromize is 80% of you physical memory\n" "This buffer is allocated dynamically upon requests, so it will not overload\n" "your memory usage.\n\n") .arg(_loadedBytes/1024.0).arg(freeBytes()/1024.0) .arg(_maxLoadedBytes/1024.0).arg(neededSize/1024.0)+_allocatedList.humanInfo(); App::stream() << msg << endl; CoreApplication::instance()->reportBug(Message::Warning, msg.toAscii().data()); return false; // really not lucky, no more space } // Perfect got memory free } _loadedBytes+=neededSize; return true; }
void QGpCoreTools::Cache::free | ( | CacheItem * | item, |
bool | saveTemp = true |
||
) |
Free data used by item. If saveTemp is false and if data is swaped, the corresponding file is removed. It saveTemp is true and if data is allocated, data is saved to file.
References QGpCoreTools::CacheItem::dataSize(), QGpCoreTools::CacheItem::free(), QGpCoreTools::CacheItem::isAllocated(), QGpCoreTools::AllocatedCacheItem::remove(), QGpCoreTools::CacheItem::save(), QGpCoreTools::CacheItem::swapFileName(), and TRACE.
Referenced by enlarge(), GeopsyCore::SignalTemplate< sampleType >::freeSamples(), makeAvailable(), and GeopsyCore::SignalTemplate< sampleType >::~SignalTemplate().
{ TRACE; if( !saveTemp && item->_saved) { _swapDir.remove(item->swapFileName()); item->_saved=false; } if(item->isAllocated()) { if(saveTemp) { //printf("Saving item %s\n",item->debugName().toAscii().data()); item->save(_swapDir); item->_saved=true; } item->free(); _mutex.lock(); _loadedBytes -= (double) item->dataSize(); _allocatedList.remove(item); _mutex.unlock(); //printf("Freeing item, %i are still allocated\n",_allocatedList.count()); //printf("Freeing %lf Kb from item %s\t\t",(double)item->dataSize()/1024, item->debugName().toAscii().data()); //printf("Free space=%lf Kb\n",freeBytes()/1024); } }
double QGpCoreTools::Cache::freeBytes | ( | ) | const [inline] |
Referenced by enlarge(), and makeAvailable().
{return _maxLoadedBytes -_loadedBytes;}
double QGpCoreTools::Cache::freeMegaBytes | ( | ) | const [inline] |
References INV_MEGABYTES.
Referenced by GeopsyMainWindow::showDBStatus().
{return freeBytes() * INV_MEGABYTES;}
bool QGpCoreTools::Cache::makeAvailable | ( | const CacheItem * | item | ) |
In all cases the data must not be allocated. This is not double checked. In a multi-threaded context, this function must be used by only one thread at a time and lock() of item must be called with this object locked.
References QGpCoreTools::AllocatedCacheItem::add(), QGpCoreTools::CacheItem::allocate(), QGpCoreTools::CacheItem::dataSize(), QGpCoreTools::endl(), free(), freeBytes(), QGpCoreTools::AllocatedCacheItem::humanInfo(), QGpCoreTools::CoreApplication::instance(), QGpCoreTools::CacheItem::load(), QGpCoreTools::CoreApplicationPrivate::reportBug(), QGpCoreTools::App::stream(), QGpCoreTools::CacheItem::swapFileName(), QGpCoreTools::tr(), TRACE, and QGpCoreTools::Message::Warning.
Referenced by GeopsyCore::SignalTemplate< sampleType >::constLockSamples(), GeopsyCore::Signal::constLockSamples(), GeopsyCore::SignalTemplate< sampleType >::lockSamples(), and GeopsyCore::Signal::lockSamples().
{ TRACE; // Process low level allocation of data double neededSize=(double) item->dataSize(); QMutexLocker ml(&_mutex); if(neededSize > freeBytes()) { // Not enough space in cache if(!free(neededSize)) { QString msg=tr( "Impossible to allocate new data\n" " current used space: %1 Kb\n" " current free space: %2 Kb\n" " current buffer size: %3 Kb\n" " required space: %4 Kb\n" "Increase buffer size, a good compromize is 80% of you physical memory\n" "This buffer is allocated dynamically upon requests, so it will not overload\n" "your memory usage.\n\n") .arg(_loadedBytes/1024.0).arg(freeBytes()/1024.0) .arg(_maxLoadedBytes/1024.0).arg(neededSize/1024.0)+_allocatedList.humanInfo(); App::stream() << msg << endl; //CoreApplication::instance()->reportBug(Message::Warning, msg.toAscii().data()); _allocatedList.humanInfo(); return false; // really not lucky, no more space } // Perfect got memory free } if(item->allocate()) { _allocatedList.add(item); _loadedBytes += neededSize; ml.unlock(); if(item->_saved) { //printf("Loading item %s\n",item->debugName().toAscii().data()); item->load(_swapDir); _swapDir.remove(item->swapFileName()); item->_saved=false; } //printf("Allocating %lf Kbytes for item %s\t\t",neededSize/1024, item->debugName().toAscii().data()); //printf("Free space=%lf Kb\n",freeBytes()/1024); return true; } // Impossible to allocate new memory, problem with your computer? QString msg=tr( "Impossible to allocate new data of size %1: current used space: %2 Kb.\n\n") .arg(neededSize) .arg(_loadedBytes * sizeof(double)/1024.0)+_allocatedList.humanInfo(); App::stream() << msg << endl; CoreApplication::instance()->reportBug(Message::Warning, msg.toAscii().data()); return false; }
QGpCoreTools::Cache::setSize | ( | double | nMegaBytes | ) | [inline] |
Set the maximum number of mega bytes that can be allocated simultaneously. The default is 0.
References MEGABYTES.
Referenced by GeopsyCore::GeopsyCoreEngine::GeopsyCoreEngine().
{_maxLoadedBytes=nMegaBytes * MEGABYTES;}
void QGpCoreTools::Cache::setSwapDir | ( | const QDir & | d | ) |
Set the path where to swap. The default is the home directory.
References TRACE.
Referenced by GeopsyCore::GeopsyCoreEngine::GeopsyCoreEngine().
{ TRACE; _swapDir=d; if(_swapDir.exists()) { // clean file that might be left after a crash QStringList filters; filters << "cache_data_*"; QStringList cacheFiles=_swapDir.entryList(filters); for(QStringList::iterator it=cacheFiles.begin();it!=cacheFiles.end();it++) { _swapDir.remove(*it); } } else { _swapDir.mkpath(_swapDir.absolutePath ()); } }
friend class CacheItem [friend] |