[calligra/krita-bounded-pooler-kazakov] krita/image: Implemented a new bounded tile data pooler
Dmitry Kazakov
dimula73 at gmail.com
Sun Mar 6 20:18:40 CET 2011
Git commit e09e0f0b9db6e95aa8a35c879c2d9b530f48d838 by Dmitry Kazakov.
Committed on 06/03/2011 at 19:38.
Pushed by dkazakov into branch 'krita-bounded-pooler-kazakov'.
Implemented a new bounded tile data pooler
(!) Important notice: it would be more safe to perform 'make clean'
in krita/image/ directory if you decide to switch to this branch
Well, this commit implements a new memory-bounded pooler thread. The
configuration of the pool is done using a special option
"memoryPoolLimitPercent". It sets the percent of the memory, that you
would like to spend on the tiles pool. Please notice, that this value
is included in hard/soft limits as well. That means Krita will never
take more than Hard Limit memory on tiles and clones together.
This implementation performs not full power yet. I haven't done any
optimizations, so the highest efficiency it can reach now is 50% of
tiles pre-clone hits. I could get this numbers on gradient tool and on
very short brush strokes. It is quite curious, but the longer stroke
you do, the less efficient the pooler is. I hope i'll get it fixed
soon.
CCMAIL:kimageshop at kde.org
M +19 -4 krita/image/kis_image_config.cpp
M +5 -2 krita/image/kis_image_config.h
M +1 -0 krita/image/tiles3/kis_tile_data_interface.h
M +166 -26 krita/image/tiles3/kis_tile_data_pooler.cc
M +19 -3 krita/image/tiles3/kis_tile_data_pooler.h
M +33 -8 krita/image/tiles3/kis_tile_data_store.cc
M +9 -1 krita/image/tiles3/kis_tile_data_store.h
M +2 -7 krita/image/tiles3/swap/kis_tile_data_swapper_p.h
M +5 -0 krita/image/tiles3/tests/CMakeLists.txt
M +6 -4 krita/image/tiles3/tests/kis_store_limits_test.cpp
A +111 -0 krita/image/tiles3/tests/kis_tile_data_pooler_test.cpp [License: GPL (v2+)]
A +32 -0 krita/image/tiles3/tests/kis_tile_data_pooler_test.h [License: GPL (v2+)]
http://commits.kde.org/calligra/e09e0f0b9db6e95aa8a35c879c2d9b530f48d838
diff --git a/krita/image/kis_image_config.cpp b/krita/image/kis_image_config.cpp
index 6911b8c..6724bf3 100644
--- a/krita/image/kis_image_config.cpp
+++ b/krita/image/kis_image_config.cpp
@@ -107,14 +107,19 @@ void KisImageConfig::setSwapWindowSize(int value)
m_config.writeEntry("swapWindowSize", value);
}
-int KisImageConfig::memoryHardLimit() const
+int KisImageConfig::tilesHardLimit() const
{
- return totalRAM() * memoryHardLimitPercent() / 100;
+ return totalRAM() * (memoryHardLimitPercent() - memoryPoolLimitPercent()) / 100;
}
-int KisImageConfig::memorySoftLimit() const
+int KisImageConfig::tilesSoftLimit() const
{
- return totalRAM() * memorySoftLimitPercent() / 100;
+ return totalRAM() * (memorySoftLimitPercent() - memoryPoolLimitPercent()) / 100;
+}
+
+int KisImageConfig::poolLimit() const
+{
+ return totalRAM() * memoryPoolLimitPercent() / 100;
}
qreal KisImageConfig::memoryHardLimitPercent() const
@@ -137,6 +142,16 @@ void KisImageConfig::setMemorySoftLimitPercent(qreal value)
m_config.writeEntry("memorySoftLimitPercent", value);
}
+qreal KisImageConfig::memoryPoolLimitPercent() const
+{
+ return m_config.readEntry("memoryPoolLimitPercent", 2.);
+}
+
+void KisImageConfig::setMemoryPoolLimitPercent(qreal value)
+{
+ m_config.writeEntry("memoryPoolLimitPercent", value);
+}
+
#if defined Q_OS_LINUX
#include <sys/sysinfo.h>
diff --git a/krita/image/kis_image_config.h b/krita/image/kis_image_config.h
index 3473ffe..17d1d6e 100644
--- a/krita/image/kis_image_config.h
+++ b/krita/image/kis_image_config.h
@@ -50,13 +50,16 @@ public:
int swapWindowSize() const;
void setSwapWindowSize(int value);
- int memoryHardLimit() const; // MiB
- int memorySoftLimit() const; // MiB
+ int tilesHardLimit() const; // MiB
+ int tilesSoftLimit() const; // MiB
+ int poolLimit() const; // MiB
qreal memoryHardLimitPercent() const; // % of total RAM
qreal memorySoftLimitPercent() const; // % of total RAM
+ qreal memoryPoolLimitPercent() const; // % of total RAM
void setMemoryHardLimitPercent(qreal value);
void setMemorySoftLimitPercent(qreal value);
+ void setMemoryPoolLimitPercent(qreal value);
static int totalRAM(); // MiB
diff --git a/krita/image/tiles3/kis_tile_data_interface.h b/krita/image/tiles3/kis_tile_data_interface.h
index f52ae2e..321b5ac 100644
--- a/krita/image/tiles3/kis_tile_data_interface.h
+++ b/krita/image/tiles3/kis_tile_data_interface.h
@@ -169,6 +169,7 @@ private:
static void freeData(quint8 *ptr, const qint32 pixelSize);
private:
friend class KisTileDataPooler;
+ friend class KisTileDataPoolerTest;
/**
* A list of pre-duplicated tiledatas.
* To make a COW faster, KisTileDataPooler thread duplicates
diff --git a/krita/image/tiles3/kis_tile_data_pooler.cc b/krita/image/tiles3/kis_tile_data_pooler.cc
index dd0aaf5..b8e30c7 100644
--- a/krita/image/tiles3/kis_tile_data_pooler.cc
+++ b/krita/image/tiles3/kis_tile_data_pooler.cc
@@ -23,6 +23,8 @@
#include "kis_tile_data_store_iterators.h"
#include "kis_debug.h"
#include "kis_tile_data_pooler.h"
+#include "kis_image_config.h"
+
const qint32 KisTileDataPooler::MAX_NUM_CLONES = 16;
const qint32 KisTileDataPooler::MAX_TIMEOUT = 60000; // 01m00s
@@ -51,21 +53,52 @@ const qint32 KisTileDataPooler::TIMEOUT_FACTOR = 2;
} while(0) \
#define DEBUG_TILE_STATISTICS() debugTileStatistics()
+
+#define DEBUG_LISTS(mem, beggers, beggersMem, donors, donorsMem) \
+ do { \
+ qDebug() << "--- getLists finished ---"; \
+ qDebug() << " memoryOccupied:" << mem << "/" << m_memoryLimit; \
+ qDebug() << " donors:" << donors.size() \
+ << "(mem:" << donorsMem << ")"; \
+ qDebug() << " beggers:" << beggers.size() \
+ << "(mem:" << beggersMem << ")"; \
+ qDebug() << "--- ----------------- ---"; \
+ } while(0)
+
+#define DEBUG_ALLOC_CLONE(mem, totalMem) \
+ qDebug() << "Alloc mem for clones:" << mem \
+ << "\tMem usage:" << totalMem << "/" << m_memoryLimit
+
+#define DEBUG_FREE_CLONE(freed, demanded) \
+ qDebug() << "Freed mem for clones:" << freed \
+ << "/" << qAbs(demanded)
+
#else
#define DEBUG_CLONE_ACTION(td, numClones)
#define DEBUG_SIMPLE_ACTION(action)
#define RUNTIME_SANITY_CHECK(td)
#define DEBUG_TILE_STATISTICS()
+#define DEBUG_LISTS(mem, beggers, beggersMem, donors, donorsMem)
+#define DEBUG_ALLOC_CLONE(mem, totalMem)
+#define DEBUG_FREE_CLONE(freed, demanded)
#endif
-KisTileDataPooler::KisTileDataPooler(KisTileDataStore *store)
- : QThread()
+KisTileDataPooler::KisTileDataPooler(KisTileDataStore *store, qint32 memoryLimit)
+ : QThread()
{
m_shouldExitFlag = 0;
m_store = store;
m_timeout = MIN_TIMEOUT;
m_lastCycleHadWork = false;
+
+ if(memoryLimit >= 0) {
+ m_memoryLimit = memoryLimit;
+ }
+ else {
+ KisImageConfig config;
+ m_memoryLimit = MiB_TO_METRIC(config.poolLimit());
+ }
}
KisTileDataPooler::~KisTileDataPooler()
@@ -137,19 +170,10 @@ void KisTileDataPooler::waitForWork()
}
}
-inline bool KisTileDataPooler::interestingTileData(KisTileData* td)
-{
- /**
- * We have to look after all clones we created.
- * That is why we recheck all tiles with non-empty clones lists
- */
-
- return td->m_state == KisTileData::NORMAL &&
- (td->m_usersCount > 1 || !td->m_clonesStack.isEmpty());
-}
-
void KisTileDataPooler::run()
{
+ if(!m_memoryLimit) return;
+
m_shouldExitFlag = false;
while (1) {
@@ -165,19 +189,14 @@ void KisTileDataPooler::run()
KisTileDataStoreReverseIterator *iter = m_store->beginReverseIteration();
- KisTileData *item;
-
- while(iter->hasNext()) {
- item = iter->next();
- if (interestingTileData(item)) {
-
- qint32 clonesNeeded = numClonesNeeded(item);
- if (clonesNeeded) {
- m_lastCycleHadWork = true;
- cloneTileData(item, clonesNeeded);
- }
- }
- }
+ QList<KisTileData*> beggers;
+ QList<KisTileData*> donors;
+ qint32 memoryOccupied;
+
+ getLists(iter, beggers, donors, memoryOccupied);
+
+ m_lastCycleHadWork =
+ processLists(beggers, donors, memoryOccupied);
m_store->endIteration(iter);
@@ -187,6 +206,127 @@ void KisTileDataPooler::run()
}
}
+inline int KisTileDataPooler::clonesMetric(KisTileData *td, int numClones) {
+ return numClones * td->pixelSize();
+}
+
+inline int KisTileDataPooler::clonesMetric(KisTileData *td) {
+ return td->m_clonesStack.size() * td->pixelSize();
+}
+
+inline void KisTileDataPooler::tryFreeOrphanedClones(KisTileData *td)
+{
+ qint32 extraClones = -numClonesNeeded(td);
+
+ if(extraClones > 0) {
+ cloneTileData(td, -extraClones);
+ }
+}
+
+inline qint32 KisTileDataPooler::needMemory(KisTileData *td)
+{
+ qint32 clonesNeeded = !td->age() ? qMax(0, numClonesNeeded(td)) : 0;
+ return clonesMetric(td, clonesNeeded);
+}
+
+inline qint32 KisTileDataPooler::canDonorMemory(KisTileData *td)
+{
+ return td->age() && clonesMetric(td);
+}
+
+template<class Iter>
+void KisTileDataPooler::getLists(Iter *iter,
+ QList<KisTileData*> &beggers,
+ QList<KisTileData*> &donors,
+ qint32 &memoryOccupied)
+{
+ memoryOccupied = 0;
+
+ qint32 needMemoryTotal = 0;
+ qint32 canDonorMemoryTotal = 0;
+
+ qint32 neededMemory;
+ qint32 donoredMemory;
+
+ KisTileData *item;
+
+ while(iter->hasNext()) {
+ item = iter->next();
+
+ tryFreeOrphanedClones(item);
+
+ if((neededMemory = needMemory(item))) {
+ needMemoryTotal += neededMemory;
+ beggers.append(item);
+ }
+ else if((donoredMemory = canDonorMemory(item))) {
+ canDonorMemoryTotal += donoredMemory;
+ donors.append(item);
+ }
+
+ memoryOccupied += clonesMetric(item);
+ }
+
+ DEBUG_LISTS(memoryOccupied,
+ beggers, needMemoryTotal,
+ donors, canDonorMemoryTotal);
+}
+
+qint32 KisTileDataPooler::tryGetMemory(QList<KisTileData*> &donors,
+ qint32 memoryMetric)
+{
+ qint32 memoryFreed = 0;
+
+ QMutableListIterator<KisTileData*> iter(donors);
+ iter.toBack();
+
+ while(iter.hasPrevious() && memoryFreed < memoryMetric) {
+ KisTileData *item = iter.previous();
+
+ qint32 numClones = item->m_clonesStack.size();
+ cloneTileData(item, -numClones);
+ memoryFreed += clonesMetric(item, numClones);
+
+ iter.remove();
+ }
+
+ return memoryFreed;
+}
+
+bool KisTileDataPooler::processLists(QList<KisTileData*> &beggers,
+ QList<KisTileData*> &donors,
+ qint32 memoryOccupied)
+{
+ bool hadWork = false;
+
+
+ foreach(KisTileData *item, beggers) {
+ qint32 clonesNeeded = numClonesNeeded(item);
+ qint32 clonesMemory = clonesMetric(item, clonesNeeded);
+
+ qint32 memoryLeft =
+ m_memoryLimit - (memoryOccupied + clonesMemory);
+
+ if(memoryLeft < 0) {
+ qint32 freedMemory = tryGetMemory(donors, -memoryLeft);
+ memoryOccupied -= freedMemory;
+
+ DEBUG_FREE_CLONE(freedMemory, memoryLeft);
+
+ if(m_memoryLimit < memoryOccupied + clonesMemory)
+ break;
+ }
+
+ cloneTileData(item, clonesNeeded);
+ DEBUG_ALLOC_CLONE(clonesMemory, memoryOccupied);
+
+ memoryOccupied += clonesMemory;
+ hadWork = true;
+ }
+
+ return hadWork;
+}
+
void KisTileDataPooler::debugTileStatistics()
{
/**
diff --git a/krita/image/tiles3/kis_tile_data_pooler.h b/krita/image/tiles3/kis_tile_data_pooler.h
index 99096fc..82a753c 100644
--- a/krita/image/tiles3/kis_tile_data_pooler.h
+++ b/krita/image/tiles3/kis_tile_data_pooler.h
@@ -32,14 +32,13 @@ class KisTileDataPooler : public QThread
public:
- KisTileDataPooler(KisTileDataStore *store);
+ KisTileDataPooler(KisTileDataStore *store, qint32 memoryLimit = -1);
virtual ~KisTileDataPooler();
void kick();
void terminatePooler();
protected:
-
static const qint32 MAX_NUM_CLONES;
static const qint32 MAX_TIMEOUT;
static const qint32 MIN_TIMEOUT;
@@ -49,8 +48,24 @@ protected:
qint32 numClonesNeeded(KisTileData *td) const;
void cloneTileData(KisTileData *td, qint32 numClones) const;
void run();
+
+ inline int clonesMetric(KisTileData *td, int numClones);
+ inline int clonesMetric(KisTileData *td);
+
+ inline void tryFreeOrphanedClones(KisTileData *td);
+ inline qint32 needMemory(KisTileData *td);
+ inline qint32 canDonorMemory(KisTileData *td);
+ qint32 tryGetMemory(QList<KisTileData*> &donors, qint32 memoryMetric);
+
+ template<class Iter>
+ void getLists(Iter *iter, QList<KisTileData*> &beggers,
+ QList<KisTileData*> &donors, qint32 &memoryOccupied);
+
+ bool processLists(QList<KisTileData*> &beggers,
+ QList<KisTileData*> &donors,
+ qint32 memoryOccupied);
+
private:
- bool interestingTileData(KisTileData* td);
void debugTileStatistics();
protected:
QSemaphore m_semaphore;
@@ -58,6 +73,7 @@ protected:
KisTileDataStore *m_store;
qint32 m_timeout;
bool m_lastCycleHadWork;
+ qint32 m_memoryLimit;
};
diff --git a/krita/image/tiles3/kis_tile_data_store.cc b/krita/image/tiles3/kis_tile_data_store.cc
index 20c1dde..140de88 100644
--- a/krita/image/tiles3/kis_tile_data_store.cc
+++ b/krita/image/tiles3/kis_tile_data_store.cc
@@ -42,7 +42,28 @@
#define DEBUG_FREE_ACTION(td)
#endif
-
+#ifdef DEBUG_HIT_MISS
+qint64 __preclone_miss = 0;
+qint64 __preclone_hit = 0;
+
+qint64 __preclone_miss_user_count = 0;
+qint64 __preclone_miss_age = 0;
+
+#define DEBUG_COUNT_PRECLONE_HIT(td) __preclone_hit++
+#define DEBUG_COUNT_PRECLONE_MISS(td) __preclone_miss++; __preclone_miss_user_count+=td->numUsers(); __preclone_miss_age+=td->age()
+#define DEBUG_REPORT_PRECLONE_EFFICIENCY() \
+ qDebug() << "Hits:" << __preclone_hit \
+ << "of" << __preclone_hit + __preclone_miss \
+ << "(" \
+ << qreal(__preclone_hit) / (__preclone_hit + __preclone_miss) \
+ << ")" \
+ << "miss users" << qreal(__preclone_miss_user_count) / __preclone_miss \
+ << "miss age" << qreal(__preclone_miss_age) / __preclone_miss
+#else
+#define DEBUG_COUNT_PRECLONE_HIT(td)
+#define DEBUG_COUNT_PRECLONE_MISS(td)
+#define DEBUG_REPORT_PRECLONE_EFFICIENCY()
+#endif
KisTileDataStore::KisTileDataStore()
: m_pooler(this),
@@ -51,13 +72,13 @@ KisTileDataStore::KisTileDataStore()
m_memoryMetric(0)
{
m_clockIterator = m_tileDataList.end();
-// m_pooler.start();
+ m_pooler.start();
m_swapper.start();
}
KisTileDataStore::~KisTileDataStore()
{
-// m_pooler.terminatePooler();
+ m_pooler.terminatePooler();
m_swapper.terminateSwapper();
if(numTiles() > 0) {
@@ -126,11 +147,13 @@ KisTileData *KisTileDataStore::duplicateTileData(KisTileData *rhs)
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);
}
registerTileData(td);
@@ -231,6 +254,7 @@ void KisTileDataStore::endIteration(KisTileDataStoreReverseIterator* iterator)
{
delete iterator;
m_listLock.unlock();
+ DEBUG_REPORT_PRECLONE_EFFICIENCY();
}
KisTileDataStoreClockIterator* KisTileDataStore::beginClockIteration()
@@ -276,12 +300,13 @@ void KisTileDataStore::debugClear()
{
QMutexLocker lock(&m_listLock);
- KisTileDataListIterator iter = m_tileDataList.begin();
-
- while(iter != m_tileDataList.end()) {
- delete *iter;
- iter = m_tileDataList.erase(iter);
+ foreach(KisTileData *item, m_tileDataList) {
+ delete item;
}
+
+ m_tileDataList.clear();
+ m_numTiles = 0;
+ m_memoryMetric = 0;
}
void KisTileDataStore::testingSuspendPooler()
diff --git a/krita/image/tiles3/kis_tile_data_store.h b/krita/image/tiles3/kis_tile_data_store.h
index 470abe4..93178ab 100644
--- a/krita/image/tiles3/kis_tile_data_store.h
+++ b/krita/image/tiles3/kis_tile_data_store.h
@@ -87,7 +87,7 @@ public:
// Called by The Memento Manager after every commit
inline void kickPooler() {
-// m_pooler.kick();
+ m_pooler.kick();
//FIXME: maybe, rename a function?
m_swapper.kick();
@@ -142,6 +142,7 @@ private:
KisTileDataSwapper m_swapper;
friend class KisTileDataStoreTest;
+ friend class KisTileDataPoolerTest;
KisSwappedDataStore m_swappedStore;
KisTileDataListIterator m_clockIterator;
@@ -158,5 +159,12 @@ private:
qint64 m_memoryMetric;
};
+template<typename T>
+inline T MiB_TO_METRIC(T value)
+{
+ unsigned long long __MiB = 1ULL << 20;
+ return value * (__MiB / (KisTileData::WIDTH * KisTileData::HEIGHT));
+}
+
#endif /* KIS_TILE_DATA_STORE_H_ */
diff --git a/krita/image/tiles3/swap/kis_tile_data_swapper_p.h b/krita/image/tiles3/swap/kis_tile_data_swapper_p.h
index 13fe007..81833eb 100644
--- a/krita/image/tiles3/swap/kis_tile_data_swapper_p.h
+++ b/krita/image/tiles3/swap/kis_tile_data_swapper_p.h
@@ -21,11 +21,6 @@
#include "kis_image_config.h"
#include "tiles3/kis_tile_data.h"
-#define MiB (1ULL << 20)
-
-#define MiB_TO_METRIC(v) (v * (MiB / (KisTileData::WIDTH * KisTileData::HEIGHT)))
-#define METRIC_TO_TILES(metric, pixelSize) (metric / pixelSize)
-
/*
Limits Diagram
@@ -67,8 +62,8 @@ public:
KisStoreLimits() {
KisImageConfig config;
- m_emergencyThreshold = MiB_TO_METRIC(config.memoryHardLimit());
- m_softLimitThreshold = MiB_TO_METRIC(config.memorySoftLimit());
+ m_emergencyThreshold = MiB_TO_METRIC(config.tilesHardLimit());
+ m_softLimitThreshold = MiB_TO_METRIC(config.tilesSoftLimit());
m_hardLimitThreshold = m_emergencyThreshold - m_emergencyThreshold / 8;
m_hardLimit = m_hardLimitThreshold - m_hardLimitThreshold / 8;
diff --git a/krita/image/tiles3/tests/CMakeLists.txt b/krita/image/tiles3/tests/CMakeLists.txt
index f1ea808..f5b88be 100644
--- a/krita/image/tiles3/tests/CMakeLists.txt
+++ b/krita/image/tiles3/tests/CMakeLists.txt
@@ -51,3 +51,8 @@ target_link_libraries(KisTileDataStoreTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_Q
set(kis_store_limits_test_SRCS kis_store_limits_test.cpp ../kis_tile_data.cc )
kde4_add_unit_test(KisStoreLimitsTest TESTNAME krita-image-KisStoreLimitsTest ${kis_store_limits_test_SRCS})
target_link_libraries(KisStoreLimitsTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY})
+
+########### next target ###############
+set(kis_tile_data_pooler_test_SRCS kis_tile_data_pooler_test.cpp ../kis_tile_data.cc ../kis_tile_data_pooler.cc )
+kde4_add_unit_test(KisTileDataPoolerTest TESTNAME krita-image-KisTileDataPoolerTest ${kis_tile_data_pooler_test_SRCS})
+target_link_libraries(KisTileDataPoolerTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY})
diff --git a/krita/image/tiles3/tests/kis_store_limits_test.cpp b/krita/image/tiles3/tests/kis_store_limits_test.cpp
index 507f942..25713cd 100644
--- a/krita/image/tiles3/tests/kis_store_limits_test.cpp
+++ b/krita/image/tiles3/tests/kis_store_limits_test.cpp
@@ -26,14 +26,16 @@
void KisStoreLimitsTest::testLimits()
{
- const int totalRAM = KisImageConfig::totalRAM();
- const int halfRAMMetric = MiB_TO_METRIC(totalRAM / 2);
- const int quarterRAMMetric = MiB_TO_METRIC(totalRAM / 4);
-
KisImageConfig config;
config.setMemoryHardLimitPercent(50);
config.setMemorySoftLimitPercent(25);
+ config.setMemoryPoolLimitPercent(10);
+
+ const int totalRAM = KisImageConfig::totalRAM();
+ // values are shifted because of the pooler part
+ const int halfRAMMetric = MiB_TO_METRIC(int(totalRAM * 0.4));
+ const int quarterRAMMetric = MiB_TO_METRIC(int(totalRAM * 0.15));
KisStoreLimits limits;
diff --git a/krita/image/tiles3/tests/kis_tile_data_pooler_test.cpp b/krita/image/tiles3/tests/kis_tile_data_pooler_test.cpp
new file mode 100644
index 0000000..b944c3c
--- /dev/null
+++ b/krita/image/tiles3/tests/kis_tile_data_pooler_test.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_tile_data_pooler_test.h"
+#include <qtest_kde.h>
+
+#include "tiles3/kis_tiled_data_manager.h"
+
+#include "tiles3/kis_tile_data_store.h"
+#include "tiles3/kis_tile_data_store_iterators.h"
+
+#include "tiles3/kis_tile_data_pooler.h"
+
+#ifdef DEBUG_TILES
+#define PRETTY_TILE(idx, td) \
+ qDebug() << "tile" << i \
+ << "\tusers" << td->numUsers() \
+ << "\tclones" << td->m_clonesStack.size() \
+ << "\tage" << td->age();
+
+#else
+#define PRETTY_TILE(idx, td)
+#endif
+
+void KisTileDataPoolerTest::testCycles()
+{
+ const qint32 pixelSize = 1;
+ quint8 defaultPixel = 128;
+
+ KisTileDataStore::instance()->debugClear();
+
+ for(int i = 0; i < 12; i++) {
+ KisTileData *td =
+ KisTileDataStore::instance()->createDefaultTileData(pixelSize, &defaultPixel);
+
+ for(int j = 0; j < 1 + (2 - i % 3); j++) {
+ td->acquire();
+ }
+
+ if(!(i/6)) {
+ td->markOld();
+ }
+
+ if(!((i / 3) & 1)) {
+ td->m_clonesStack.push(new KisTileData(*td));
+ }
+
+ PRETTY_TILE(i, td);
+ }
+
+ {
+ KisTileDataPooler pooler(KisTileDataStore::instance(), 5);
+ pooler.start();
+ pooler.kick();
+ pooler.kick();
+
+ QTest::qSleep(500);
+
+ pooler.terminatePooler();
+ }
+
+ int i = 0;
+ KisTileData *item;
+ KisTileDataStoreIterator *iter =
+ KisTileDataStore::instance()->beginIteration();
+
+ while(iter->hasNext()) {
+ item = iter->next();
+
+ int expectedClones;
+
+ switch(i) {
+ case 6:
+ case 7:
+ case 10:
+ expectedClones = 1;
+ break;
+ case 9:
+ expectedClones = 2;
+ break;
+ default:
+ expectedClones = 0;
+ }
+
+ PRETTY_TILE(i, item);
+ QCOMPARE(item->m_clonesStack.size(), expectedClones);
+ i++;
+ }
+
+
+ KisTileDataStore::instance()->endIteration(iter);
+ KisTileDataStore::instance()->debugClear();
+}
+
+QTEST_KDEMAIN(KisTileDataPoolerTest, NoGUI)
+#include "kis_tile_data_pooler_test.moc"
diff --git a/krita/image/tiles3/tests/kis_tile_data_pooler_test.h b/krita/image/tiles3/tests/kis_tile_data_pooler_test.h
new file mode 100644
index 0000000..e5a3785
--- /dev/null
+++ b/krita/image/tiles3/tests/kis_tile_data_pooler_test.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2011 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KIS_TILE_DATA_POOLER_TEST_H
+#define __KIS_TILE_DATA_POOLER_TEST_H
+
+#include <QtTest/QtTest>
+
+class KisTileDataPoolerTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testCycles();
+};
+
+#endif /* __KIS_TILE_DATA_POOLER_TEST_H */
More information about the kimageshop
mailing list