From 80d938c6a31be9f45f0ceaa289a5f8c04c8f33dc Mon Sep 17 00:00:00 2001
From: Ulf Hermann <ulf.hermann@digia.com>
Date: Fri, 11 Jul 2014 11:01:47 +0200
Subject: [PATCH] Be more verbose about aggregated memory allocations

The memory profiler aggregates allocations originating from the same
QML/JS constructs into one event. This change makes sure the origins
are really the same calls, not only the same functions and gives some
more details on hom much memory was allocated or deallocated in how
many steps.

Change-Id: I784c521855122f7b3b894417de0afb216766e2d4
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
---
 .../qmlprofilerextension/memoryusagemodel.cpp | 73 ++++++++++++-------
 .../qmlprofilerextension/memoryusagemodel.h   |  9 ++-
 2 files changed, 56 insertions(+), 26 deletions(-)

diff --git a/plugins/qmlprofilerextension/memoryusagemodel.cpp b/plugins/qmlprofilerextension/memoryusagemodel.cpp
index 6c3282aa9f7..5085b0bfbe2 100644
--- a/plugins/qmlprofilerextension/memoryusagemodel.cpp
+++ b/plugins/qmlprofilerextension/memoryusagemodel.cpp
@@ -145,7 +145,7 @@ const QVariantList MemoryUsageModel::getEventDetails(int index) const
     const MemoryUsageModelPrivate::Range *ev = &d->range(index);
 
     QVariantMap res;
-    if (ev->delta > 0)
+    if (ev->allocated >= -ev->deallocated)
         res.insert(title, tr("Memory Allocated"));
     else
         res.insert(title, tr("Memory Freed"));
@@ -156,7 +156,14 @@ const QVariantList MemoryUsageModel::getEventDetails(int index) const
     result << res;
     res.clear();
 
-    res.insert(tr("Allocation"), QVariant(QString::fromLatin1("%1 bytes").arg(ev->delta)));
+    if (ev->allocations > 0) {
+        res.insert(tr("Allocated"), QString::fromLatin1("%1 bytes").arg(ev->allocated));
+        res.insert(tr("Allocations"), QString::number(ev->allocations));
+    }
+    if (ev->deallocations > 0) {
+        res.insert(tr("Deallocated"), QString::fromLatin1("%1 bytes").arg(-ev->deallocated));
+        res.insert(tr("Deallocations"), QString::number(ev->deallocations));
+    }
     res.insert(tr("Type"), QVariant(MemoryUsageModelPrivate::memoryTypeName(ev->type)));
     if (ev->originTypeIndex != -1) {
         res.insert(tr("Location"),
@@ -189,9 +196,7 @@ void MemoryUsageModel::loadData()
     int currentJSHeapIndex = -1;
 
     QStack<RangeStackFrame> rangeStack;
-    MemoryAllocation dummy = {
-        QmlDebug::MaximumMemoryType, -1, -1 , -1
-    };
+    MemoryAllocation dummy;
 
     const QVector<QmlProfilerDataModel::QmlEventTypeData> &types = simpleModel->getEventTypes();
     foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) {
@@ -207,18 +212,18 @@ void MemoryUsageModel::loadData()
         }
 
         if (type.detailType == QmlDebug::SmallItem || type.detailType == QmlDebug::LargeItem) {
-            currentUsage += event.numericData1;
             MemoryAllocation &last = currentUsageIndex > -1 ? d->data(currentUsageIndex) : dummy;
-            if (!rangeStack.empty() && last.originTypeIndex == rangeStack.top().originTypeIndex) {
-                last.size = currentUsage;
-                last.delta += event.numericData1;
+            if (!rangeStack.empty() && type.detailType == last.type &&
+                    last.originTypeIndex == rangeStack.top().originTypeIndex &&
+                    rangeStack.top().startTime < d->range(currentUsageIndex).start) {
+                last.update(event.numericData1);
+                currentUsage = last.size;
             } else {
-                MemoryAllocation allocation = {
-                    QmlDebug::SmallItem,
-                    currentUsage,
-                    event.numericData1,
-                    rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex
-                };
+                MemoryAllocation allocation(QmlDebug::SmallItem, currentUsage,
+                        rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex);
+                allocation.update(event.numericData1);
+                currentUsage = allocation.size;
+
                 if (currentUsageIndex != -1) {
                     d->insertEnd(currentUsageIndex,
                                  event.startTime - d->range(currentUsageIndex).start - 1);
@@ -228,18 +233,17 @@ void MemoryUsageModel::loadData()
         }
 
         if (type.detailType == QmlDebug::HeapPage || type.detailType == QmlDebug::LargeItem) {
-            currentSize += event.numericData1;
             MemoryAllocation &last = currentJSHeapIndex > -1 ? d->data(currentJSHeapIndex) : dummy;
-            if (!rangeStack.empty() && last.originTypeIndex == rangeStack.top().originTypeIndex) {
-                last.size = currentSize;
-                last.delta += event.numericData1;
+            if (!rangeStack.empty() && type.detailType == last.type &&
+                    last.originTypeIndex == rangeStack.top().originTypeIndex &&
+                    rangeStack.top().startTime < d->range(currentJSHeapIndex).start) {
+                last.update(event.numericData1);
+                currentSize = last.size;
             } else {
-                MemoryAllocation allocation = {
-                    (QmlDebug::MemoryType)type.detailType,
-                    currentSize,
-                    event.numericData1,
-                    rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex
-                };
+                MemoryAllocation allocation((QmlDebug::MemoryType)type.detailType, currentSize,
+                        rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex);
+                allocation.update(event.numericData1);
+                currentSize = allocation.size;
 
                 if (currentSize > d->maxSize)
                     d->maxSize = currentSize;
@@ -286,6 +290,25 @@ QString MemoryUsageModel::MemoryUsageModelPrivate::memoryTypeName(int type)
     }
 }
 
+MemoryUsageModel::MemoryAllocation::MemoryAllocation(QmlDebug::MemoryType type, qint64 baseAmount,
+                                                     int originTypeIndex) :
+    type(type), size(baseAmount), allocated(0), deallocated(0), allocations(0), deallocations(0),
+    originTypeIndex(originTypeIndex)
+{
+}
+
+void MemoryUsageModel::MemoryAllocation::update(qint64 amount)
+{
+    size += amount;
+    if (amount < 0) {
+        deallocated += amount;
+        ++deallocations;
+    } else {
+        allocated += amount;
+        ++allocations;
+    }
+}
+
 
 } // namespace Internal
 } // namespace QmlProfilerExtension
diff --git a/plugins/qmlprofilerextension/memoryusagemodel.h b/plugins/qmlprofilerextension/memoryusagemodel.h
index 7559c9c7493..e3453812504 100644
--- a/plugins/qmlprofilerextension/memoryusagemodel.h
+++ b/plugins/qmlprofilerextension/memoryusagemodel.h
@@ -37,8 +37,15 @@ public:
     struct MemoryAllocation {
         QmlDebug::MemoryType type;
         qint64 size;
-        qint64 delta;
+        qint64 allocated;
+        qint64 deallocated;
+        int allocations;
+        int deallocations;
         int originTypeIndex;
+
+        MemoryAllocation(QmlDebug::MemoryType type = QmlDebug::MaximumMemoryType,
+                         qint64 baseAmount = 0, int originTypeIndex = -1);
+        void update(qint64 amount);
     };
 
     MemoryUsageModel(QObject *parent = 0);
-- 
GitLab