From a4ec0446751fccb397e99c52296b5cf3a11f27f2 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Thu, 8 Aug 2019 23:35:28 +0200 Subject: 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 --- tests/auto/shared/perfparsertestclient.cpp | 8 ++- tests/auto/shared/perfparsertestclient.h | 7 ++- tests/manual/manual.pro | 5 ++ tests/manual/manual.qbs | 7 +++ tests/manual/perf2text/perf2text.cpp | 99 ++++++++++++++++++++++++++++++ tests/manual/perf2text/perf2text.pro | 21 +++++++ tests/manual/perf2text/perf2text.qbs | 16 +++++ tests/tests.pro | 2 +- tests/tests.qbs | 2 +- 9 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 tests/manual/manual.pro create mode 100644 tests/manual/manual.qbs create mode 100644 tests/manual/perf2text/perf2text.cpp create mode 100644 tests/manual/perf2text/perf2text.pro create mode 100644 tests/manual/perf2text/perf2text.qbs 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 + +#ifdef MANUAL_TEST +#define QVERIFY Q_ASSERT +#define QCOMPARE(x, y) Q_ASSERT(x == y) +#else #include +#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 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 m_strings; QVector m_attributes; - QVector m_commands; + QHash m_commands; QVector m_threadEnds; QVector m_locations; - QVector m_symbols; + QHash m_symbols; QVector m_samples; QHash 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 +** 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 +#include +#include +#include +#include + +#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::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(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"] } -- cgit v1.2.3