[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [calligra/krita-testing-kazakov] krita: Release the memory occupied by pools when the last document 
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2014-07-10 11:14:11
Message-ID: E1X5CIl-0005ff-Cj () scm ! kde ! org
[Download RAW message or body]

Git commit e91bcc89fdcf64108318f07a1a30282d4955f6c3 by Dmitry Kazakov.
Committed on 10/07/2014 at 11:11.
Pushed by dkazakov into branch 'krita-testing-kazakov'.

Release the memory occupied by pools when the last document has been closed

We cannot use boost::pool::release_memory, because we use unordered pool.
Even if we used one, freeing 1.5 GiB of small chunks would take ages
(more than 20s), so it would be of no need to users.

That is why we just check that there are no tiles left in the store and
purge the entire slab of memory we occupied for the pool.

M  +10   -0    krita/image/kis_datamanager.h
M  +10   -0    krita/image/kis_paint_device.cc
M  +8    -0    krita/image/kis_paint_device.h
M  +30   -0    krita/image/tiles3/kis_tile_data.cc
M  +10   -0    krita/image/tiles3/kis_tile_data_interface.h
M  +4    -0    krita/image/tiles3/kis_tiled_data_manager.cc
M  +2    -0    krita/image/tiles3/kis_tiled_data_manager.h
M  +6    -1    krita/ui/kis_view2.cpp

http://commits.kde.org/calligra/e91bcc89fdcf64108318f07a1a30282d4955f6c3

diff --git a/krita/image/kis_datamanager.h b/krita/image/kis_datamanager.h
index c80b539..28db864 100644
--- a/krita/image/kis_datamanager.h
+++ b/krita/image/kis_datamanager.h
@@ -133,6 +133,16 @@ public:
         ACTUAL_DATAMGR::purge(area);
     }
 
+    /**
+     * The tiles may be not allocated directly from the glibc, but
+     * instead can be allocated in bigger blobs. After you freed quite
+     * a lot of data and are sure you won't need it anymore, you can
+     * release these pools to save the memory.
+     */
+    static inline void releaseInternalPools() {
+        ACTUAL_DATAMGR::releaseInternalPools();
+    }
+
 public:
 
     /**
diff --git a/krita/image/kis_paint_device.cc b/krita/image/kis_paint_device.cc
index 125e268..dbb4be2 100644
--- a/krita/image/kis_paint_device.cc
+++ b/krita/image/kis_paint_device.cc
@@ -1068,4 +1068,14 @@ QVector<qint32> KisPaintDevice::channelSizes() const
     return sizes;
 }
 
+KisPaintDevice::MemoryReleaseObject::~MemoryReleaseObject()
+{
+    KisDataManager::releaseInternalPools();
+}
+
+KisPaintDevice::MemoryReleaseObject* KisPaintDevice::createMemoryReleaseObject()
+{
+    return new MemoryReleaseObject();
+}
+
 #include "kis_paint_device.moc"
diff --git a/krita/image/kis_paint_device.h b/krita/image/kis_paint_device.h
index deefdfc..f6a6c8d 100644
--- a/krita/image/kis_paint_device.h
+++ b/krita/image/kis_paint_device.h
@@ -715,6 +715,14 @@ public:
      */
     QRect calculateExactBounds() const;
 
+public:
+    struct MemoryReleaseObject : public QObject
+    {
+        ~MemoryReleaseObject();
+    };
+
+    static MemoryReleaseObject* createMemoryReleaseObject();
+
 private:
     KisPaintDevice& operator=(const KisPaintDevice&);
     void init(KisDataManagerSP explicitDataManager,
diff --git a/krita/image/tiles3/kis_tile_data.cc b/krita/image/tiles3/kis_tile_data.cc
index 84bb68c..0ab7007 100644
--- a/krita/image/tiles3/kis_tile_data.cc
+++ b/krita/image/tiles3/kis_tile_data.cc
@@ -20,6 +20,8 @@
 #include "kis_tile_data.h"
 #include "kis_tile_data_store.h"
 
+#include <QDebug>
+
 #include <boost/pool/singleton_pool.hpp>
 
 // BPP == bytes per pixel
@@ -145,4 +147,32 @@ void KisTileData::freeData(quint8* ptr, const qint32 pixelSize)
     }
 }
 
+//#define DEBUG_POOL_RELEASE
+
+#ifdef DEBUG_POOL_RELEASE
+#include <unistd.h>
+#endif /* DEBUG_POOL_RELEASE */
+
+void KisTileData::releaseInternalPools()
+{
+    if (!KisTileDataStore::instance()->numTiles() &&
+        !KisTileDataStore::instance()->numTilesInMemory()) {
+
+        BoostPool4BPP::purge_memory();
+        BoostPool8BPP::purge_memory();
 
+#ifdef DEBUG_POOL_RELEASE
+        qDebug() << "After purging unused memory:";
+
+        char command[256];
+        sprintf(command, "cat /proc/%d/status | grep -i vm", (int)getpid());
+        printf("--- %s ---\n", command);
+        (void)system(command);
+#endif /* DEBUG_POOL_RELEASE */
+
+    } else {
+        qWarning() << "WARNING: trying to purge pool memory while there are used tiles present!";
+        qWarning() << "         The memory will *NOT* be returned to the system, though it will";
+        qWarning() << "         be reused by Krita internally. Please report to developers!";
+    }
+}
diff --git a/krita/image/tiles3/kis_tile_data_interface.h b/krita/image/tiles3/kis_tile_data_interface.h
index 733b100..fc2aad4 100644
--- a/krita/image/tiles3/kis_tile_data_interface.h
+++ b/krita/image/tiles3/kis_tile_data_interface.h
@@ -151,6 +151,16 @@ public:
      */
     void allocateMemory();
 
+    /**
+     * Releases internal pools, which keep blobs where the tiles are
+     * stored.  The point is that we don't allocate the tiles from
+     * glibc directly, but use pools (implemented via boost) to
+     * allocate bigger chunks. This method should be called when one
+     * knows that we have just free'd quite a lot of memory and we
+     * won't need it anymore. E.g. when a document has been closed.
+     */
+    static void releaseInternalPools();
+
 private:
     void fillWithPixel(const quint8 *defPixel);
 
diff --git a/krita/image/tiles3/kis_tiled_data_manager.cc b/krita/image/tiles3/kis_tiled_data_manager.cc
index 7b16738..51f10ed 100644
--- a/krita/image/tiles3/kis_tiled_data_manager.cc
+++ b/krita/image/tiles3/kis_tiled_data_manager.cc
@@ -785,3 +785,7 @@ qint32 KisTiledDataManager::rowStride(qint32 x, qint32 y) const
     return KisTileData::WIDTH * pixelSize();
 }
 
+void KisTiledDataManager::releaseInternalPools()
+{
+    KisTileData::releaseInternalPools();
+}
diff --git a/krita/image/tiles3/kis_tiled_data_manager.h b/krita/image/tiles3/kis_tiled_data_manager.h
index 88be8d3..fba08ec 100644
--- a/krita/image/tiles3/kis_tiled_data_manager.h
+++ b/krita/image/tiles3/kis_tiled_data_manager.h
@@ -166,6 +166,8 @@ public:
         m_mementoManager->purgeHistory(oldestMemento);
     }
 
+    static void releaseInternalPools();
+
 protected:
     /**
      * Reads and writes the tiles 
diff --git a/krita/ui/kis_view2.cpp b/krita/ui/kis_view2.cpp
index fbbdc65..c280d40 100644
--- a/krita/ui/kis_view2.cpp
+++ b/krita/ui/kis_view2.cpp
@@ -199,10 +199,15 @@ public:
         delete actionManager;
         delete canvasControlsManager;
         delete tooltipManager;
+
+        /**
+         * Push a timebomb, which will try to release the memory after
+         * the document has been deleted
+         */
+        KisPaintDevice::createMemoryReleaseObject()->deleteLater();
     }
 
 public:
-
     KisCanvas2 *canvas;
     KisDoc2 *doc;
     KisCoordinatesConverter *viewConverter;

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic