Skip to content

Commit

Permalink
feat: tracepoint data on hover
Browse files Browse the repository at this point in the history
  • Loading branch information
lievenhey committed Nov 18, 2024
1 parent 5ebd0b0 commit f1454ef
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/models/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_library(
timeaxisheaderview.cpp
timelinedelegate.cpp
topproxy.cpp
tracepointformat.cpp
treemodel.cpp
)

Expand Down
23 changes: 21 additions & 2 deletions src/models/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <QSet>
#include <QString>
#include <QTypeInfo>
#include <QVariant>
#include <QVector>

#include "../util.h"
Expand Down Expand Up @@ -787,18 +788,23 @@ const constexpr auto INVALID_CPU_ID = std::numeric_limits<quint32>::max();
const constexpr int INVALID_TID = -1;
const constexpr int INVALID_PID = -1;

const constexpr auto INVALID_TRACEPOINTFORMAT = std::numeric_limits<quint32>::max();
const constexpr auto INVALID_TRACEPOINTDATA = std::numeric_limits<quint32>::max();

struct Event
{
quint64 time = 0;
quint64 cost = 0;
qint32 type = -1;
qint32 stackId = -1;
quint32 cpuId = INVALID_CPU_ID;
quint32 tracepointFormat = INVALID_TRACEPOINTFORMAT;
quint32 tracepointData = INVALID_TRACEPOINTDATA;

bool operator==(const Event& rhs) const
{
return std::tie(time, cost, type, stackId, cpuId)
== std::tie(rhs.time, rhs.cost, rhs.type, rhs.stackId, rhs.cpuId);
return std::tie(time, cost, type, stackId, cpuId, tracepointFormat, tracepointData)
== std::tie(rhs.time, rhs.cost, rhs.type, rhs.stackId, rhs.cpuId, rhs.tracepointFormat, rhs.tracepointData);
}
};

Expand Down Expand Up @@ -962,13 +968,26 @@ struct TracepointEvents
}
};

struct TracePointFormat
{
QString systemId;
QString nameId;
quint32 flags;
QString format;
};

#include <QHash>
using TracePointData = QHash<QString, QVariant>;

struct EventResults
{
QVector<ThreadEvents> threads;
QVector<CpuEvents> cpus;
QVector<TracepointEvents> tracepoints;
QVector<QVector<qint32>> stacks;
QVector<CostSummary> totalCosts;
QHash<quint32, TracePointFormat> tracePointFormats;
QVector<TracePointData> tracePointData;
qint32 offCpuTimeCostId = -1;
qint32 lostEventCostId = -1;
qint32 tracepointEventCostId = -1;
Expand Down
34 changes: 28 additions & 6 deletions src/models/timelinedelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "../util.h"
#include "eventmodel.h"
#include "filterandzoomstack.h"
#include "tracepointformat.h"

#include <KColorScheme>

Expand Down Expand Up @@ -314,7 +315,6 @@ bool TimeLineDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, con
// check whether we are hovering an off-CPU area
found = findSamples(results.offCpuTimeCostId, true);
}

const auto formattedTime = Util::formatTimeString(time - data.time.start);
const auto totalCosts = index.data(EventModel::TotalCostsRole).value<QVector<Data::CostSummary>>();
if (found.numLost > 0) {
Expand All @@ -329,12 +329,34 @@ bool TimeLineDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, con
Util::formatTimeString(found.totalCost),
Util::formatTimeString(found.maxCost)));
} else if (found.numSamples > 0) {
qDebug() << m_eventType;
if (m_eventType == results.tracepointEventCostId) {
// currently tracepoint cost is saying nothig, so don't show it
QToolTip::showText(
event->globalPos(),
tr("time: %1\n%3 samples: %2")
.arg(formattedTime, QString::number(found.numSamples), results.tracepoints[index.row()].name));
qDebug() << "HERE" << found.numSamples;
if (found.numSamples != 1) {
QToolTip::showText(event->globalPos(),
tr("time: %1\n%3 samples: %2")
.arg(formattedTime, QString::number(found.numSamples),
results.tracepoints[index.row()].name));
} else {
// we only hover over one tracepoint, find it
Data::Event tracepoint;
data.findSamples(mappedX, m_eventType, results.lostEventCostId, false, start,
[&tracepoint](const Data::Event& event, bool isLost) {
Q_UNUSED(isLost);
tracepoint = event;
});

const auto format = results.tracePointFormats[tracepoint.tracepointFormat];
qDebug() << format.systemId << format.nameId << format.format;
qDebug() << results.tracePointData[tracepoint.tracepointData];

TracePointFormatter formatter(format.format);

QToolTip::showText(event->globalPos(),
tr("time: %1\n%2:\n%3")
.arg(formattedTime, results.tracepoints[index.row()].name,
formatter.format(results.tracePointData[tracepoint.tracepointData])));
}

} else {
QToolTip::showText(event->globalPos(),
Expand Down
54 changes: 42 additions & 12 deletions src/parsers/perf/perfparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,13 +560,24 @@ QDebug operator<<(QDebug stream, const TracePointFormat& format)
return stream;
}

using TracePointData = QHash<qint32, QVariant>;
struct TracePointData
{
quint32 formatId;
QHash<quint32, QVariant> data;
};

QDataStream& operator>>(QDataStream& stream, TracePointData& traceData)
{
stream >> traceData.formatId >> traceData.data;
return stream;
}

QDebug operator<<(QDebug stream, const TracePointData& traceData)
{
auto s = stream.noquote().nospace();
s << "TracePointData{";
for (auto it = traceData.cbegin(), end = traceData.cend(); it != end; it++) {
s << "eventId=" << traceData.formatId << ", ";
for (auto it = traceData.data.cbegin(), end = traceData.data.cend(); it != end; it++) {
s << it.key() << "=" << it.value() << ", ";
}
s << "}";
Expand Down Expand Up @@ -795,12 +806,11 @@ class PerfParserPrivate : public QObject
}

if (static_cast<EventType>(eventType) == EventType::TracePointSample) {
quint32 eventFormatId;
TracePointData traceData;
stream >> eventFormatId >> traceData;
tracepointData[eventFormatId].push_back(traceData);
qCDebug(LOG_PERFPARSER) << "parsed:" << traceData;
sample.tracePointFormat = eventFormatId;
stream >> traceData;
tracepointData.push_back(traceData);
qCDebug(LOG_PERFPARSER) << "DATA parsed:" << traceData;
sample.tracePointFormat = traceData.formatId;
sample.tracePointData = tracepointData.size() - 1;
}

Expand Down Expand Up @@ -921,7 +931,7 @@ class PerfParserPrivate : public QObject
case EventType::TracePointFormat: {
qint32 id;
TracePointFormat format;
stream >> id >> format;
stream >> id >> format; // id is the tracepoint id, see /sys/kernel/tracing/system/tracepoint
qCDebug(LOG_PERFPARSER) << "parsed:" << format;
tracepointFormat[id] = format;
break;
Expand Down Expand Up @@ -954,10 +964,28 @@ class PerfParserPrivate : public QObject
buildPerLibraryResult();
buildCallerCalleeResult();

for (auto it = tracepoints.begin(), end = tracepoints.end(); it != end; it++) {
for (auto it = tracepoints.cbegin(), end = tracepoints.cend(); it != end; it++) {
eventResult.tracepoints.push_back({strings[it.key()], {it.value()}});
}

eventResult.tracePointData.reserve(tracepointData.size());
std::transform(tracepointData.cbegin(), tracepointData.cend(), std::back_inserter(eventResult.tracePointData),
[this](const TracePointData& data) -> Data::TracePointData {
QHash<QString, QVariant> tracepointData;

for (auto it = data.data.cbegin(), end = data.data.cend(); it != end; it++) {
tracepointData[strings.value(it.key())] = it.value();
}

return tracepointData;
});

for (auto it = tracepointFormat.cbegin(), end = tracepointFormat.cend(); it != end; it++) {
qDebug() << "FORMAT" << strings.value(it->format.id);
eventResult.tracePointFormats[it.key()] = {strings.value(it->systemId.id), strings.value(it->nameId.id),
it->flags, strings.value(it->format.id)};
}

for (auto& thread : eventResult.threads) {
thread.time.start = std::max(thread.time.start, applicationTime.start);
thread.time.end = std::min(thread.time.end, applicationTime.end);
Expand Down Expand Up @@ -1174,6 +1202,8 @@ class PerfParserPrivate : public QObject
event.type = attributeIdsToCostIds.value(sampleCost.attributeId, -1);
event.stackId = internStack(sample.frames);
event.cpuId = sample.cpu;
event.tracepointFormat = sample.tracePointFormat;
event.tracepointData = sample.tracePointData;
thread->events.push_back(event);
cpu.events.push_back(event);

Expand All @@ -1186,7 +1216,8 @@ class PerfParserPrivate : public QObject

if (attribute.name.id != m_schedSwitchId) {
auto& tracepointList = tracepoints[attribute.name.id];
tracepointList.push_back({event.time, 0, eventResult.tracepointEventCostId});
event.type = eventResult.tracepointEventCostId;
tracepointList.push_back(event);
}
}
}
Expand Down Expand Up @@ -1494,7 +1525,7 @@ class PerfParserPrivate : public QObject
Settings::CostAggregation costAggregation;
bool perfMapFileExists = false;
QHash<quint32, TracePointFormat> tracepointFormat;
QHash<quint32, QVector<TracePointData>> tracepointData;
QVector<TracePointData> tracepointData;

// samples recorded without --call-graph have only one frame
int m_numSamplesWithMoreThanOneFrame = 0;
Expand Down Expand Up @@ -1526,7 +1557,6 @@ PerfParser::PerfParser(QObject* parent)
qRegisterMetaType<Data::ByFileResults>();
qRegisterMetaType<Data::EventResults>();
qRegisterMetaType<Data::PerLibraryResults>();
qRegisterMetaType<Data::TracepointEvents>();
qRegisterMetaType<Data::FrequencyResults>();
qRegisterMetaType<Data::ThreadNames>();

Expand Down
14 changes: 13 additions & 1 deletion tests/modeltests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ set_target_properties(

ecm_add_test(
tst_disassemblyoutput.cpp
../../src/settings.cpp
LINK_LIBRARIES
Qt::Core
Qt::Test
models
PrefixTickLabels
TEST_NAME
tst_disassemblyoutput
../../src/settings.cpp
)

set_target_properties(
Expand Down Expand Up @@ -91,3 +91,15 @@ ecm_add_test(
tst_formatting
)
set_target_properties(tst_formatting PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${KDE_INSTALL_BINDIR}")

ecm_add_test(
tst_tracepointformat.cpp
LINK_LIBRARIES
Qt::Test
models
TEST_NAME
tst_tracepointformat
)
set_target_properties(
tst_tracepointformat PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${KDE_INSTALL_BINDIR}"
)

0 comments on commit f1454ef

Please sign in to comment.