Add size histogram to heaptrack_gui.
authorMilian Wolff <mail@milianw.de>
Tue, 15 Dec 2015 16:46:04 +0000 (17:46 +0100)
committerMilian Wolff <mail@milianw.de>
Tue, 15 Dec 2015 16:46:04 +0000 (17:46 +0100)
This tracks the number of times allocations of a certain size are
requested and displays the data in a histogram. Note that the sizes
are binned in the following byte ranges:

0-8
9-16
17-32
33-64
65-128
129-256
257-512
513-1024
>1024

13 files changed:
accumulatedtracedata.cpp
accumulatedtracedata.h
gui/CMakeLists.txt
gui/chartwidget.cpp
gui/histogrammodel.cpp [new file with mode: 0644]
gui/histogrammodel.h [new file with mode: 0644]
gui/histogramwidget.cpp [new file with mode: 0644]
gui/histogramwidget.h [new file with mode: 0644]
gui/mainwindow.cpp
gui/mainwindow.ui
gui/parser.cpp
gui/parser.h
heaptrack_print.cpp

index 8829c23..e7ac38d 100644 (file)
@@ -157,7 +157,6 @@ bool AccumulatedTraceData::read(istream& in)
     peak = 0;
     leaked = 0;
     allocations.clear();
-    sizeHistogram.clear();
     uint64_t lastAllocationPtr = 0;
     uint fileVersion = 0;
 
@@ -211,14 +210,15 @@ bool AccumulatedTraceData::read(istream& in)
             }
         } else if (reader.mode() == '+') {
             BigAllocationInfo info;
+            AllocationIndex allocationIndex;
             if (fileVersion >= 0x010000) {
-                uint32_t allocationInfoIndex = 0;
-                if (!(reader >> allocationInfoIndex)) {
+                if (!(reader >> allocationIndex.index)) {
                     cerr << "failed to parse line: " << reader.line() << endl;
                     continue;
                 }
-                info = allocationInfos[allocationInfoIndex];
+                info = allocationInfos[allocationIndex.index];
             } else {
+                // TODO: allocationInfoIndex
                 uint64_t ptr = 0;
                 if (!(reader >> info.size) || !(reader >> info.traceIndex) || !(reader >> ptr)) {
                     cerr << "failed to parse line: " << reader.line() << endl;
@@ -250,11 +250,7 @@ bool AccumulatedTraceData::read(istream& in)
                 peak = leaked;
             }
 
-            if (printHistogram) {
-                ++sizeHistogram[info.size];
-            }
-
-            handleAllocation();
+            handleAllocation(info, allocationIndex);
         } else if (reader.mode() == '-') {
             BigAllocationInfo info;
             bool temporary = false;
index 6192f4c..1b34be0 100644 (file)
@@ -125,7 +125,7 @@ struct AccumulatedTraceData
     virtual ~AccumulatedTraceData() = default;
 
     virtual void handleTimeStamp(uint64_t oldStamp, uint64_t newStamp) = 0;
-    virtual void handleAllocation() = 0;
+    virtual void handleAllocation(const BigAllocationInfo& info, const AllocationIndex index) = 0;
     virtual void handleDebuggee(const char* command) = 0;
 
     const std::string& stringify(const StringIndex stringId) const;
@@ -136,11 +136,9 @@ struct AccumulatedTraceData
     bool read(std::istream& in);
 
     bool shortenTemplates = false;
-    bool printHistogram = false;
     bool fromAttached = false;
 
     std::vector<Allocation> allocations;
-    std::map<uint64_t, uint64_t> sizeHistogram;
     uint64_t totalAllocated = 0;
     uint64_t totalAllocations = 0;
     uint64_t totalTemporary = 0;
index 2887bd7..81cd8b3 100644 (file)
@@ -19,6 +19,8 @@ add_executable(heaptrack_gui
     chartwidget.cpp
     chartmodel.cpp
     chartproxy.cpp
+    histogramwidget.cpp
+    histogrammodel.cpp
     modeltest.cpp
     parser.cpp
     flamegraph.cpp
index 46f5ace..ad95f9b 100644 (file)
@@ -67,7 +67,6 @@ public:
 
     const QString customizedLabel(const QString& label) const override
     {
-        // TODO: change distance between labels to 1024 and simply use prettyCost() here
         KFormat format(QLocale::system());
         return format.formatByteSize(label.toDouble(), 1, KFormat::MetricBinaryDialect);
     }
diff --git a/gui/histogrammodel.cpp b/gui/histogrammodel.cpp
new file mode 100644 (file)
index 0000000..15b5eed
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 "histogrammodel.h"
+
+#include <KChartGlobal>
+
+#include <KFormat>
+#include <KLocalizedString>
+
+#include <QColor>
+#include <QBrush>
+#include <QPen>
+
+#include <limits>
+
+namespace {
+QColor colorForColumn(int column, int columnCount)
+{
+    return QColor::fromHsv((double(column) / columnCount) * 255, 255, 255);
+}
+}
+
+HistogramModel::HistogramModel(QObject* parent)
+    : QAbstractTableModel(parent)
+{
+    qRegisterMetaType<HistogramData>("HistogramData");
+}
+
+HistogramModel::~HistogramModel() = default;
+
+QVariant HistogramModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+    if (orientation == Qt::Vertical && role == Qt::DisplayRole && section >= 0 && section < m_data.size()) {
+        return m_data.at(section).sizeLabel;
+    }
+    return {};
+}
+
+QVariant HistogramModel::data(const QModelIndex& index, int role) const
+{
+    if (!hasIndex(index.row(), index.column(), index.parent())) {
+        return {};
+    }
+    if ( role == KChart::DatasetBrushRole ) {
+        return QVariant::fromValue(QBrush(colorForColumn(index.column(), columnCount())));
+    } else if ( role == KChart::DatasetPenRole ) {
+        return QVariant::fromValue(QPen(Qt::black));
+    }
+
+    if (role != Qt::DisplayRole && role != Qt::ToolTipRole) {
+        return {};
+    }
+
+    const auto& row = m_data.at(index.row());
+    const auto& column = row.columns[index.column()];
+    if (role == Qt::ToolTipRole) {
+        if (index.column() == 0) {
+            return i18n("%1 allocations in total", column.allocations);
+        }
+        if (!column.location->file.isEmpty()) {
+            return i18n("%1 allocations from %2 at %3:%4 in %5", column.allocations,
+                        column.location->function, column.location->file, column.location->line,
+                        column.location->module);
+        }
+        return i18n("%1 allocations from %2 in %3", column.allocations,
+                    column.location->function, column.location->module);
+    }
+    return column.allocations;
+}
+
+int HistogramModel::columnCount(const QModelIndex& parent) const
+{
+    if (parent.isValid()) {
+        return 0;
+    }
+    return HistogramRow::NUM_COLUMNS;
+}
+
+int HistogramModel::rowCount(const QModelIndex& parent) const
+{
+    if (parent.isValid()) {
+        return 0;
+    }
+    return m_data.size();
+}
+
+void HistogramModel::resetData(const HistogramData& data)
+{
+    beginResetModel();
+    m_data = data;
+    endResetModel();
+}
diff --git a/gui/histogrammodel.h b/gui/histogrammodel.h
new file mode 100644 (file)
index 0000000..2ebc64b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 HISTOGRAMMODEL_H
+#define HISTOGRAMMODEL_H
+
+#include <QAbstractTableModel>
+
+#include "treemodel.h"
+
+struct HistogramColumn
+{
+    quint64 allocations;
+    std::shared_ptr<LocationData> location;
+};
+Q_DECLARE_TYPEINFO(HistogramColumn, Q_MOVABLE_TYPE);
+
+struct HistogramRow
+{
+    HistogramRow()
+    {
+        columns.fill({0, {}});
+    }
+    enum {
+        NUM_COLUMNS = 10 + 1
+    };
+    QString sizeLabel;
+    quint64 size = 0;
+    std::array<HistogramColumn, NUM_COLUMNS> columns;
+};
+Q_DECLARE_TYPEINFO(HistogramRow, Q_MOVABLE_TYPE);
+Q_DECLARE_METATYPE(HistogramRow);
+
+using HistogramData = QVector<HistogramRow>;
+
+class HistogramModel : public QAbstractTableModel
+{
+    Q_OBJECT
+public:
+    explicit HistogramModel(QObject* parent = nullptr);
+    ~HistogramModel() override;
+
+    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+    int rowCount(const QModelIndex& parent = {}) const override;
+    int columnCount(const QModelIndex& parent = {}) const override;
+
+    void resetData(const HistogramData& data);
+
+private:
+    HistogramData m_data;
+};
+
+#endif // HISTOGRAMMODEL_H
diff --git a/gui/histogramwidget.cpp b/gui/histogramwidget.cpp
new file mode 100644 (file)
index 0000000..64cfc8f
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 "histogramwidget.h"
+
+#include <QVBoxLayout>
+#include <QSortFilterProxyModel>
+
+#include <KChartChart>
+#include <KChartBarDiagram>
+
+#include <KChartGridAttributes>
+#include <KChartHeaderFooter>
+#include <KChartCartesianCoordinatePlane>
+#include <KChartLegend>
+#include <KChartDataValueAttributes>
+#include <KChartBackgroundAttributes>
+#include <KChartFrameAttributes.h>
+
+#include <KLocalizedString>
+#include <KColorScheme>
+#include <KFormat>
+
+#include "histogrammodel.h"
+
+using namespace KChart;
+
+namespace {
+class SizeAxis : public CartesianAxis
+{
+    Q_OBJECT
+public:
+    explicit SizeAxis(AbstractCartesianDiagram* diagram = nullptr)
+        : CartesianAxis(diagram)
+    {}
+
+    const QString customizedLabel(const QString& label) const override
+    {
+        KFormat format(QLocale::system());
+        return format.formatByteSize(label.toDouble(), 1, KFormat::MetricBinaryDialect);
+    }
+};
+
+class HistogramProxy : public QSortFilterProxyModel
+{
+    Q_OBJECT
+public:
+    explicit HistogramProxy(bool showTotal, QObject* parent = nullptr)
+        : QSortFilterProxyModel(parent)
+        , m_showTotal(showTotal)
+    {
+    }
+    virtual ~HistogramProxy() = default;
+
+protected:
+    bool filterAcceptsColumn(int sourceColumn, const QModelIndex& /*sourceParent*/) const override
+    {
+        if (m_showTotal) {
+            return sourceColumn == 0;
+        } else {
+            return sourceColumn != 0;
+        }
+    }
+
+private:
+    bool m_showTotal;
+};
+
+}
+
+HistogramWidget::HistogramWidget(QWidget* parent)
+    : QWidget(parent)
+    , m_chart(new KChart::Chart(this))
+    , m_total(new BarDiagram(this))
+    , m_detailed(new BarDiagram(this))
+{
+    auto layout = new QVBoxLayout(this);
+    layout->addWidget(m_chart);
+    setLayout(layout);
+
+    auto* coordinatePlane = dynamic_cast<CartesianCoordinatePlane*>(m_chart->coordinatePlane());
+    Q_ASSERT(coordinatePlane);
+
+    {
+        m_total->setAntiAliasing(true);
+
+        KColorScheme scheme(QPalette::Active, KColorScheme::Window);
+        QPen foreground(scheme.foreground().color());
+        auto bottomAxis = new CartesianAxis(m_total);
+        auto axisTextAttributes = bottomAxis->textAttributes();
+        axisTextAttributes.setPen(foreground);
+        bottomAxis->setTextAttributes(axisTextAttributes);
+        auto axisTitleTextAttributes = bottomAxis->titleTextAttributes();
+        axisTitleTextAttributes.setPen(foreground);
+        bottomAxis->setTitleTextAttributes(axisTitleTextAttributes);
+        bottomAxis->setPosition(KChart::CartesianAxis::Bottom);
+        bottomAxis->setTitleText(i18n("Requested Allocation Size"));
+        m_total->addAxis(bottomAxis);
+
+        auto* rightAxis = new CartesianAxis(m_total);
+        rightAxis->setTextAttributes(axisTextAttributes);
+        rightAxis->setTitleTextAttributes(axisTitleTextAttributes);
+        rightAxis->setTitleText(i18n("Number of Allocations"));
+        rightAxis->setPosition(CartesianAxis::Right);
+        m_total->addAxis(rightAxis);
+
+        coordinatePlane->addDiagram(m_total);
+
+        m_total->setType(BarDiagram::Normal);
+    }
+
+    {
+        m_detailed->setAntiAliasing(true);
+
+        coordinatePlane->addDiagram(m_detailed);
+
+        m_detailed->setType(BarDiagram::Stacked);
+    }
+}
+
+HistogramWidget::~HistogramWidget() = default;
+
+void HistogramWidget::setModel(QAbstractItemModel* model)
+{
+    {
+        auto proxy = new HistogramProxy(true, this);
+        proxy->setSourceModel(model);
+        m_total->setModel(proxy);
+    }
+    {
+        auto proxy = new HistogramProxy(false, this);
+        proxy->setSourceModel(model);
+        m_detailed->setModel(proxy);
+    }
+}
+
+#include "histogramwidget.moc"
diff --git a/gui/histogramwidget.h b/gui/histogramwidget.h
new file mode 100644 (file)
index 0000000..28571bf
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library 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 HISTOGRAMWIDGET_H
+#define HISTOGRAMWIDGET_H
+
+#include <QWidget>
+
+namespace KChart {
+class Chart;
+class BarDiagram;
+}
+
+class QAbstractItemModel;
+
+class HistogramWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit HistogramWidget(QWidget* parent = nullptr);
+    virtual ~HistogramWidget();
+
+    void setModel(QAbstractItemModel* model);
+
+private:
+    KChart::Chart* m_chart;
+    KChart::BarDiagram* m_total;
+    KChart::BarDiagram* m_detailed;
+};
+
+#endif // HISTOGRAMWIDGET_H
+
index 3b8b2ef..a33625f 100644 (file)
@@ -32,6 +32,7 @@
 #include "parser.h"
 #include "chartmodel.h"
 #include "chartproxy.h"
+#include "histogrammodel.h"
 
 using namespace std;
 
@@ -57,6 +58,8 @@ MainWindow::MainWindow(QWidget* parent)
     m_ui->allocatedTab->setModel(allocatedModel);
     auto temporaryModel = new ChartModel(ChartModel::Temporary, this);
     m_ui->temporaryTab->setModel(temporaryModel);
+    auto sizeHistogramModel = new HistogramModel(this);
+    m_ui->sizesTab->setModel(sizeHistogramModel);
 
     connect(m_parser, &Parser::bottomUpDataAvailable,
             m_bottomUpModel, &TreeModel::resetData);
@@ -70,6 +73,8 @@ MainWindow::MainWindow(QWidget* parent)
             allocationsModel, &ChartModel::resetData);
     connect(m_parser, &Parser::temporaryChartDataAvailable,
             temporaryModel, &ChartModel::resetData);
+    connect(m_parser, &Parser::sizeHistogramDataAvailable,
+            sizeHistogramModel, &HistogramModel::resetData);
     connect(m_parser, &Parser::summaryAvailable,
             m_ui->summary, &QLabel::setText);
     connect(m_parser, &Parser::topDownDataAvailable,
index cbbae1d..c58fa1f 100644 (file)
             <string>Allocated</string>
            </attribute>
           </widget>
+          <widget class="HistogramWidget" name="sizesTab">
+           <attribute name="title">
+            <string>Sizes</string>
+           </attribute>
+          </widget>
           <widget class="FlameGraph" name="flameGraphTab">
            <attribute name="title">
             <string>Flame Graph</string>
    <header>flamegraph.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>HistogramWidget</class>
+   <extends>QWidget</extends>
+   <header>histogramwidget.h</header>
+   <container>1</container>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
index 12fc978..52fdad9 100644 (file)
@@ -29,6 +29,7 @@
 #include "../accumulatedtracedata.h"
 
 #include <vector>
+#include <tuple>
 
 using namespace std;
 
@@ -239,9 +240,15 @@ struct ParserData final : public AccumulatedTraceData
         temporaryChartData.rows << temporary;
     }
 
-    void handleAllocation()
+    void handleAllocation(const BigAllocationInfo& info, const AllocationIndex index)
     {
         maxConsumedSinceLastTimeStamp = max(maxConsumedSinceLastTimeStamp, leaked);
+
+        if (index.index == allocationInfoCounter.size()) {
+            allocationInfoCounter.push_back({info, 1});
+        } else {
+            ++allocationInfoCounter[index.index].allocations;
+        }
     }
 
     void handleDebuggee(const char* command)
@@ -251,6 +258,17 @@ struct ParserData final : public AccumulatedTraceData
 
     string debuggee;
 
+    struct CountedAllocationInfo
+    {
+        BigAllocationInfo info;
+        uint64_t allocations;
+        bool operator<(const CountedAllocationInfo& rhs) const
+        {
+            return make_tuple(info.size, allocations) < make_tuple(rhs.info.size, rhs.allocations);
+        }
+    };
+    vector<CountedAllocationInfo> allocationInfoCounter;
+
     ChartData consumedChartData;
     ChartData allocationsChartData;
     ChartData allocatedChartData;
@@ -390,6 +408,78 @@ QVector<RowData> toTopDownData(const QVector<RowData>& bottomUpData)
     return topRows;
 }
 
+struct MergedHistogramColumnData
+{
+    std::shared_ptr<LocationData> location;
+    uint64_t allocations;
+    bool operator<(const std::shared_ptr<LocationData>& rhs) const
+    {
+        return location < rhs;
+    }
+};
+
+HistogramData buildSizeHistogram(ParserData& data)
+{
+    HistogramData ret;
+    if (data.allocationInfoCounter.empty()) {
+        return ret;
+    }
+    sort(data.allocationInfoCounter.begin(), data.allocationInfoCounter.end());
+    const auto totalLabel = i18n("total");
+    HistogramRow row;
+    const pair<uint64_t, QString> buckets[] = {
+        {8, i18n("0B to 8B")},
+        {16, i18n("9B to 16B")},
+        {32, i18n("17B to 32B")},
+        {64, i18n("33B to 64B")},
+        {128, i18n("65B to 128B")},
+        {256, i18n("129B to 256B")},
+        {512, i18n("257B to 512B")},
+        {1024, i18n("512B to 1KB")},
+        {numeric_limits<uint64_t>::max(), i18n("more than 1KB")}
+    };
+    uint bucketIndex = 0;
+    row.size = buckets[bucketIndex].first;
+    row.sizeLabel = buckets[bucketIndex].second;
+    vector<MergedHistogramColumnData> columnData;
+    columnData.reserve(128);
+    auto insertColumns = [&] () {
+        sort(columnData.begin(), columnData.end(), [] (const MergedHistogramColumnData& lhs, const MergedHistogramColumnData& rhs) {
+            return lhs.allocations > rhs.allocations;
+        });
+        // -1 to account for total row
+        for (size_t i = 0; i < size_t(HistogramRow::NUM_COLUMNS - 1); ++i) {
+            const auto& column = columnData[i];
+            row.columns[i + 1] = {column.allocations, column.location};
+        }
+    };
+    for (const auto& info : data.allocationInfoCounter) {
+        if (info.info.size > row.size) {
+            insertColumns();
+            columnData.clear();
+            ret << row;
+            ++bucketIndex;
+            row.size = buckets[bucketIndex].first;
+            row.sizeLabel = buckets[bucketIndex].second;
+            row.columns[0] = {info.allocations, {}};
+        } else {
+            row.columns[0].allocations += info.allocations;
+        }
+        const auto ipIndex = data.findTrace(info.info.traceIndex).ipIndex;
+        const auto ip = data.findIp(ipIndex);
+        const auto location = data.stringCache.location(ip);
+        auto it = lower_bound(columnData.begin(), columnData.end(), location);
+        if (it == columnData.end() || it->location != location) {
+            columnData.insert(it, {location, info.allocations});
+        } else {
+            it->allocations += info.allocations;
+        }
+    }
+    insertColumns();
+    ret << row;
+    return ret;
+}
+
 }
 
 Parser::Parser(QObject* parent)
@@ -411,11 +501,14 @@ void Parser::parse(const QString& path)
 
         // merge allocations before modifying the data again
         const auto mergedAllocations = mergeAllocations(*data);
+        // also calculate the size histogram
+        const auto sizeHistogram = buildSizeHistogram(*data);
         // now data can be modified again for the chart data evaluation
 
         auto parallel = new Collection;
-        *parallel << make_job([this, mergedAllocations]() {
+        *parallel << make_job([this, mergedAllocations, sizeHistogram]() {
             emit bottomUpDataAvailable(mergedAllocations);
+            emit sizeHistogramDataAvailable(sizeHistogram);
             const auto topDownData = toTopDownData(mergedAllocations);
             emit topDownDataAvailable(topDownData);
         }) << make_job([this, data, stdPath]() {
index 88438cd..72e0e46 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "treemodel.h"
 #include "chartmodel.h"
+#include "histogrammodel.h"
 
 class Parser : public QObject
 {
@@ -43,6 +44,7 @@ signals:
     void allocationsChartDataAvailable(const ChartData& data);
     void allocatedChartDataAvailable(const ChartData& data);
     void temporaryChartDataAvailable(const ChartData& data);
+    void sizeHistogramDataAvailable(const HistogramData& data);
     void finished();
 };
 
index d544ccd..5e6d0e5 100644 (file)
@@ -430,8 +430,12 @@ struct Printer final : public AccumulatedTraceData
         }
     }
 
-    void handleAllocation() override
+    void handleAllocation(const BigAllocationInfo& info, const AllocationIndex /*index*/) override
     {
+        if (printHistogram) {
+            ++sizeHistogram[info.size];
+        }
+
         if (leaked > lastMassifPeak && massifOut.is_open()) {
             massifAllocations = allocations;
             lastMassifPeak = leaked;
@@ -453,10 +457,13 @@ struct Printer final : public AccumulatedTraceData
         }
     }
 
+    bool printHistogram = false;
     bool mergeBacktraces = true;
 
     vector<MergedAllocation> mergedAllocations;
 
+    std::map<uint64_t, uint64_t> sizeHistogram;
+
     uint64_t massifSnapshotId = 0;
     uint64_t lastMassifPeak = 0;
     vector<Allocation> massifAllocations;