From: Milian Wolff Date: Fri, 11 Sep 2015 18:18:51 +0000 (+0200) Subject: Fix tooltips and show stacked graph. X-Git-Tag: submit/tizen/20180620.112952^2~282 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a3f45c5cad01c86a2e2e4d83c972f96ca2cd5e87;p=sdk%2Ftools%2Fheaptrack.git Fix tooltips and show stacked graph. --- diff --git a/gui/chartproxy.cpp b/gui/chartproxy.cpp index abf5c95..ef630ef 100644 --- a/gui/chartproxy.cpp +++ b/gui/chartproxy.cpp @@ -24,10 +24,12 @@ #include -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; } diff --git a/gui/chartproxy.h b/gui/chartproxy.h index 118c440..97dcb1d 100644 --- a/gui/chartproxy.h +++ b/gui/chartproxy.h @@ -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 diff --git a/gui/chartwidget.cpp b/gui/chartwidget.cpp index 90c45bf..c364c11 100644 --- a/gui/chartwidget.cpp +++ b/gui/chartwidget.cpp @@ -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()) { diff --git a/gui/parser.cpp b/gui/parser.cpp index fda1511..aff6385 100644 --- a/gui/parser.cpp +++ b/gui/parser.cpp @@ -34,6 +34,61 @@ 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(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& strings) + { + transform(strings.begin() + m_strings.size(), strings.end(), + back_inserter(m_strings), [] (const string& str) { return QString::fromStdString(str); }); + } + + vector 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(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 m_strings; -}; - void setParents(QVector& children, const RowData* parent) { for (auto& row: children) { @@ -170,10 +182,9 @@ void setParents(QVector& children, const RowData* parent) } } -QVector mergeAllocations(const AccumulatedTraceData& data) +QVector mergeAllocations(const ParserData& data) { QVector 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 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;