#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;
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);
}
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;
}
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()
void handleTimeStamp(uint64_t /*newStamp*/, uint64_t oldStamp)
{
+ stringCache.update(strings);
maxLeakedSinceLastTimeStamp = max(maxLeakedSinceLastTimeStamp, leaked);
ChartRows data;
data.timeStamp = oldStamp;
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;
ChartData chartData;
uint64_t maxLeakedSinceLastTimeStamp = 0;
+
+ StringCache stringCache;
};
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) {
}
}
-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;
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;