Skip to content

Commit 3752c0a

Browse files
committed
glue diffing on perfparser
1 parent f952582 commit 3752c0a

File tree

9 files changed

+165
-72
lines changed

9 files changed

+165
-72
lines changed

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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ QString prettifySymbol(const QStringRef& str)
272272

273273
return result;
274274
}
275+
276+
void mergeBottomUpResults(const BottomUp& a, const BottomUp* b, BottomUp* result_node, const Costs& costs_a,
277+
const Costs& costs_b, Costs* costs_result)
278+
{
279+
for (const auto& node : a.children) {
280+
const auto sibling = b->entryForSymbol(node.symbol);
281+
if (sibling) {
282+
BottomUp merged;
283+
merged.id = node.id;
284+
merged.symbol = node.symbol;
285+
286+
for (int i = 0; i < costs_result->numTypes(); i += 2) {
287+
costs_result->add(i * 2, merged.id, costs_a.cost(i, node.id));
288+
costs_result->add(i * 2 + 1, merged.id, costs_b.cost(i, sibling->id));
289+
}
290+
291+
result_node->children.push_back(merged);
292+
mergeBottomUpResults(node, sibling, &result_node->children.back(), costs_a, costs_b, costs_result);
293+
}
294+
}
295+
}
275296
}
276297

277298
QString Data::prettifySymbol(const QString& name)
@@ -353,3 +374,28 @@ const Data::ThreadEvents* Data::EventResults::findThread(qint32 pid, qint32 tid)
353374
{
354375
return const_cast<Data::EventResults*>(this)->findThread(pid, tid);
355376
}
377+
378+
BottomUpResults BottomUpResults::mergeBottomUpResults(const BottomUpResults& a, const BottomUpResults& b)
379+
{
380+
if (a.costs.numTypes() != b.costs.numTypes()) {
381+
return {};
382+
}
383+
384+
BottomUpResults results;
385+
386+
for (int i = 0; i < a.costs.numTypes(); i++) {
387+
results.costs.addType(i * 2, a.costs.typeName(i) + QStringLiteral(" - file A"), a.costs.unit(i));
388+
results.costs.addTotalCost(i * 2, a.costs.totalCost(i));
389+
}
390+
391+
for (int i = 0; i < b.costs.numTypes(); i++) {
392+
results.costs.addType(i * 2 + 1, b.costs.typeName(i) + QStringLiteral(" - file B"), b.costs.unit(i));
393+
results.costs.addTotalCost(i * 2 + 1, b.costs.totalCost(i));
394+
}
395+
396+
::mergeBottomUpResults(a.root, &b.root, &results.root, a.costs, b.costs, &results.costs);
397+
398+
Data::BottomUp::initializeParents(&results.root);
399+
400+
return results;
401+
}

src/models/data.h

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

425+
static BottomUpResults mergeBottomUpResults(const Data::BottomUpResults& a, const Data::BottomUpResults& b);
426+
425427
private:
426428
quint32 maxBottomUpId = 0;
427429

src/parsers/perf/perfparser.cpp

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,13 +1319,22 @@ PerfParser::PerfParser(QObject* parent)
13191319
m_decompressed.reset();
13201320
};
13211321

1322+
auto diffResults = [this](const Data::BottomUpResults& first, const Data::BottomUpResults& second) {
1323+
m_bottomUpResults = Data::BottomUpResults::mergeBottomUpResults(first, second);
1324+
emit bottomUpDataAvailable(m_bottomUpResults);
1325+
emit topDownDataAvailable(Data::TopDownResults::fromBottomUp(m_bottomUpResults));
1326+
m_callerCalleeResults = {};
1327+
Data::callerCalleesFromBottomUpData(m_bottomUpResults, &m_callerCalleeResults);
1328+
emit callerCalleeDataAvailable(m_callerCalleeResults);
1329+
};
1330+
13221331
connect(this, &PerfParser::parsingFailed, this, parsingStopped);
13231332
connect(this, &PerfParser::parsingFinished, this, parsingStopped);
13241333
}
13251334

13261335
PerfParser::~PerfParser() = default;
13271336

1328-
void PerfParser::startParseFile(const QString& path)
1337+
void PerfParser::startParseFile(const QString& path, const QString& diffFile)
13291338
{
13301339
Q_ASSERT(!m_isParsing);
13311340

@@ -1351,6 +1360,7 @@ void PerfParser::startParseFile(const QString& path)
13511360

13521361
auto parserArgs = [this](const QString& filename) {
13531362
const auto settings = Settings::instance();
1363+
13541364
QStringList parserArgs = {QStringLiteral("--input"), decompressIfNeeded(filename),
13551365
QStringLiteral("--max-frames"), QStringLiteral("1024")};
13561366
const auto sysroot = settings->sysroot();
@@ -1398,12 +1408,12 @@ void PerfParser::startParseFile(const QString& path)
13981408

13991409
emit parsingStarted();
14001410
using namespace ThreadWeaver;
1401-
stream() << make_job([path, parserBinary, parserArgs, env, this]() {
1411+
stream() << make_job([path, diffFile, parserBinary, env, this]() {
14021412
PerfParserPrivate d;
14031413
connect(&d, &PerfParserPrivate::progress, this, &PerfParser::progress);
14041414
connect(this, &PerfParser::stopRequested, &d, &PerfParserPrivate::stop);
14051415

1406-
auto finalize = [&d, this]() {
1416+
auto finalize = [&d, diffFile, this]() {
14071417
d.finalize();
14081418
emit bottomUpDataAvailable(d.bottomUpResult);
14091419
emit topDownDataAvailable(d.topDownResult);
@@ -1443,55 +1453,55 @@ void PerfParser::startParseFile(const QString& path)
14431453

14441454
d.setInput(&process);
14451455

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

14961506
connect(&process, &QProcess::errorOccurred, &process, [&d, &process, this](QProcess::ProcessError error) {
14971507
if (m_stopRequested) {
@@ -1515,6 +1525,14 @@ void PerfParser::startParseFile(const QString& path)
15151525
&QEventLoop::quit);
15161526
loop.exec();
15171527
});
1528+
1529+
if (diffFile.isEmpty()) {
1530+
return;
1531+
}
1532+
1533+
PerfParser otherData;
1534+
1535+
otherData.startParseFile(diffFile);
15181536
}
15191537

15201538
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,9 +69,12 @@ 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 callerCalleeDataAvailable(const Data::CallerCalleeResults& data);
7476
void eventsAvailable(const Data::EventResults& events);
77+
void secondEventsAvailable(const Data::EventResults& events);
7578
void parsingFinished();
7679
void parsingFailed(const QString& errorMessage);
7780
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)