summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2019-08-08 23:35:28 +0200
committerMilian Wolff <milian.wolff@kdab.com>2019-08-13 13:46:41 +0000
commita4ec0446751fccb397e99c52296b5cf3a11f27f2 (patch)
treec30e5407b0ec309b36e4dc28717b828d3d9eaf74
parent4fcd8e4fd3968b320932137aa0da2d07b6450851 (diff)
Add manual perf2text test helper
This executable will be used to convert perf.data files to a textual format, similar to perf script. We can then use this for testing purposes, either manually for now or automatically in the future. Change-Id: Ia2b5ebdba26c9c11e16c08fa41f7a8fdf43268cb Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--tests/auto/shared/perfparsertestclient.cpp8
-rw-r--r--tests/auto/shared/perfparsertestclient.h7
-rw-r--r--tests/manual/manual.pro5
-rw-r--r--tests/manual/manual.qbs7
-rw-r--r--tests/manual/perf2text/perf2text.cpp99
-rw-r--r--tests/manual/perf2text/perf2text.pro21
-rw-r--r--tests/manual/perf2text/perf2text.qbs16
-rw-r--r--tests/tests.pro2
-rw-r--r--tests/tests.qbs2
9 files changed, 162 insertions, 5 deletions
diff --git a/tests/auto/shared/perfparsertestclient.cpp b/tests/auto/shared/perfparsertestclient.cpp
index 55feb2d..ac45c28 100644
--- a/tests/auto/shared/perfparsertestclient.cpp
+++ b/tests/auto/shared/perfparsertestclient.cpp
@@ -21,7 +21,13 @@
#include "perfparsertestclient.h"
#include <QtEndian>
+
+#ifdef MANUAL_TEST
+#define QVERIFY Q_ASSERT
+#define QCOMPARE(x, y) Q_ASSERT(x == y)
+#else
#include <QtTest>
+#endif
PerfParserTestClient::PerfParserTestClient(QObject *parent) : QObject(parent)
{
@@ -82,7 +88,7 @@ void PerfParserTestClient::extractTrace(QIODevice *device)
CommandEvent command;
stream >> command.pid >> command.tid >> command.time >> command.cpu >> command.name;
checkString(command.name);
- m_commands.append(command);
+ m_commands.insert(command.tid, command);
break;
}
case LocationDefinition: {
diff --git a/tests/auto/shared/perfparsertestclient.h b/tests/auto/shared/perfparsertestclient.h
index 821cee8..8e6b7d5 100644
--- a/tests/auto/shared/perfparsertestclient.h
+++ b/tests/auto/shared/perfparsertestclient.h
@@ -107,18 +107,21 @@ public:
void extractTrace(QIODevice *output);
QByteArray string(qint32 id) const { return m_strings.value(id); }
+ CommandEvent command(qint32 tid) const { return m_commands[tid]; }
AttributeEvent attribute(qint32 id) const { return m_attributes.value(id); }
QVector<SampleEvent> samples() const { return m_samples; }
+ 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); }
private:
QVector<QByteArray> m_strings;
QVector<AttributeEvent> m_attributes;
- QVector<CommandEvent> m_commands;
+ QHash<qint32, CommandEvent> m_commands;
QVector<ThreadEndEvent> m_threadEnds;
QVector<LocationEvent> m_locations;
- QVector<SymbolEvent> m_symbols;
+ QHash<qint32, SymbolEvent> m_symbols;
QVector<SampleEvent> m_samples;
QHash<qint32, TracePointFormatEvent> m_tracePointFormats;
};
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
new file mode 100644
index 0000000..764c84c
--- /dev/null
+++ b/tests/manual/manual.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+SUBDIRS = perf2text
+
+OTHER_FILES += manual.qbs
+
diff --git a/tests/manual/manual.qbs b/tests/manual/manual.qbs
new file mode 100644
index 0000000..8b83f87
--- /dev/null
+++ b/tests/manual/manual.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+Project {
+ name: "Manual Tests"
+ references: ["perf2text"]
+}
+
diff --git a/tests/manual/perf2text/perf2text.cpp b/tests/manual/perf2text/perf2text.cpp
new file mode 100644
index 0000000..e57082f
--- /dev/null
+++ b/tests/manual/perf2text/perf2text.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Enterprise Perf Profiler Add-on.
+**
+** GNU General Public License Usage
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in
+** the file LICENSE.GPLv3 included in the packaging of this file. Please
+** review the following information to ensure the GNU General Public License
+** requirements will be met: https://www.gnu.org/licenses/gpl.html.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#include <QProcess>
+#include <QCoreApplication>
+#include <QStandardPaths>
+#include <QTextStream>
+#include <QDebug>
+
+#include "perfparsertestclient.h"
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ const auto perfparser = QStandardPaths::findExecutable(QStringLiteral("perfparser"), {app.applicationDirPath()});
+ if (perfparser.isEmpty()) {
+ qWarning() << "failed to find perfparser executable";
+ return 1;
+ }
+
+ auto args = app.arguments();
+ 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();
+ });
+ QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ &app, [&process](int exitCode, QProcess::ExitStatus status) {
+ if (exitCode != 0 || status != QProcess::NormalExit)
+ qWarning() << "perfparser process finished abnormally:" << exitCode << status << process.errorString();
+ });
+ process.start(perfparser, args);
+ 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';
+ }
+
+ return 0;
+}
diff --git a/tests/manual/perf2text/perf2text.pro b/tests/manual/perf2text/perf2text.pro
new file mode 100644
index 0000000..88acc5d
--- /dev/null
+++ b/tests/manual/perf2text/perf2text.pro
@@ -0,0 +1,21 @@
+QT = core
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+CONFIG += strict_flags warn_on
+
+INCLUDEPATH += ../../../app
+
+include(../../../paths.pri)
+include(../../auto/shared/shared.pri)
+
+DEFINES += MANUAL_TEST
+DESTDIR = $$PERFPARSER_APP_DESTDIR
+target.path = $$PERFPARSER_APP_INSTALLDIR
+INSTALLS += target
+
+TARGET = perf2text
+
+SOURCES += perf2text.cpp
+
+OTHER_FILES += perf2text.qbs
diff --git a/tests/manual/perf2text/perf2text.qbs b/tests/manual/perf2text/perf2text.qbs
new file mode 100644
index 0000000..5a697f1
--- /dev/null
+++ b/tests/manual/perf2text/perf2text.qbs
@@ -0,0 +1,16 @@
+import qbs
+
+QtcTool {
+ name: "perf2text"
+
+ Depends { name: "perfparser" }
+
+ cpp.defines: ["MANUAL_TEST"]
+ cpp.includePaths: ["../../../app", "../../auto/shared"]
+
+ files: [
+ "perf2text.cpp",
+ "../shared/perfparsertestclient.cpp",
+ "../shared/perfparsertestclient.h",
+ ]
+}
diff --git a/tests/tests.pro b/tests/tests.pro
index 3ed55d8..f3b0483 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1,4 +1,4 @@
TEMPLATE = subdirs
-SUBDIRS = auto
+SUBDIRS = auto manual
OTHER_FILES += tests.qbs
diff --git a/tests/tests.qbs b/tests/tests.qbs
index 365a337..d3f801d 100644
--- a/tests/tests.qbs
+++ b/tests/tests.qbs
@@ -2,5 +2,5 @@ import qbs
Project {
name: "Tests"
- references: ["auto"]
+ references: ["auto", "manual"]
}