[calligra/krita-testing-kazakov] krita: Switch the pool of tile data to boost::singleton_pool

Dmitry Kazakov dimula73 at gmail.com
Tue Jul 8 12:46:16 UTC 2014


Git commit 4f3f69e7fde2b72bd1384cf4cdf6019a8d3c16e1 by Dmitry Kazakov.
Committed on 08/07/2014 at 12:41.
Pushed by dkazakov into branch 'krita-testing-kazakov'.

Switch the pool of tile data to boost::singleton_pool

Using usual malloc/free causes huge memory fragmenation, in the result
Krita eats all the memory of the system until some stable fragmented
state is reached.

There seems to be a regression: the first stroke is sometimes delayed.
Needs testing.

Testcase:
Image 8k x 8k, 2 layer
Brush 1k x 1k

Paint a dozen of strokes with undo disabled. If the memory continually
grows, it means the RAM gets fragmented. This image should not take much
more than 1.5 GiB (and massif will report it)

CCMAIL:kimageshop at kde.org

A  +-    --    krita/benchmarks/data/BIG_TESTING.kpp
M  +26   -3    krita/benchmarks/kis_low_memory_benchmark.cpp
M  +2    -0    krita/benchmarks/kis_low_memory_benchmark.h
M  +18   -8    krita/image/tiles3/kis_tile_data.cc
M  +0    -14   krita/image/tiles3/kis_tile_data_interface.h
M  +2    -3    krita/image/tiles3/swap/kis_tile_data_swapper_p.h

http://commits.kde.org/calligra/4f3f69e7fde2b72bd1384cf4cdf6019a8d3c16e1

diff --git a/krita/benchmarks/data/BIG_TESTING.kpp b/krita/benchmarks/data/BIG_TESTING.kpp
new file mode 100644
index 0000000..4d76362
Binary files /dev/null and b/krita/benchmarks/data/BIG_TESTING.kpp differ
diff --git a/krita/benchmarks/kis_low_memory_benchmark.cpp b/krita/benchmarks/kis_low_memory_benchmark.cpp
index 7acd9a5..c49016f 100644
--- a/krita/benchmarks/kis_low_memory_benchmark.cpp
+++ b/krita/benchmarks/kis_low_memory_benchmark.cpp
@@ -43,6 +43,8 @@
     if(!preset->load()) { qDebug() << "Preset" << fileName << "was NOT loaded properly. Done."; return; } \
     else qDebug() << "Loaded preset:" << fileName
 
+#define HUGE_IMAGE_SIZE 8000
+
 /**
  * This benchmark runs a series of huge strokes on a canvas with a
  * particular configuration of the swapper/pooler and history
@@ -67,8 +69,13 @@ void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName,
      * Initialize image and painter
      */
     const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
-    KisImageSP image = new KisImage(0, TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, colorSpace, "stroke sample image", false);
+    KisImageSP image = new KisImage(0, HUGE_IMAGE_SIZE, HUGE_IMAGE_SIZE, colorSpace, "stroke sample image", true);
     KisLayerSP layer = new KisPaintLayer(image, "temporary for stroke sample", OPACITY_OPAQUE_U8, colorSpace);
+    KisLayerSP layerExtra = new KisPaintLayer(image, "temporary for threading", OPACITY_OPAQUE_U8, colorSpace);
+
+    image->addNode(layer, image->root());
+    image->addNode(layerExtra, image->root());
+
     KisPainter *painter = new KisPainter(layer->paintDevice());
 
     painter->setPaintColor(KoColor(Qt::black, colorSpace));
@@ -139,6 +146,7 @@ void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName,
             KisPaintInformation pi1(line.p1(), 0.0);
             KisPaintInformation pi2(line.p2(), 1.0);
             painter->paintLine(pi1, pi2, &currentDistance);
+            painter->device()->setDirty(painter->takeDirtyRegion());
 
             logStream << "L 1" << i << lineTime.elapsed()
                       << KisTileDataStore::instance()->numTilesInMemory() * 16
@@ -147,12 +155,15 @@ void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName,
 
             line.translate(0, vstep);
         }
+
+        painter->device()->setDirty(painter->takeDirtyRegion());
+
         if (createTransaction) {
             painter->endTransaction(&undoAdapter);
         }
 
-        // uncomment to emulate user waiting after the stroke
-        //QTest::qSleep(500);
+        // comment/uncomment to emulate user waiting after the stroke
+        QTest::qSleep(1000);
 
         logStream << "C 2" << i << cycleTime.elapsed()
                   << KisTileDataStore::instance()->numTilesInMemory() * 16
@@ -206,4 +217,16 @@ void KisLowMemoryBenchmark::unlimitedMemoryHistoryPool50()
                       3000, 3000, 50, 0);
 }
 
+void KisLowMemoryBenchmark::memory2000History100Pool500HugeBrush()
+{
+    QString presetFileName = "BIG_TESTING.kpp";
+    // one cycle takes about 316 MiB of memory (total 3+ GiB)
+    QRectF rect(150,150,7850,7850);
+    qreal step = 250;
+    int numCycles = 10;
+
+    benchmarkWideArea(presetFileName, rect, step, numCycles, true,
+                      2000, 600, 500, 0);
+}
+
 QTEST_KDEMAIN(KisLowMemoryBenchmark, GUI)
diff --git a/krita/benchmarks/kis_low_memory_benchmark.h b/krita/benchmarks/kis_low_memory_benchmark.h
index 9d58d22..d5d331d 100644
--- a/krita/benchmarks/kis_low_memory_benchmark.h
+++ b/krita/benchmarks/kis_low_memory_benchmark.h
@@ -29,6 +29,8 @@ private slots:
     void unlimitedMemoryHistoryNoPool();
     void unlimitedMemoryHistoryPool50();
 
+    void memory2000History100Pool500HugeBrush();
+
 private:
     void benchmarkWideArea(const QString presetFileName,
                            const QRectF &rect, qreal vstep,
diff --git a/krita/image/tiles3/kis_tile_data.cc b/krita/image/tiles3/kis_tile_data.cc
index 615cccb..b9048c3 100644
--- a/krita/image/tiles3/kis_tile_data.cc
+++ b/krita/image/tiles3/kis_tile_data.cc
@@ -20,13 +20,19 @@
 #include "kis_tile_data.h"
 #include "kis_tile_data_store.h"
 
+#include <boost/pool/singleton_pool.hpp>
+
+// BPP == bytes per pixel
+#define TILE_SIZE_4BPP (4 * __TILE_DATA_WIDTH * __TILE_DATA_HEIGHT)
+#define TILE_SIZE_8BPP (8 * __TILE_DATA_WIDTH * __TILE_DATA_HEIGHT)
+
+typedef boost::singleton_pool<KisTileData, TILE_SIZE_4BPP, boost::default_user_allocator_new_delete, boost::details::pool::default_mutex, 128> BoostPool4BPP;
+typedef boost::singleton_pool<KisTileData, TILE_SIZE_8BPP> BoostPool8BPP;
+
 
 const qint32 KisTileData::WIDTH = __TILE_DATA_WIDTH;
 const qint32 KisTileData::HEIGHT = __TILE_DATA_HEIGHT;
 
-KisTileMemoryPool4BPP KisTileData::m_pool4BPP;
-KisTileMemoryPool8BPP KisTileData::m_pool8BPP;
-
 
 KisTileData::KisTileData(qint32 pixelSize, const quint8 *defPixel, KisTileDataStore *store)
     : m_state(NORMAL),
@@ -110,26 +116,30 @@ void KisTileData::allocateMemory()
 
 quint8* KisTileData::allocateData(const qint32 pixelSize)
 {
+    quint8 *ptr = 0;
+
     switch(pixelSize) {
     case 4:
-        return (quint8*) m_pool4BPP.pop();
+        ptr = (quint8*)BoostPool4BPP::malloc();
         break;
     case 8:
-        return (quint8*) m_pool8BPP.pop();
+        ptr = (quint8*)BoostPool8BPP::malloc();
         break;
     default:
-        return (quint8*) malloc(pixelSize * WIDTH * HEIGHT);
+        ptr = (quint8*) malloc(pixelSize * WIDTH * HEIGHT);
     }
+
+    return ptr;
 }
 
 void KisTileData::freeData(quint8* ptr, const qint32 pixelSize)
 {
     switch(pixelSize) {
     case 4:
-        return m_pool4BPP.push(ptr);
+        BoostPool4BPP::free(ptr);
         break;
     case 8:
-        return m_pool8BPP.push(ptr);
+        BoostPool8BPP::free(ptr);
         break;
     default:
         free(ptr);
diff --git a/krita/image/tiles3/kis_tile_data_interface.h b/krita/image/tiles3/kis_tile_data_interface.h
index 7c20763..733b100 100644
--- a/krita/image/tiles3/kis_tile_data_interface.h
+++ b/krita/image/tiles3/kis_tile_data_interface.h
@@ -35,19 +35,8 @@ class KisTileDataStore;
 #define __TILE_DATA_WIDTH 64
 #define __TILE_DATA_HEIGHT 64
 
-#define TILE_DATA_POOL_SIZE 32
-
-
-// BPP == bytes per pixel
-#define TILE_SIZE_4BPP (4 * __TILE_DATA_WIDTH * __TILE_DATA_HEIGHT)
-#define TILE_SIZE_8BPP (8 * __TILE_DATA_WIDTH * __TILE_DATA_HEIGHT)
-
-
-typedef KisMemoryPool<quint8[TILE_SIZE_4BPP],TILE_DATA_POOL_SIZE> KisTileMemoryPool4BPP;
-typedef KisMemoryPool<quint8[TILE_SIZE_8BPP],TILE_DATA_POOL_SIZE> KisTileMemoryPool8BPP;
 typedef KisLocklessStack<KisTileData*> KisTileDataCache;
 
-
 typedef QLinkedList<KisTileData*> KisTileDataList;
 typedef KisTileDataList::iterator KisTileDataListIterator;
 typedef KisTileDataList::const_iterator KisTileDataListConstIterator;
@@ -259,9 +248,6 @@ private:
     //qint32 m_timeStamp;
 
     KisTileDataStore *m_store;
-
-    static KisTileMemoryPool4BPP m_pool4BPP;
-    static KisTileMemoryPool8BPP m_pool8BPP;
 public:
     static const qint32 WIDTH;
     static const qint32 HEIGHT;
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 81833eb..e2f6df7 100644
--- a/krita/image/tiles3/swap/kis_tile_data_swapper_p.h
+++ b/krita/image/tiles3/swap/kis_tile_data_swapper_p.h
@@ -63,13 +63,12 @@ public:
         KisImageConfig config;
 
         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;
-        m_softLimit = m_softLimitThreshold - m_softLimitThreshold / 8;
-
 
+        m_softLimitThreshold = qBound(0, MiB_TO_METRIC(config.tilesSoftLimit()), m_hardLimitThreshold);
+        m_softLimit = m_softLimitThreshold - m_softLimitThreshold / 8;
     }
 
     /**


More information about the kimageshop mailing list