summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/perfsymboltable.cpp158
-rw-r--r--app/perfsymboltable.h4
-rw-r--r--tests/auto/shared/perfparsertestclient.cpp43
-rw-r--r--tests/auto/shared/perfparsertestclient.h6
-rw-r--r--tests/manual/perf2text/perf2text.cpp45
5 files changed, 85 insertions, 171 deletions
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index 07d6f3a..28289fa 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -599,116 +599,23 @@ PerfElfMap::ElfInfo PerfSymbolTable::findElf(quint64 ip) const
return m_elfs.findElf(ip);
}
-struct AddrRange
+class CuDieRanges
{
- Dwarf_Addr low = 0;
- Dwarf_Addr high = 0;
-
- void setMinMax(const AddrRange range)
- {
- if (range.low && (low == 0 || low > range.low))
- low = range.low;
- if (range.high && (high == 0 || high < range.high))
- high = range.high;
- }
-
- bool contains(Dwarf_Addr addr) const
- {
- return low <= addr && addr < high;
- }
-
- bool operator<(const AddrRange &rhs) const
- {
- return std::tie(low, high) < std::tie(rhs.low, rhs.high);
- }
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(AddrRange, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-struct DieRangeMap
-{
- DieRangeMap(Dwarf_Die *die = nullptr, Dwarf_Addr bias = 0)
- : die(die)
- , bias(bias)
- {
- if (die)
- gatherRanges(die, bias);
- }
-
- bool contains(Dwarf_Addr addr) const
- {
- if (!range.contains(addr))
- return false;
- return std::any_of(ranges.begin(), ranges.end(),
- [addr](AddrRange range) {
- return range.contains(addr);
- });
- }
-
- bool operator<(const DieRangeMap &rhs) const
- {
- return range < rhs.range;
- }
-
- Dwarf_Die *die = nullptr;
- AddrRange range; // may be non-continuous, but allows quick checks and sorting
- QVector<AddrRange> ranges;
- Dwarf_Addr bias;
-
-private:
- void gatherRanges(Dwarf_Die *parent_die, Dwarf_Addr bias)
- {
- Dwarf_Die die;
- if (dwarf_child(parent_die, &die) != 0)
- return;
-
- do {
- switch (dwarf_tag(&die)) {
- case DW_TAG_subprogram:
- case DW_TAG_inlined_subroutine:
- addRanges(&die, bias);
- break;
- };
- bool declaration = false;
- Dwarf_Attribute attr_mem;
- dwarf_formflag(dwarf_attr(&die, DW_AT_declaration, &attr_mem), &declaration);
- if (!declaration) {
- // let's be curious and look deeper in the tree,
- // function are not necessarily at the first level, but
- // might be nested inside a namespace, structure etc.
- gatherRanges(&die, bias);
- }
- } while (dwarf_siblingof(&die, &die) == 0);
- }
-
- void addRanges(Dwarf_Die *die, Dwarf_Addr bias)
+public:
+ struct CuDieRange
{
- Dwarf_Addr low = 0, high = 0;
- Dwarf_Addr base = 0;
- ptrdiff_t offset = 0;
- while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
- addRange(low, high, bias);
+ Dwarf_Die *cuDie;
+ Dwarf_Addr bias;
+ Dwarf_Addr low;
+ Dwarf_Addr high;
+
+ bool contains(Dwarf_Addr addr) const
+ {
+ return low <= addr && addr < high;
}
- }
+ };
- void addRange(Dwarf_Addr low, Dwarf_Addr high, Dwarf_Addr bias)
- {
- AddrRange ret;
- ret.low = low + bias;
- ret.high = high + bias;
- range.setMinMax(ret);
- ranges.push_back(ret);
- }
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(DieRangeMap, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-class DieRangeMaps
-{
-public:
- DieRangeMaps(Dwfl_Module *mod = nullptr)
+ CuDieRanges(Dwfl_Module *mod = nullptr)
{
if (!mod)
return;
@@ -716,37 +623,34 @@ public:
Dwarf_Die *die = nullptr;
Dwarf_Addr bias = 0;
while ((die = dwfl_module_nextcu(mod, die, &bias))) {
- DieRangeMap map(die, bias);
- if (map.range.low == 0 && map.range.high == 0) {
- // no range entries, skip
- continue;
+ Dwarf_Addr low = 0;
+ Dwarf_Addr high = 0;
+ Dwarf_Addr base = 0;
+ ptrdiff_t offset = 0;
+ while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
+ ranges.push_back(CuDieRange{die, bias, low + bias, high + bias});
}
- range.setMinMax(map.range);
- maps.push_back(std::move(map));
}
}
Dwarf_Die *findDie(Dwarf_Addr addr, Dwarf_Addr *bias) const
{
- if (!range.contains(addr))
- return nullptr;
-
- auto it = std::find_if(maps.begin(), maps.end(),
- [addr](const DieRangeMap &map) {
- return map.contains(addr);
+ auto it = std::find_if(ranges.begin(), ranges.end(),
+ [addr](const CuDieRange &range) {
+ return range.contains(addr);
});
- if (it == maps.end())
+ if (it == ranges.end())
return nullptr;
*bias = it->bias;
- return it->die;
+ return it->cuDie;
}
public:
- AddrRange range; // may be non-continuous, but allows quick checks
- QVector<DieRangeMap> maps;
+ QVector<CuDieRange> ranges;
};
QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(DieRangeMaps, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(CuDieRanges, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(CuDieRanges::CuDieRange, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
int symbolIndex(const Elf64_Rel &rel)
@@ -969,10 +873,10 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
// broken DWARF emitter by clang, e.g. no aranges
// cf.: https://sourceware.org/ml/elfutils-devel/2017-q2/msg00180.html
// build a custom lookup table and query that one
- if (!m_dieRangeMaps.contains(mod)) {
- m_dieRangeMaps[mod] = DieRangeMaps(mod);
+ if (!m_cuDieRanges.contains(mod)) {
+ m_cuDieRanges[mod] = CuDieRanges(mod);
}
- const auto& maps = m_dieRangeMaps[mod];
+ const auto& maps = m_cuDieRanges[mod];
die = maps.findDie(addressLocation.address, &bias);
}
@@ -1127,7 +1031,7 @@ Dwfl *PerfSymbolTable::attachDwfl(void *arg)
void PerfSymbolTable::clearCache()
{
m_addressCache.clearInvalid();
- m_dieRangeMaps.clear();
+ m_cuDieRanges.clear();
m_perfMap.clear();
if (m_perfMapFile.isOpen())
m_perfMapFile.reset();
diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h
index 4d9318b..9687763 100644
--- a/app/perfsymboltable.h
+++ b/app/perfsymboltable.h
@@ -34,7 +34,7 @@
#include <QObject>
-class DieRangeMaps;
+class CuDieRanges;
class PerfSymbolTable
{
@@ -111,7 +111,7 @@ private:
PerfElfMap m_elfs;
PerfAddressCache m_addressCache;
- QHash<Dwfl_Module*, DieRangeMaps> m_dieRangeMaps;
+ QHash<Dwfl_Module*, CuDieRanges> m_cuDieRanges;
Dwfl_Callbacks *m_callbacks;
qint32 m_pid;
diff --git a/tests/auto/shared/perfparsertestclient.cpp b/tests/auto/shared/perfparsertestclient.cpp
index ac45c28..82eed31 100644
--- a/tests/auto/shared/perfparsertestclient.cpp
+++ b/tests/auto/shared/perfparsertestclient.cpp
@@ -20,6 +20,7 @@
#include "perffeatures.h"
#include "perfparsertestclient.h"
+#include <QTextStream>
#include <QtEndian>
#ifdef MANUAL_TEST
@@ -187,3 +188,45 @@ void PerfParserTestClient::extractTrace(QIODevice *device)
QVERIFY(stream.atEnd());
}
}
+
+void PerfParserTestClient::convertToText(QTextStream &out) const
+{
+ for (const auto &sample : samples()) {
+ out << string(command(sample.pid).name) << '\t'
+ << sample.pid << '\t' << sample.tid << '\t'
+ << sample.time / 1000000000 << '.' << qSetFieldWidth(9) << qSetPadChar(QLatin1Char('0'))
+ << sample.time % 1000000000 << qSetFieldWidth(0) << qSetPadChar(QLatin1Char(' ')) << '\n';
+ for (const auto &value : sample.values) {
+ const auto attribute = this->attribute(value.first);
+ const auto cost = attribute.usesFrequency ? value.second : attribute.frequencyOrPeriod;
+ out << '\t' << string(attribute.name) << ": ";
+ if (attribute.type == 2) {
+ const auto format = tracePointFormat(static_cast<qint32>(attribute.config));
+ out << string(format.system) << ' ' << string(format.name) << ' ' << hex << format.flags << dec << '\n';
+ for (auto it = sample.tracePointData.begin(); it != sample.tracePointData.end(); ++it) {
+ out << "\t\t" << string(it.key()) << '=' << it.value().toString() << '\n';
+ }
+ } else {
+ out << cost << '\n';
+ }
+ }
+ out << '\n';
+ auto printFrame = [&out, this](qint32 locationId) -> qint32 {
+ const auto location = this->location(locationId);
+ out << '\t' << hex << location.address << dec;
+ const auto symbol = this->symbol(locationId);
+ if (location.file != -1)
+ out << '\t' << string(location.file) << ':' << location.line << ':' << location.column;
+ if (symbol.path != -1)
+ out << '\t' << string(symbol.name) << ' ' << string(symbol.binary) << ' ' << string(symbol.path) << ' ' << (symbol.isKernel ? "[kernel]" : "");
+ out << '\n';
+ return location.parentLocationId;
+ };
+ for (const auto &frame : sample.frames) {
+ auto locationId = printFrame(frame);
+ while (locationId != -1)
+ locationId = printFrame(locationId);
+ }
+ out << '\n';
+ }
+}
diff --git a/tests/auto/shared/perfparsertestclient.h b/tests/auto/shared/perfparsertestclient.h
index 8e6b7d5..468d7ae 100644
--- a/tests/auto/shared/perfparsertestclient.h
+++ b/tests/auto/shared/perfparsertestclient.h
@@ -25,6 +25,8 @@
#include <QVariant>
#include <QVector>
+class QTextStream;
+
class PerfParserTestClient : public QObject
{
Q_OBJECT
@@ -113,7 +115,9 @@ public:
LocationEvent location(qint32 id) const { return m_locations.value(id); }
SymbolEvent symbol(qint32 id) const { return m_symbols.value(id); }
- TracePointFormatEvent tracePointFormat(qint32 id) { return m_tracePointFormats.value(id); }
+ TracePointFormatEvent tracePointFormat(qint32 id) const { return m_tracePointFormats.value(id); }
+
+ void convertToText(QTextStream &output) const;
private:
QVector<QByteArray> m_strings;
diff --git a/tests/manual/perf2text/perf2text.cpp b/tests/manual/perf2text/perf2text.cpp
index e57082f..d77f518 100644
--- a/tests/manual/perf2text/perf2text.cpp
+++ b/tests/manual/perf2text/perf2text.cpp
@@ -39,7 +39,6 @@ int main(int argc, char **argv)
args.removeFirst();
QProcess process;
- PerfParserTestClient client;
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
QObject::connect(&process, &QProcess::errorOccurred, &app, [&process](QProcess::ProcessError error) {
qWarning() << "perfparser process error:" << error << process.errorString();
@@ -53,47 +52,11 @@ int main(int argc, char **argv)
if (!process.waitForStarted() || !process.waitForFinished())
return 1;
- client.extractTrace(&process);
-
QTextStream out(stdout);
- for (const auto &sample : client.samples()) {
- out << client.string(client.command(sample.pid).name) << '\t'
- << sample.pid << '\t' << sample.tid << '\t'
- << sample.time / 1000000000 << '.' << qSetFieldWidth(9) << qSetPadChar(QLatin1Char('0'))
- << sample.time % 1000000000 << qSetFieldWidth(0) << qSetPadChar(QLatin1Char(' ')) << '\n';
- for (const auto &value : sample.values) {
- const auto attribute = client.attribute(value.first);
- const auto cost = attribute.usesFrequency ? value.second : attribute.frequencyOrPeriod;
- out << '\t' << client.string(attribute.name) << ": ";
- if (attribute.type == 2) {
- const auto format = client.tracePointFormat(static_cast<qint32>(attribute.config));
- out << client.string(format.system) << ' ' << client.string(format.name) << ' ' << hex << format.flags << dec << '\n';
- for (auto it = sample.tracePointData.begin(); it != sample.tracePointData.end(); ++it) {
- out << "\t\t" << client.string(it.key()) << '=' << it.value().toString() << '\n';
- }
- } else {
- out << cost << '\n';
- }
- }
- out << '\n';
- auto printFrame = [&out, &client](qint32 locationId) -> qint32 {
- const auto location = client.location(locationId);
- out << '\t' << hex << location.address << dec;
- const auto symbol = client.symbol(locationId);
- if (location.file != -1)
- out << '\t' << client.string(location.file) << ':' << location.line << ':' << location.column;
- if (symbol.path != -1)
- out << '\t' << client.string(symbol.name) << ' ' << client.string(symbol.binary) << ' ' << client.string(symbol.path) << ' ' << (symbol.isKernel ? "[kernel]" : "");
- out << '\n';
- return location.parentLocationId;
- };
- for (const auto &frame : sample.frames) {
- auto locationId = printFrame(frame);
- while (locationId != -1)
- locationId = printFrame(locationId);
- }
- out << '\n';
- }
+
+ PerfParserTestClient client;
+ client.extractTrace(&process);
+ client.convertToText(out);
return 0;
}