Skip to content

Commit d0b37e5

Browse files
committed
glue diffing on perfparser
1 parent 0a3aabf commit d0b37e5

9 files changed

Lines changed: 187 additions & 71 deletions

File tree

src/mainwindow.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ MainWindow::MainWindow(QWidget* parent)
148148
connect(m_startPage, &StartPage::recordButtonClicked, this, &MainWindow::onRecordButtonClicked);
149149
connect(m_startPage, &StartPage::stopParseButtonClicked, this,
150150
static_cast<void (MainWindow::*)()>(&MainWindow::clear));
151+
connect(m_startPage, &StartPage::diffButtonClicked, this, [this] {
152+
const auto fileNameA = QFileDialog::getOpenFileName(this, tr("Open File A"), QDir::currentPath(),
153+
tr("Data Files (perf*.data perf.data.*);;All Files (*)"));
154+
if (fileNameA.isEmpty()) {
155+
return;
156+
}
157+
158+
const auto fileNameB = QFileDialog::getOpenFileName(this, tr("Open File B"), QDir::currentPath(),
159+
tr("Data Files (perf*.data perf.data.*);;All Files (*)"));
160+
if (fileNameB.isEmpty()) {
161+
return;
162+
}
163+
164+
openFile(fileNameA, false, fileNameB);
165+
});
151166
connect(m_parser, &PerfParser::progress, m_startPage, &StartPage::onParseFileProgress);
152167
connect(this, &MainWindow::openFileError, m_startPage, &StartPage::onOpenFileError);
153168
connect(m_recordPage, &RecordPage::homeButtonClicked, this, &MainWindow::onHomeButtonClicked);
@@ -363,7 +378,7 @@ void MainWindow::clear()
363378
clear(false);
364379
}
365380

366-
void MainWindow::openFile(const QString& path, bool isReload)
381+
void MainWindow::openFile(const QString& path, bool isReload, const QString& diffFile)
367382
{
368383
clear(isReload);
369384

@@ -374,7 +389,7 @@ void MainWindow::openFile(const QString& path, bool isReload)
374389
m_pageStack->setCurrentWidget(m_startPage);
375390

376391
// TODO: support input files of different types via plugins
377-
m_parser->startParseFile(path);
392+
m_parser->startParseFile(path, diffFile);
378393
m_reloadAction->setData(path);
379394
m_exportAction->setData(QUrl::fromLocalFile(file.absoluteFilePath() + QLatin1String(".perfparser")));
380395

src/mainwindow.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public slots:
7878

7979
private:
8080
void clear(bool isReload);
81-
void openFile(const QString& path, bool isReload);
81+
void openFile(const QString& path, bool isReload, const QString& diffFile = QStringLiteral(""));
8282
void closeEvent(QCloseEvent* event) override;
8383
void setupCodeNavigationMenu();
8484

src/models/data.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,26 @@ void buildPerLibrary(const TopDown* node, PerLibraryResults& results, QHash<QStr
295295
buildPerLibrary(&child, results, binaryToResultIndex, costs);
296296
}
297297
}
298+
299+
void diffBottomUpResults(const BottomUp& a, const BottomUp* b, BottomUp* result_node, const Costs& costs_a,
300+
const Costs& costs_b, Costs* costs_result)
301+
{
302+
for (const auto& node : a.children) {
303+
const auto sibling = b->entryForSymbol(node.symbol);
304+
if (sibling) {
305+
BottomUp diffed;
306+
diffed.id = node.id;
307+
diffed.symbol = node.symbol;
308+
309+
for (int i = 0; i < costs_result->numTypes(); i += 2) {
310+
costs_result->add(i, diffed.id, costs_a.cost(i, node.id) - costs_b.cost(i, sibling->id));
311+
}
312+
313+
result_node->children.push_back(diffed);
314+
diffBottomUpResults(node, sibling, &result_node->children.back(), costs_a, costs_b, costs_result);
315+
}
316+
}
317+
}
298318
}
299319

300320
QString Data::prettifySymbol(const QString& name)
@@ -389,3 +409,23 @@ const Data::ThreadEvents* Data::EventResults::findThread(qint32 pid, qint32 tid)
389409
{
390410
return const_cast<Data::EventResults*>(this)->findThread(pid, tid);
391411
}
412+
413+
BottomUpResults BottomUpResults::diffBottomUpResults(const BottomUpResults& a, const BottomUpResults& b)
414+
{
415+
if (a.costs.numTypes() != b.costs.numTypes()) {
416+
return {};
417+
}
418+
419+
BottomUpResults results;
420+
421+
for (int i = 0; i < a.costs.numTypes(); i++) {
422+
results.costs.addType(i, a.costs.typeName(i), a.costs.unit(i));
423+
results.costs.addTotalCost(i , a.costs.totalCost(i) - b.costs.totalCost(i));
424+
}
425+
426+
::diffBottomUpResults(a.root, &b.root, &results.root, a.costs, b.costs, &results.costs);
427+
428+
Data::BottomUp::initializeParents(&results.root);
429+
430+
return results;
431+
}

src/models/data.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ struct BottomUpResults
423423
return parent;
424424
}
425425

426+
static BottomUpResults diffBottomUpResults(const Data::BottomUpResults& a, const Data::BottomUpResults& b);
427+
426428
private:
427429
quint32 maxBottomUpId = 0;
428430

src/parsers/perf/perfparser.cpp

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ PerfParser::PerfParser(QObject* parent)
13321332

13331333
PerfParser::~PerfParser() = default;
13341334

1335-
void PerfParser::startParseFile(const QString& path)
1335+
void PerfParser::startParseFile(const QString& path, const QString& diffFile)
13361336
{
13371337
Q_ASSERT(!m_isParsing);
13381338

@@ -1358,6 +1358,7 @@ void PerfParser::startParseFile(const QString& path)
13581358

13591359
auto parserArgs = [this](const QString& filename) {
13601360
const auto settings = Settings::instance();
1361+
13611362
QStringList parserArgs = {QStringLiteral("--input"), decompressIfNeeded(filename),
13621363
QStringLiteral("--max-frames"), QStringLiteral("1024")};
13631364
const auto sysroot = settings->sysroot();
@@ -1405,7 +1406,7 @@ void PerfParser::startParseFile(const QString& path)
14051406

14061407
emit parsingStarted();
14071408
using namespace ThreadWeaver;
1408-
stream() << make_job([path, parserBinary, parserArgs, env, this]() {
1409+
stream() << make_job([path, parserBinary, env, this]() {
14091410
PerfParserPrivate d;
14101411
connect(&d, &PerfParserPrivate::progress, this, &PerfParser::progress);
14111412
connect(this, &PerfParser::stopRequested, &d, &PerfParserPrivate::stop);
@@ -1451,55 +1452,55 @@ void PerfParser::startParseFile(const QString& path)
14511452

14521453
d.setInput(&process);
14531454

1455+
const auto exitCodeHandler = [finalize, this](int exitCode, QProcess::ExitStatus exitStatus) {
1456+
if (m_stopRequested) {
1457+
emit parsingFailed(tr("Parsing stopped."));
1458+
return;
1459+
}
1460+
qCDebug(LOG_PERFPARSER) << exitCode << exitStatus;
1461+
1462+
enum ErrorCodes
1463+
{
1464+
NoError,
1465+
TcpSocketError,
1466+
CannotOpen,
1467+
BadMagic,
1468+
HeaderError,
1469+
DataError,
1470+
MissingData,
1471+
InvalidOption
1472+
};
1473+
switch (exitCode) {
1474+
case NoError:
1475+
finalize();
1476+
break;
1477+
case TcpSocketError:
1478+
emit parsingFailed(
1479+
tr("The hotspot-perfparser binary exited with code %1 (TCP socket error).").arg(exitCode));
1480+
break;
1481+
case CannotOpen:
1482+
emit parsingFailed(
1483+
tr("The hotspot-perfparser binary exited with code %1 (file could not be opened).").arg(exitCode));
1484+
break;
1485+
case BadMagic:
1486+
case HeaderError:
1487+
case DataError:
1488+
case MissingData:
1489+
emit parsingFailed(
1490+
tr("The hotspot-perfparser binary exited with code %1 (invalid perf data file).").arg(exitCode));
1491+
break;
1492+
case InvalidOption:
1493+
emit parsingFailed(
1494+
tr("The hotspot-perfparser binary exited with code %1 (invalid option).").arg(exitCode));
1495+
break;
1496+
default:
1497+
emit parsingFailed(tr("The hotspot-perfparser binary exited with code %1.").arg(exitCode));
1498+
break;
1499+
}
1500+
};
1501+
14541502
connect(&process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), &process,
1455-
[finalize, this](int exitCode, QProcess::ExitStatus exitStatus) {
1456-
if (m_stopRequested) {
1457-
emit parsingFailed(tr("Parsing stopped."));
1458-
return;
1459-
}
1460-
qCDebug(LOG_PERFPARSER) << exitCode << exitStatus;
1461-
1462-
enum ErrorCodes
1463-
{
1464-
NoError,
1465-
TcpSocketError,
1466-
CannotOpen,
1467-
BadMagic,
1468-
HeaderError,
1469-
DataError,
1470-
MissingData,
1471-
InvalidOption
1472-
};
1473-
switch (exitCode) {
1474-
case NoError:
1475-
finalize();
1476-
break;
1477-
case TcpSocketError:
1478-
emit parsingFailed(
1479-
tr("The hotspot-perfparser binary exited with code %1 (TCP socket error).").arg(exitCode));
1480-
break;
1481-
case CannotOpen:
1482-
emit parsingFailed(
1483-
tr("The hotspot-perfparser binary exited with code %1 (file could not be opened).")
1484-
.arg(exitCode));
1485-
break;
1486-
case BadMagic:
1487-
case HeaderError:
1488-
case DataError:
1489-
case MissingData:
1490-
emit parsingFailed(
1491-
tr("The hotspot-perfparser binary exited with code %1 (invalid perf data file).")
1492-
.arg(exitCode));
1493-
break;
1494-
case InvalidOption:
1495-
emit parsingFailed(
1496-
tr("The hotspot-perfparser binary exited with code %1 (invalid option).").arg(exitCode));
1497-
break;
1498-
default:
1499-
emit parsingFailed(tr("The hotspot-perfparser binary exited with code %1.").arg(exitCode));
1500-
break;
1501-
}
1502-
});
1503+
exitCodeHandler);
15031504

15041505
connect(&process, &QProcess::errorOccurred, &process, [&d, &process, this](QProcess::ProcessError error) {
15051506
if (m_stopRequested) {
@@ -1523,6 +1524,52 @@ void PerfParser::startParseFile(const QString& path)
15231524
&QEventLoop::quit);
15241525
loop.exec();
15251526
});
1527+
1528+
if (diffFile.isEmpty()) {
1529+
return;
1530+
}
1531+
1532+
PerfParser otherData;
1533+
1534+
otherData.startParseFile(diffFile);
1535+
QEventLoop loop;
1536+
connect(&otherData, &PerfParser::parsingFinished, &loop, &QEventLoop::quit);
1537+
connect(&otherData, &PerfParser::parsingFailed, &loop, &QEventLoop::quit);
1538+
connect(&otherData, &PerfParser::parsingFailed, this, [this](const QString& error) { emit parsingFailed(error); });
1539+
1540+
connect(&otherData, &PerfParser::bottomUpDataAvailable, &otherData,
1541+
[this, &otherData](const Data::BottomUpResults& otherResults) {
1542+
if (m_bottomUpResults.root.children.size() > 0) {
1543+
this->m_callerCalleeResults = {};
1544+
1545+
const auto diffResults =
1546+
Data::BottomUpResults::mergeBottomUpResults(m_bottomUpResults, otherResults);
1547+
m_bottomUpResults = diffResults;
1548+
const auto topDown = Data::TopDownResults::fromBottomUp(diffResults);
1549+
Data::CallerCalleeResults callerCalleeResults;
1550+
Data::callerCalleesFromBottomUpData(diffResults, &callerCalleeResults);
1551+
emit bottomUpDataAvailable(diffResults);
1552+
emit topDownDataAvailable(Data::TopDownResults::fromBottomUp(diffResults));
1553+
emit callerCalleeDataAvailable(callerCalleeResults);
1554+
} else {
1555+
connect(this, &PerfParser::bottomUpDataAvailable, &otherData,
1556+
[this, &otherData, otherResults](const Data::BottomUpResults& results) {
1557+
this->m_bottomUpResults = {};
1558+
this->m_callerCalleeResults = {};
1559+
1560+
const auto diffResults =
1561+
Data::BottomUpResults::mergeBottomUpResults(results, otherResults);
1562+
const auto topDown = Data::TopDownResults::fromBottomUp(diffResults);
1563+
Data::CallerCalleeResults callerCalleeResults;
1564+
Data::callerCalleesFromBottomUpData(diffResults, &callerCalleeResults);
1565+
emit bottomUpDataAvailable(diffResults);
1566+
emit topDownDataAvailable(Data::TopDownResults::fromBottomUp(diffResults));
1567+
emit callerCalleeDataAvailable(callerCalleeResults);
1568+
});
1569+
}
1570+
});
1571+
1572+
loop.exec();
15261573
}
15271574

15281575
void PerfParser::filterResults(const Data::FilterAction& filter)

src/parsers/perf/perfparser.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class PerfParser : public QObject
4444
explicit PerfParser(QObject* parent = nullptr);
4545
~PerfParser();
4646

47-
void startParseFile(const QString& path);
47+
void startParseFile(const QString& path, const QString& diffFile = QStringLiteral(""));
4848

4949
void filterResults(const Data::FilterAction& filter);
5050

@@ -69,10 +69,13 @@ class PerfParser : public QObject
6969
void parsingStarted();
7070
void summaryDataAvailable(const Data::Summary& data);
7171
void bottomUpDataAvailable(const Data::BottomUpResults& data);
72+
void firstBottomUpDataAvailable(const Data::BottomUpResults& data);
73+
void secondBottomUpDataAvailable(const Data::BottomUpResults& data);
7274
void topDownDataAvailable(const Data::TopDownResults& data);
7375
void perLibraryDataAvailable(const Data::PerLibraryResults& data);
7476
void callerCalleeDataAvailable(const Data::CallerCalleeResults& data);
7577
void eventsAvailable(const Data::EventResults& events);
78+
void secondEventsAvailable(const Data::EventResults& events);
7679
void parsingFinished();
7780
void parsingFailed(const QString& errorMessage);
7881
void progress(float progress);

src/startpage.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ StartPage::StartPage(QWidget* parent)
4242
connect(ui->recordDataButton, &QAbstractButton::clicked, this, &StartPage::recordButtonClicked);
4343
connect(ui->stopParseButton, &QAbstractButton::clicked, this, &StartPage::stopParseButtonClicked);
4444
connect(ui->pathSettings, &QAbstractButton::clicked, this, &StartPage::pathSettingsButtonClicked);
45+
connect(ui->diffButton, &QAbstractButton::clicked, this, &StartPage::diffButtonClicked);
4546
ui->openFileButton->setFocus();
4647

4748
updateBackground();

src/startpage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public slots:
5858
void recordButtonClicked();
5959
void stopParseButtonClicked();
6060
void pathSettingsButtonClicked();
61+
void diffButtonClicked();
6162

6263
private:
6364
void updateBackground();

0 commit comments

Comments
 (0)