Optimize: Reduce memory consumption of RowData for TreeModel by ~20%.
authorMilian Wolff <mail@milianw.de>
Sun, 6 Dec 2015 16:46:18 +0000 (17:46 +0100)
committerMilian Wolff <mail@milianw.de>
Sun, 6 Dec 2015 16:46:18 +0000 (17:46 +0100)
By interning the common LocationData we can save quite some memory
for large data sets. Still, the large tree is still easily hogging
up gigabytes of memory...

gui/flamegraph.cpp
gui/parser.cpp
gui/treemodel.cpp
gui/treemodel.h

index f45f7c5..d47a789 100644 (file)
@@ -199,9 +199,9 @@ FrameGraphicsItem* findItemByFunction(const QList<QGraphicsItem*>& items, const
 void toGraphicsItems(const QVector<RowData>& data, FrameGraphicsItem *parent)
 {
     foreach (const auto& row, data) {
-        auto item = findItemByFunction(parent->childItems(), row.location.function);
+        auto item = findItemByFunction(parent->childItems(), row.location->function);
         if (!item) {
-            item = new FrameGraphicsItem(row.allocations, row.location.function, parent);
+            item = new FrameGraphicsItem(row.allocations, row.location->function, parent);
             item->setPen(parent->pen());
             item->setBrush(brush());
         } else {
index bfbc2d3..88b5b71 100644 (file)
@@ -29,7 +29,6 @@
 #include "../accumulatedtracedata.h"
 
 #include <vector>
-#include <memory>
 
 using namespace std;
 
@@ -80,9 +79,17 @@ struct StringCache
         }
     }
 
-    LocationData location(const InstructionPointer& ip) const
+    shared_ptr<LocationData> location(const InstructionPointer& ip) const
     {
-        return {func(ip), file(ip), module(ip), ip.line};
+        LocationData data = {func(ip), file(ip), module(ip), ip.line};
+        auto it = lower_bound(m_locations.begin(), m_locations.end(), data);
+        if (it != m_locations.end() && **it == data) {
+            return *it;
+        } else {
+            auto interned = make_shared<LocationData>(data);
+            m_locations.insert(it, interned);
+            return interned;
+        }
     }
 
     void update(const vector<string>& strings)
@@ -93,6 +100,7 @@ struct StringCache
 
     vector<QString> m_strings;
     mutable QHash<uint64_t, QString> m_ipAddresses;
+    mutable vector<shared_ptr<LocationData>> m_locations;
 };
 
 struct ChartMergeData
@@ -294,7 +302,6 @@ QVector<RowData> mergeAllocations(const ParserData& data)
         while (traceIndex) {
             const auto& trace = data.findTrace(traceIndex);
             const auto& ip = data.findIp(trace.ipIndex);
-            // TODO: only store the IpIndex and use that
             auto location = data.stringCache.location(ip);
             auto it = lower_bound(rows->begin(), rows->end(), location);
             if (it != rows->end() && it->location == location) {
index 527695b..b397784 100644 (file)
@@ -129,21 +129,21 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const
         case LeakedColumn:
             return row->leaked;
         case FunctionColumn:
-            return row->location.function;
+            return row->location->function;
         case ModuleColumn:
-            return row->location.module;
+            return row->location->module;
         case FileColumn:
-            return row->location.file;
+            return row->location->file;
         case LineColumn:
-            return row->location.line;
+            return row->location->line;
         case LocationColumn:
-            if (row->location.file.isEmpty()) {
-                return i18n("%1 in ?? (%2)", row->location.function,
-                            row->location.module);
+            if (row->location->file.isEmpty()) {
+                return i18n("%1 in ?? (%2)", row->location->function,
+                            row->location->module);
             } else {
-                return i18n("%1 in %2:%3 (%4)", row->location.function,
-                            row->location.file, row->location.line,
-                            row->location.module);
+                return i18n("%1 in %2:%3 (%4)", row->location->function,
+                            row->location->file, row->location->line,
+                            row->location->module);
             }
         case NUM_COLUMNS:
             break;
@@ -153,7 +153,7 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const
         QTextStream stream(&tooltip);
         stream << "<qt><pre>";
         stream << i18nc("1: function, 2: file, 3: line, 4: module", "%1\n  at %2:%3\n  in %4",
-                        row->location.function, row->location.file, row->location.line, row->location.module);
+                        row->location->function, row->location->file, row->location->line, row->location->module);
         stream << '\n';
         KFormat format;
         stream << i18n("allocated %1 over %2 calls, peak at %3, leaked %4",
@@ -167,7 +167,7 @@ QVariant TreeModel::data(const QModelIndex& index, int role) const
             while (child->children.count() == 1 && max-- > 0) {
                 stream << "\n";
                 stream << i18nc("1: function, 2: file, 3: line, 4: module", "%1\n  at %2:%3\n  in %4",
-                                child->location.function, child->location.file, child->location.line, child->location.module);
+                                child->location->function, child->location->file, child->location->line, child->location->module);
                 child = child->children.data();
             }
             if (child->children.count() > 1) {
index e0695cc..00de25f 100644 (file)
 #include <QAbstractItemModel>
 #include <QVector>
 
+#include <boost/functional/hash.hpp>
+
+#include <memory>
+
 struct LocationData
 {
     QString function;
     QString file;
     QString module;
     int line;
+
     bool operator==(const LocationData& rhs) const
     {
         return function == rhs.function
@@ -36,6 +41,7 @@ struct LocationData
             && module == rhs.module
             && line == rhs.line;
     }
+
     bool operator<(const LocationData& rhs) const
     {
         int i = function.compare(rhs.function);
@@ -53,18 +59,23 @@ struct LocationData
 };
 Q_DECLARE_TYPEINFO(LocationData, Q_MOVABLE_TYPE);
 
+inline bool operator<(const std::shared_ptr<LocationData>& lhs, const LocationData& rhs)
+{
+    return *lhs < rhs;
+}
+
 struct RowData
 {
     quint64 allocations;
     quint64 peak;
     quint64 leaked;
     quint64 allocated;
-    LocationData location;
+    std::shared_ptr<LocationData> location;
     const RowData* parent;
     QVector<RowData> children;
-    bool operator<(const LocationData& rhs) const
+    bool operator<(const std::shared_ptr<LocationData>& rhs) const
     {
-        return location < rhs;
+        return *location < *rhs;
     }
 };
 Q_DECLARE_TYPEINFO(RowData, Q_MOVABLE_TYPE);