Fix tooltips and show stacked graph.
authorMilian Wolff <mail@milianw.de>
Fri, 11 Sep 2015 18:18:51 +0000 (20:18 +0200)
committerMilian Wolff <mail@milianw.de>
Fri, 11 Sep 2015 18:18:51 +0000 (20:18 +0200)
gui/chartproxy.cpp
gui/chartproxy.h
gui/chartwidget.cpp
gui/parser.cpp

index abf5c95..ef630ef 100644 (file)
 
 #include <QDebug>
 
-ChartProxy::ChartProxy(ChartModel::Columns column, QObject* parent)
+ChartProxy::ChartProxy(ChartModel::Columns column, bool showTotal, QObject* parent)
     : QSortFilterProxyModel(parent)
     , m_column(column)
-{}
+    , m_showTotal(showTotal)
+{
+}
 
 ChartProxy::~ChartProxy() = default;
 
@@ -40,10 +42,10 @@ QVariant ChartProxy::headerData(int section, Qt::Orientation orientation, int ro
 QVariant ChartProxy::data(const QModelIndex& proxyIndex, int role) const
 {
     static_assert(ChartModel::TimeStampColumn == 0, "The code below assumes the time stamp column comes with value 0.");
-    if (role == Qt::ToolTipRole && proxyIndex.column() == 0) {
+    if (role == Qt::ToolTipRole) {
         // KChart queries the tooltip for the timestamp column, which is not useful for us
         // instead, we want to use the m_column, or in proxy column value that is 1
-        return QSortFilterProxyModel::data(index(proxyIndex.row(), 1, proxyIndex.parent()), role);
+        return QSortFilterProxyModel::data(index(proxyIndex.row(), proxyIndex.column() + 1, proxyIndex.parent()), role);
     } else {
         return QSortFilterProxyModel::data(proxyIndex, role);
     }
@@ -51,6 +53,10 @@ QVariant ChartProxy::data(const QModelIndex& proxyIndex, int role) const
 
 bool ChartProxy::filterAcceptsColumn(int sourceColumn, const QModelIndex& /*sourceParent*/) const
 {
-    const auto column = sourceColumn % 4;
+    if (m_showTotal && sourceColumn >= ChartModel::NUM_COLUMNS)
+        return false;
+    else if (!m_showTotal && sourceColumn < ChartModel::NUM_COLUMNS)
+        return false;
+    const auto column = sourceColumn % ChartModel::NUM_COLUMNS;
     return column == ChartModel::TimeStampColumn || column == m_column;
 }
index 118c440..97dcb1d 100644 (file)
@@ -27,7 +27,7 @@ class ChartProxy : public QSortFilterProxyModel
 {
     Q_OBJECT
 public:
-    explicit ChartProxy(ChartModel::Columns column, QObject* parent = nullptr);
+    explicit ChartProxy(ChartModel::Columns column, bool showTotal, QObject* parent = nullptr);
     virtual ~ChartProxy();
 
     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
@@ -38,6 +38,7 @@ protected:
 
 private:
     ChartModel::Columns m_column;
+    bool m_showTotal;
 };
 
 #endif //CHARTPROXY_H
index 90c45bf..c364c11 100644 (file)
@@ -99,7 +99,7 @@ void ChartWidget::setModel(ChartModel* model, ChartModel::Columns costColumn)
     }
 
     Q_ASSERT(costColumn != ChartModel::TimeStampColumn);
-    auto proxy = new ChartProxy(costColumn, this);
+    auto proxy = new ChartProxy(costColumn, false, this);
     proxy->setSourceModel(model);
 
     foreach (auto axis, m_plotter->axes()) {
index fda1511..aff6385 100644 (file)
 using namespace std;
 
 namespace {
+
+// TODO: use QString directly
+struct StringCache
+{
+    StringCache()
+    {
+    }
+
+    QString func(const InstructionPointer& ip) const
+    {
+        if (ip.functionIndex) {
+            // TODO: support removal of template arguments
+            return stringify(ip.functionIndex);
+        } else {
+            return static_cast<QString>(QLatin1String("0x") + QString::number(ip.instructionPointer, 16));
+        }
+    }
+
+    QString file(const InstructionPointer& ip) const
+    {
+        if (ip.fileIndex) {
+            return stringify(ip.fileIndex);
+        } else {
+            return {};
+        }
+    }
+
+    QString module(const InstructionPointer& ip) const
+    {
+        return stringify(ip.moduleIndex);
+    }
+
+    QString stringify(const StringIndex index) const
+    {
+        if (!index || index.index > m_strings.size()) {
+            return {};
+        } else {
+            return m_strings.at(index.index - 1);
+        }
+    }
+
+    LocationData location(const InstructionPointer& ip) const
+    {
+        return {func(ip), file(ip), module(ip), ip.line};
+    }
+
+    void update(const vector<string>& strings)
+    {
+        transform(strings.begin() + m_strings.size(), strings.end(),
+                  back_inserter(m_strings), [] (const string& str) { return QString::fromStdString(str); });
+    }
+
+    vector<QString> m_strings;
+};
+
 struct ParserData final : public AccumulatedTraceData
 {
     ParserData()
@@ -43,6 +98,7 @@ struct ParserData final : public AccumulatedTraceData
 
     void handleTimeStamp(uint64_t /*newStamp*/, uint64_t oldStamp)
     {
+        stringCache.update(strings);
         maxLeakedSinceLastTimeStamp = max(maxLeakedSinceLastTimeStamp, leaked);
         ChartRows data;
         data.timeStamp = oldStamp;
@@ -50,27 +106,31 @@ struct ParserData final : public AccumulatedTraceData
         data.allocations.push_back({i18n("total"), totalAllocations});
         data.allocated.push_back({i18n("total"), totalAllocated});
 
+        // TODO: deduplicate code
         auto allocs = allocations;
         sort(allocs.begin(), allocs.end(), [] (const Allocation& left, const Allocation& right) {
             return left.leaked < right.leaked;
         });
         for (size_t i = 0; i < min(size_t(10), allocs.size()); ++i) {
-            QString function;
-            data.leaked.push_back({function, allocs[i].leaked});
+            const auto& alloc = allocs[i];
+            auto function = stringCache.func(findIp(findTrace(alloc.traceIndex).ipIndex));
+            data.leaked.push_back({function, alloc.leaked});
         }
         sort(allocs.begin(), allocs.end(), [] (const Allocation& left, const Allocation& right) {
             return left.allocations < right.allocations;
         });
         for (size_t i = 0; i < min(size_t(10), allocs.size()); ++i) {
-            QString function;
-            data.allocations.push_back({function, allocs[i].allocations});
+            const auto& alloc = allocs[i];
+            auto function = stringCache.func(findIp(findTrace(alloc.traceIndex).ipIndex));
+            data.allocations.push_back({function, alloc.allocations});
         }
         sort(allocs.begin(), allocs.end(), [] (const Allocation& left, const Allocation& right) {
             return left.allocated < right.allocated;
         });
         for (size_t i = 0; i < min(size_t(10), allocs.size()); ++i) {
-            QString function;
-            data.allocated.push_back({function, allocs[i].allocated});
+            const auto& alloc = allocs[i];
+            auto function = stringCache.func(findIp(findTrace(alloc.traceIndex).ipIndex));
+            data.allocated.push_back({function, alloc.allocated});
         }
         chartData.push_back(data);
         maxLeakedSinceLastTimeStamp = 0;
@@ -90,6 +150,8 @@ struct ParserData final : public AccumulatedTraceData
 
     ChartData chartData;
     uint64_t maxLeakedSinceLastTimeStamp = 0;
+
+    StringCache stringCache;
 };
 
 QString generateSummary(const ParserData& data)
@@ -112,56 +174,6 @@ QString generateSummary(const ParserData& data)
     return ret;
 }
 
-struct StringCache
-{
-    StringCache(const AccumulatedTraceData& data)
-    {
-        m_strings.resize(data.strings.size());
-        transform(data.strings.begin(), data.strings.end(),
-                  m_strings.begin(), [] (const string& str) { return QString::fromStdString(str); });
-    }
-
-    QString func(const InstructionPointer& ip) const
-    {
-        if (ip.functionIndex) {
-            // TODO: support removal of template arguments
-            return stringify(ip.functionIndex);
-        } else {
-            return static_cast<QString>(QLatin1String("0x") + QString::number(ip.instructionPointer, 16));
-        }
-    }
-
-    QString file(const InstructionPointer& ip) const
-    {
-        if (ip.fileIndex) {
-            return stringify(ip.fileIndex);
-        } else {
-            return {};
-        }
-    }
-
-    QString module(const InstructionPointer& ip) const
-    {
-        return stringify(ip.moduleIndex);
-    }
-
-    QString stringify(const StringIndex index) const
-    {
-        if (!index || index.index > m_strings.size()) {
-            return {};
-        } else {
-            return m_strings.at(index.index - 1);
-        }
-    }
-
-    LocationData location(const InstructionPointer& ip) const
-    {
-        return {func(ip), file(ip), module(ip), ip.line};
-    }
-
-    vector<QString> m_strings;
-};
-
 void setParents(QVector<RowData>& children, const RowData* parent)
 {
     for (auto& row: children) {
@@ -170,10 +182,9 @@ void setParents(QVector<RowData>& children, const RowData* parent)
     }
 }
 
-QVector<RowData> mergeAllocations(const AccumulatedTraceData& data)
+QVector<RowData> mergeAllocations(const ParserData& data)
 {
     QVector<RowData> topRows;
-    StringCache strings(data);
     // merge allocations, leave parent pointers invalid (their location may change)
     for (const auto& allocation : data.allocations) {
         auto traceIndex = allocation.traceIndex;
@@ -182,7 +193,7 @@ QVector<RowData> mergeAllocations(const AccumulatedTraceData& data)
             const auto& trace = data.findTrace(traceIndex);
             const auto& ip = data.findIp(trace.ipIndex);
             // TODO: only store the IpIndex and use that
-            auto location = strings.location(ip);
+            auto location = data.stringCache.location(ip);
             auto it = lower_bound(rows->begin(), rows->end(), location);
             if (it != rows->end() && it->location == location) {
                 it->allocated += allocation.allocated;