diff --git a/libs/image/tiles3/KisOptimizedTileDataList.h b/libs/image/tiles3/KisOptimizedTileDataList.h index ea280a5..9264d56 100644 --- a/libs/image/tiles3/KisOptimizedTileDataList.h +++ b/libs/image/tiles3/KisOptimizedTileDataList.h @@ -19,11 +19,95 @@ #ifndef KISOPTIMIZEDTILEDATALIST_H #define KISOPTIMIZEDTILEDATALIST_H +#include +#include +#include +#include "kis_lockless_stack.h" +#include "kis_tile_data_interface.h" -class KisOptimizedTileDataList +class KisOptimizedTileDataList; +typedef KisOptimizedTileDataList::iterator KisOptimizedTileDataListIterator; +typedef KisOptimizedTileDataList::const_iterator KisOptimizedTileDataListConstIterator; + + +class KisOptimizedTileDataList : public QLinkedList { public: - KisOptimizedTileDataList(); + //KisOptimizedTileDataList(); + + + void registerTileData(KisTileData *td) { + m_numTiles.ref(); + m_numTiles.fetchAndAddOrdered(td->pixelSize()); + } + + inline int numTiles() const { + return m_numTiles; + } + + inline int memoryMetric() const { + return m_memoryMetric; + } + + void lock() { + m_mutex.lock(); + m_lockCount.ref(); + + KisTileData *td = 0; + while (m_pendingTiles.pop(td)) { + registerTileDataImp(td); + } + + while (m_discardedTiles.pop(td)) { + unregisterTileDataImp(td); + } + } + + void unlock() { + m_mutex.unlock(); + } + + KisOptimizedTileDataListIterator clockIterator() const { + return m_clockIterator; + } + + void setClockIterator(KisOptimizedTileDataListIterator value) { + m_clockIterator = value; + } + +private: + inline void registerTileDataImp(KisTileData *td) { + td->m_listIterator = this->insert(this->end(), td); + } + + inline void unregisterTileDataImp(KisTileData *td) { + KisOptimizedTileDataListIterator tempIterator = td->m_listIterator; + + if(m_clockIterator == tempIterator) { + m_clockIterator = tempIterator + 1; + } + + td->m_listIterator = this->end(); + this->erase(tempIterator); + } + + + +private: + QMutex m_mutex; + + QAtomicInteger m_numTiles; + QAtomicInteger m_memoryMetric; + + QAtomicInteger m_lockCount; + + KisOptimizedTileDataListIterator m_clockIterator; + + KisLocklessStack m_pendingTiles; + KisLocklessStack m_discardedTiles; }; +typedef KisOptimizedTileDataList::iterator KisOptimizedTileDataListIterator; +typedef KisOptimizedTileDataList::const_iterator KisOptimizedTileDataListConstIterator; + #endif // KISOPTIMIZEDTILEDATALIST_H diff --git a/libs/image/tiles3/kis_tile_data.h b/libs/image/tiles3/kis_tile_data.h index dee8a37..03f881b 100644 --- a/libs/image/tiles3/kis_tile_data.h +++ b/libs/image/tiles3/kis_tile_data.h @@ -78,14 +78,14 @@ inline bool KisTileData::deref() { bool _ref; if (!(_ref = m_refCount.deref())) { - m_store->freeTileData(this); + m_store->freeTileDataOptimized(this); return 0; } return _ref; } inline KisTileData* KisTileData::clone() { - return m_store->duplicateTileData(this); + return m_store->duplicateTileDataOptimized(this); } inline void KisTileData::blockSwapping() { diff --git a/libs/image/tiles3/kis_tile_data_store.cc b/libs/image/tiles3/kis_tile_data_store.cc index 38978fb..d2546ba 100644 --- a/libs/image/tiles3/kis_tile_data_store.cc +++ b/libs/image/tiles3/kis_tile_data_store.cc @@ -96,7 +96,9 @@ KisTileDataStore* KisTileDataStore::instance() KisTileDataStore::MemoryStatistics KisTileDataStore::memoryStatistics() { - QMutexLocker lock(&m_listLock); + //QMutexLocker lock(&m_listLock); + + lockList(); MemoryStatistics stats; @@ -110,6 +112,8 @@ KisTileDataStore::MemoryStatistics KisTileDataStore::memoryStatistics() stats.swapSize = m_swappedStore.totalMemoryMetric() * metricCoeff; + unlockList(); + return stats; } @@ -140,16 +144,17 @@ inline void KisTileDataStore::unregisterTileDataImp(KisTileData *td) m_memoryMetric -= td->pixelSize(); } -void KisTileDataStore::unregisterTileData(KisTileData *td) +KisTileData *KisTileDataStore::createDefaultTileData(qint32 pixelSize, const quint8 *defPixel) { - QMutexLocker lock(&m_listLock); - unregisterTileDataImp(td); + KisTileData *td = new KisTileData(pixelSize, defPixel, this); + registerTileData(td); + return td; } -KisTileData *KisTileDataStore::allocTileData(qint32 pixelSize, const quint8 *defPixel) +KisTileData *KisTileDataStore::createDefaultTileDataOptimized(qint32 pixelSize, const quint8 *defPixel) { KisTileData *td = new KisTileData(pixelSize, defPixel, this); - registerTileData(td); + m_pendingTiles.push(td); return td; } @@ -172,6 +177,25 @@ KisTileData *KisTileDataStore::duplicateTileData(KisTileData *rhs) return td; } +KisTileData *KisTileDataStore::duplicateTileDataOptimized(KisTileData *rhs) +{ + KisTileData *td = 0; + + if (rhs->m_clonesStack.pop(td)) { + DEBUG_PRECLONE_ACTION("+ Pre-clone HIT", rhs, td); + DEBUG_COUNT_PRECLONE_HIT(rhs); + } else { + rhs->blockSwapping(); + td = new KisTileData(*rhs); + rhs->unblockSwapping(); + DEBUG_PRECLONE_ACTION("- Pre-clone #MISS#", rhs, td); + DEBUG_COUNT_PRECLONE_MISS(rhs); + } + + m_pendingTiles.push(td); + return td; +} + void KisTileDataStore::freeTileData(KisTileData *td) { Q_ASSERT(td->m_store == this); @@ -194,6 +218,11 @@ void KisTileDataStore::freeTileData(KisTileData *td) delete td; } +void KisTileDataStore::freeTileDataOptimized(KisTileData *td) +{ + m_discardedTiles.push(td); +} + void KisTileDataStore::ensureTileDataLoaded(KisTileData *td) { // dbgKrita << "#### SWAP MISS! ####" << td << ppVar(td->mementoed()) << ppVar(td->age()) << ppVar(td->numUsers()); @@ -263,37 +292,43 @@ bool KisTileDataStore::trySwapTileData(KisTileData *td) KisTileDataStoreIterator* KisTileDataStore::beginIteration() { - m_listLock.lock(); + //m_listLock.lock(); + lockList(); return new KisTileDataStoreIterator(m_tileDataList, this); } void KisTileDataStore::endIteration(KisTileDataStoreIterator* iterator) { delete iterator; - m_listLock.unlock(); + unlockList(); + //m_listLock.unlock(); } KisTileDataStoreReverseIterator* KisTileDataStore::beginReverseIteration() { - m_listLock.lock(); + //m_listLock.lock(); + lockList(); return new KisTileDataStoreReverseIterator(m_tileDataList, this); } void KisTileDataStore::endIteration(KisTileDataStoreReverseIterator* iterator) { delete iterator; - m_listLock.unlock(); + //m_listLock.unlock(); + unlockList(); DEBUG_REPORT_PRECLONE_EFFICIENCY(); } KisTileDataStoreClockIterator* KisTileDataStore::beginClockIteration() { - m_listLock.lock(); + //m_listLock.lock(); + lockList(); return new KisTileDataStoreClockIterator(m_clockIterator, m_tileDataList, this); } void KisTileDataStore::endIteration(KisTileDataStoreClockIterator* iterator) { m_clockIterator = iterator->getFinalPosition(); delete iterator; - m_listLock.unlock(); + //m_listLock.unlock(); + unlockList(); } void KisTileDataStore::debugPrintList() @@ -323,7 +358,8 @@ void KisTileDataStore::debugSwapAll() void KisTileDataStore::debugClear() { - QMutexLocker lock(&m_listLock); + //QMutexLocker lock(&m_listLock); + lockList(); Q_FOREACH (KisTileData *item, m_tileDataList) { delete item; @@ -334,6 +370,8 @@ void KisTileDataStore::debugClear() m_numTiles = 0; m_memoryMetric = 0; + + unlockList(); } void KisTileDataStore::testingRereadConfig() { @@ -342,6 +380,25 @@ void KisTileDataStore::testingRereadConfig() { kickPooler(); } +void KisTileDataStore::lockList() +{ + KisTileData *td = 0; + while (m_pendingTiles.pop(td)) { + registerTileData(td); + } + + while (m_discardedTiles.pop(td)) { + freeTileData(td); + } + + m_listLock.lock(); +} + +void KisTileDataStore::unlockList() +{ + m_listLock.unlock(); +} + void KisTileDataStore::testingSuspendPooler() { m_pooler.terminatePooler(); diff --git a/libs/image/tiles3/kis_tile_data_store.h b/libs/image/tiles3/kis_tile_data_store.h index 4477c3b..9582935 100644 --- a/libs/image/tiles3/kis_tile_data_store.h +++ b/libs/image/tiles3/kis_tile_data_store.h @@ -90,9 +90,8 @@ public: KisTileDataStoreClockIterator* beginClockIteration(); void endIteration(KisTileDataStoreClockIterator* iterator); - inline KisTileData* createDefaultTileData(qint32 pixelSize, const quint8 *defPixel) { - return allocTileData(pixelSize, defPixel); - } + KisTileData* createDefaultTileData(qint32 pixelSize, const quint8 *defPixel); + KisTileData* createDefaultTileDataOptimized(qint32 pixelSize, const quint8 *defPixel); // Called by The Memento Manager after every commit inline void kickPooler() { @@ -116,8 +115,10 @@ public: */ KisTileData *duplicateTileData(KisTileData *rhs); + KisTileData *duplicateTileDataOptimized(KisTileData *rhs); void freeTileData(KisTileData *td); + void freeTileDataOptimized(KisTileData *td); /** * Ensures that the tile data is totally present in memory @@ -132,10 +133,7 @@ public: void ensureTileDataLoaded(KisTileData *td); private: - KisTileData *allocTileData(qint32 pixelSize, const quint8 *defPixel); - void registerTileData(KisTileData *td); - void unregisterTileData(KisTileData *td); inline void registerTileDataImp(KisTileData *td); inline void unregisterTileDataImp(KisTileData *td); void freeRegisteredTiles(); @@ -151,6 +149,10 @@ private: friend class KisLowMemoryBenchmark; void testingRereadConfig(); + + void lockList(); + void unlockList(); + private: KisTileDataPooler m_pooler; KisTileDataSwapper m_swapper; @@ -163,14 +165,17 @@ private: QMutex m_listLock; KisTileDataList m_tileDataList; - qint32 m_numTiles; + QAtomicInteger m_numTiles; /** * This metric is used for computing the volume * of memory occupied by tile data objects. * metric = num_bytes / (KisTileData::WIDTH * KisTileData::HEIGHT) */ - qint64 m_memoryMetric; + QAtomicInteger m_memoryMetric; + + KisLocklessStack m_pendingTiles; + KisLocklessStack m_discardedTiles; }; template diff --git a/libs/image/tiles3/kis_tiled_data_manager.cc b/libs/image/tiles3/kis_tiled_data_manager.cc index 2191de5..0e3d3c3 100644 --- a/libs/image/tiles3/kis_tiled_data_manager.cc +++ b/libs/image/tiles3/kis_tiled_data_manager.cc @@ -107,7 +107,7 @@ void KisTiledDataManager::setDefaultPixel(const quint8 *defaultPixel) void KisTiledDataManager::setDefaultPixelImpl(const quint8 *defaultPixel) { - KisTileData *td = KisTileDataStore::instance()->createDefaultTileData(pixelSize(), defaultPixel); + KisTileData *td = KisTileDataStore::instance()->createDefaultTileDataOptimized(pixelSize(), defaultPixel); m_hashTable->setDefaultTileData(td); m_mementoManager->setDefaultTileData(td); @@ -369,7 +369,7 @@ void KisTiledDataManager::clear(QRect clearRect, const quint8 *clearPixel) clearRect.width() >= KisTileData::WIDTH && clearRect.height() >= KisTileData::HEIGHT) { - td = KisTileDataStore::instance()->createDefaultTileData(pixelSize, clearPixel); + td = KisTileDataStore::instance()->createDefaultTileDataOptimized(pixelSize, clearPixel); td->acquire(); }