quint64 consumed;
quint64 allocations;
quint64 allocated;
+ quint64 temporary;
bool operator<(const IpIndex rhs) const
{
return ip < rhs;
consumedChartData.rows.reserve(MAX_CHART_DATAPOINTS);
allocatedChartData.rows.reserve(MAX_CHART_DATAPOINTS);
allocationsChartData.rows.reserve(MAX_CHART_DATAPOINTS);
+ temporaryChartData.rows.reserve(MAX_CHART_DATAPOINTS);
// start off with null data at the origin
consumedChartData.rows.push_back({});
allocatedChartData.rows.push_back({});
allocationsChartData.rows.push_back({});
+ temporaryChartData.rows.push_back({});
// index 0 indicates the total row
consumedChartData.labels[0] = i18n("total");
allocatedChartData.labels[0] = i18n("total");
allocationsChartData.labels[0] = i18n("total");
+ temporaryChartData.labels[0] = i18n("total");
buildCharts = true;
maxConsumedSinceLastTimeStamp = 0;
const auto ip = findTrace(alloc.traceIndex).ipIndex;
auto it = lower_bound(merged.begin(), merged.end(), ip);
if (it == merged.end() || it->ip != ip) {
- it = merged.insert(it, {ip, 0, 0, 0});
+ it = merged.insert(it, {ip, 0, 0, 0, 0});
}
it->consumed += alloc.peak; // we want to track the top peaks in the chart
it->allocated += alloc.allocated;
it->allocations += alloc.allocations;
+ it->temporary += alloc.temporary;
}
// find the top hot spots for the individual data members and remember their IP and store the label
auto findTopChartEntries = [&] (quint64 ChartMergeData::* member, int LabelIds::* label, ChartData* data) {
findTopChartEntries(&ChartMergeData::consumed, &LabelIds::consumed, &consumedChartData);
findTopChartEntries(&ChartMergeData::allocated, &LabelIds::allocated, &allocatedChartData);
findTopChartEntries(&ChartMergeData::allocations, &LabelIds::allocations, &allocationsChartData);
+ findTopChartEntries(&ChartMergeData::temporary, &LabelIds::temporary, &temporaryChartData);
}
void handleTimeStamp(uint64_t /*oldStamp*/, uint64_t newStamp)
auto consumed = createRow(newStamp, nowConsumed);
auto allocated = createRow(newStamp, totalAllocated);
auto allocs = createRow(newStamp, totalAllocations);
+ auto temporary = createRow(newStamp, totalTemporary);
// if the cost is non-zero and the ip corresponds to a hotspot function selected in the labels,
// we add the cost to the rows column
addDataToRow(alloc.leaked, labelIds.consumed, &consumed);
addDataToRow(alloc.allocated, labelIds.allocated, &allocated);
addDataToRow(alloc.allocations, labelIds.allocations, &allocs);
+ addDataToRow(alloc.temporary, labelIds.temporary, &temporary);
}
// add the rows for this time stamp
consumedChartData.rows << consumed;
allocatedChartData.rows << allocated;
allocationsChartData.rows << allocs;
+ temporaryChartData.rows << temporary;
}
void handleAllocation()
ChartData consumedChartData;
ChartData allocationsChartData;
ChartData allocatedChartData;
+ ChartData temporaryChartData;
// here we store the indices into ChartRows::cost for those IpIndices that
// are within the top hotspots. This way, we can do one hash lookup in the
// handleTimeStamp function instead of three when we'd store this data
int consumed = -1;
int allocations = -1;
int allocated = -1;
+ int temporary = -1;
};
QHash<IpIndex, LabelIds> labelIds;
uint64_t maxConsumedSinceLastTimeStamp = 0;
format.formatByteSize(data.totalAllocated, 2), format.formatByteSize(data.totalAllocated / totalTimeS)) << "<br/>"
<< i18n("<strong>calls to allocation functions</strong>: %1 (%2/s)",
data.totalAllocations, quint64(data.totalAllocations / totalTimeS)) << "<br/>"
+ << i18n("<strong>temporary allocations</strong>: %1 (%2%, %3/s)",
+ data.totalTemporary, round(float(data.totalTemporary) * 100.f * 100.f / data.totalAllocations) / 100.f,
+ quint64(data.totalTemporary / totalTimeS)) << "<br/>"
<< i18n("<strong>peak heap memory consumption</strong>: %1", format.formatByteSize(data.peak)) << "<br/>"
<< i18n("<strong>total memory leaked</strong>: %1", format.formatByteSize(data.leaked)) << "<br/>";
stream << "</qt>";
if (it != rows->end() && it->location == location) {
it->allocated += allocation.allocated;
it->allocations += allocation.allocations;
+ it->temporary += allocation.temporary;
it->leaked += allocation.leaked;
it->peak += allocation.peak;
} else {
- it = rows->insert(it, {allocation.allocations, allocation.peak, allocation.leaked, allocation.allocated,
+ it = rows->insert(it, {allocation.allocations, allocation.peak, allocation.leaked, allocation.allocated, allocation.temporary,
location, nullptr, {}});
}
if (data.isStopIndex(ip.functionIndex)) {
auto data = findByLocation(*node, stack);
if (!data) {
// create an empty top-down item for this bottom-up node
- *stack << RowData{0, 0, 0, 0, node->location, nullptr, {}};
+ *stack << RowData{0, 0, 0, 0, 0, node->location, nullptr, {}};
data = &stack->back();
}
// always use the leaf node's cost and propagate that one up the chain
data->peak += row.peak;
data->leaked += row.leaked;
data->allocated += row.allocated;
+ data->temporary += row.temporary;
stack = &data->children;
node = node->parent;
}
emit consumedChartDataAvailable(data->consumedChartData);
emit allocationsChartDataAvailable(data->allocationsChartData);
emit allocatedChartDataAvailable(data->allocatedChartData);
+ emit temporaryChartDataAvailable(data->temporaryChartData);
});
auto sequential = new Sequence;
#include <KFormat>
#include <KLocalizedString>
+#include <cmath>
+
namespace {
int indexOf(const RowData* row, const TreeData& siblings)
return i18n("Module");
case AllocationsColumn:
return i18n("Allocations [-]");
+ case TemporaryColumn:
+ return i18n("Temporary Allocations [-]");
case PeakColumn:
return i18n("Peak [B]");
case LeakedColumn:
return i18n("<qt>The module, i.e. executable or shared library, from which an allocation function was called.</qt>");
case AllocationsColumn:
return i18n("<qt>The number of times an allocation function was called from this location.</qt>");
+ case TemporaryColumn:
+ return i18n("<qt>The number of temporary allocations. These allocations are directly followed by a free without any other allocations in-between.</qt>");
case PeakColumn:
return i18n("<qt>The maximum heap memory in bytes consumed from allocations originating at this location. "
"This takes deallocations into account.</qt>");
return row->allocated;
case AllocationsColumn:
return row->allocations;
+ case TemporaryColumn:
+ return row->temporary;
case PeakColumn:
return row->peak;
case LeakedColumn:
row->location->function, row->location->file, row->location->line, row->location->module);
stream << '\n';
KFormat format;
- stream << i18n("allocated %1 over %2 calls, peak at %3, leaked %4",
- format.formatByteSize(row->allocated), row->allocations,
+ stream << i18n("allocated %1 over %2 calls (%3 temporary, i.e. %4%), peak at %5, leaked %6",
+ format.formatByteSize(row->allocated), row->allocations, row->temporary,
+ round(float(row->temporary) * 100.f * 100.f / row->allocations) / 100.f,
format.formatByteSize(row->peak), format.formatByteSize(row->leaked));
stream << '\n';
if (!row->children.isEmpty()) {