Skip to content

Commit adf95bc

Browse files
committed
Add perf profiler run mode
Change-Id: If2f84bec32957ab9c45df503efaf592cebbd4f72 Reviewed-by: Joerg Bornemann <[email protected]>
1 parent ddbf08f commit adf95bc

File tree

6 files changed

+162
-15
lines changed

6 files changed

+162
-15
lines changed

appcontroller.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ QT+=network
33
HEADERS=\
44
process.h \
55
portlist.h \
6+
perfprocesshandler.h
67

78
SOURCES=\
89
main.cpp \
910
process.cpp \
1011
portlist.cpp \
12+
perfprocesshandler.cpp
1113

1214
android {
1315
target.path = $$[INSTALL_ROOT]/system/bin

main.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "process.h"
2020
#include "portlist.h"
21+
#include "perfprocesshandler.h"
2122
#include <QCoreApplication>
2223
#include <QTcpServer>
2324
#include <QProcess>
@@ -144,17 +145,21 @@ static void stop()
144145
connectSocket();
145146
}
146147

147-
static int findFirstFreePort(Utils::PortList &range)
148+
static int openServer(QTcpServer *s, Utils::PortList &range)
148149
{
149-
QTcpServer s;
150-
151150
while (range.hasMore()) {
152-
if (s.listen(QHostAddress::Any, range.getNext()))
153-
return s.serverPort();
151+
if (s->listen(QHostAddress::Any, range.getNext()))
152+
return s->serverPort();
154153
}
155154
return -1;
156155
}
157156

157+
static int findFirstFreePort(Utils::PortList &range)
158+
{
159+
QTcpServer s;
160+
return openServer(&s, range);
161+
}
162+
158163
static Config parseConfigFile()
159164
{
160165
Config config;
@@ -244,6 +249,7 @@ int main(int argc, char **argv)
244249
quint16 gdbDebugPort = 0;
245250
bool useGDB = false;
246251
bool useQML = false;
252+
QStringList perfParams;
247253
bool fireAndForget = false;
248254
bool detach = false;
249255
Utils::PortList range;
@@ -274,6 +280,14 @@ int main(int argc, char **argv)
274280
setsid();
275281
} else if (arg == "--debug-qml") {
276282
useQML = true;
283+
} else if (arg == "--profile-perf") {
284+
if (args.isEmpty() ||
285+
(perfParams = args.takeFirst().split(QLatin1Char(','))).length() != 3) {
286+
fprintf(stderr, "--profile-perf requires a parameter specification of"
287+
" \"<method>,<size>,<freq>\" where <method> can be \"fp\" or "
288+
" \"dwarf\", amd <size> and <freq> are integers.");
289+
return 1;
290+
}
277291
} else if (arg == "--stop") {
278292
stop();
279293
return 0;
@@ -403,7 +417,28 @@ int main(int argc, char **argv)
403417
if (gdbDebugPort)
404418
process.setDebug();
405419
process.setSocketNotifier(new QSocketNotifier(serverSocket, QSocketNotifier::Read, &process));
406-
process.start(defaultArgs);
420+
421+
if (perfParams.length() == 3) {
422+
QStringList allArgs;
423+
allArgs << QLatin1String("perf") << QLatin1String("record") << QLatin1String("--call-graph");
424+
if (perfParams[0] == QLatin1String("dwarf"))
425+
allArgs << QString(QLatin1String("dwarf,%1")).arg(perfParams[1]);
426+
else
427+
allArgs << perfParams[0];
428+
allArgs << QLatin1String("-F") << perfParams[2] << QLatin1String("-o") << QLatin1String("-")
429+
<< QLatin1String("--") << defaultArgs.join(QLatin1Char(' '));
430+
431+
PerfProcessHandler *server = new PerfProcessHandler(&process, allArgs);
432+
int port = openServer(server->server(), range);
433+
if (port < 0) {
434+
fprintf(stderr, "Could not find an unused port in range\n");
435+
return 1;
436+
}
437+
printf("AppController: Going to wait for perf connection on port %d...\n", port);
438+
} else {
439+
process.start(defaultArgs);
440+
}
441+
407442
app.exec();
408443
if (!fireAndForget)
409444
close(serverSocket);

perfprocesshandler.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/****************************************************************************
2+
**
3+
** Copyright (C) 2015 The Qt Company Ltd
4+
** All rights reserved.
5+
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
6+
**
7+
** This file is part of QtEnterprise Embedded.
8+
**
9+
** Licensees holding valid Qt Enterprise licenses may use this file in
10+
** accordance with the Qt Enterprise License Agreement provided with the
11+
** Software or, alternatively, in accordance with the terms contained in
12+
** a written agreement between you and The Qt Company.
13+
**
14+
** If you have questions regarding the use of this file, please use
15+
** contact form at http://www.qt.io/contact-us
16+
**
17+
****************************************************************************/
18+
19+
#include "perfprocesshandler.h"
20+
#include <QTcpSocket>
21+
22+
PerfProcessHandler::PerfProcessHandler(Process *process, const QStringList &allArgs) : mProcess(process), mAllArgs(allArgs)
23+
{
24+
QObject::connect(&mServer, &QTcpServer::newConnection, this, &PerfProcessHandler::acceptConnection);
25+
}
26+
27+
QTcpServer *PerfProcessHandler::server()
28+
{
29+
return &mServer;
30+
}
31+
32+
void PerfProcessHandler::acceptConnection()
33+
{
34+
QTcpSocket *socket = mServer.nextPendingConnection();
35+
socket->setParent(mProcess);
36+
mProcess->setStdoutFd(socket->socketDescriptor());
37+
mProcess->start(mAllArgs);
38+
this->deleteLater();
39+
}

perfprocesshandler.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/****************************************************************************
2+
**
3+
** Copyright (C) 2015 The Qt Company Ltd
4+
** All rights reserved.
5+
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
6+
**
7+
** This file is part of QtEnterprise Embedded.
8+
**
9+
** Licensees holding valid Qt Enterprise licenses may use this file in
10+
** accordance with the Qt Enterprise License Agreement provided with the
11+
** Software or, alternatively, in accordance with the terms contained in
12+
** a written agreement between you and The Qt Company.
13+
**
14+
** If you have questions regarding the use of this file, please use
15+
** contact form at http://www.qt.io/contact-us
16+
**
17+
****************************************************************************/
18+
19+
#ifndef PERFPROCESSHANDLER_H
20+
#define PERFPROCESSHANDLER_H
21+
22+
#include "process.h"
23+
#include <QTcpServer>
24+
25+
// Starts the process once a connection to the TCP server is established and then deletes itself.
26+
class PerfProcessHandler : public QObject {
27+
Q_OBJECT
28+
29+
private:
30+
QTcpServer mServer;
31+
Process *mProcess;
32+
QStringList mAllArgs;
33+
34+
public:
35+
PerfProcessHandler(Process *process, const QStringList &allArgs);
36+
QTcpServer *server();
37+
38+
public slots:
39+
void acceptConnection();
40+
};
41+
42+
#endif // PERFPROCESSHANDLER_H

process.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include <signal.h>
2727
#include <fcntl.h>
2828
#include <QFileInfo>
29+
#include <QTcpSocket>
30+
#include <errno.h>
2931

3032
static int pipefd[2];
3133

@@ -86,6 +88,7 @@ Process::Process()
8688
, mProcess(new QProcess(this))
8789
, mDebuggee(0)
8890
, mDebug(false)
91+
, mStdoutFd(1)
8992
{
9093
mProcess->setProcessChannelMode(QProcess::SeparateChannels);
9194
connect(mProcess, &QProcess::readyReadStandardError, this, &Process::readyReadStandardError);
@@ -112,13 +115,29 @@ Process::~Process()
112115
close(pipefd[1]);
113116
}
114117

115-
void Process::readyReadStandardOutput()
118+
void Process::forwardProcessOutput(qintptr fd, const QByteArray &data)
116119
{
117-
QByteArray b = mProcess->readAllStandardOutput();
118-
write(1, b.constData(), b.size());
120+
const char *constData = data.constData();
121+
int size = data.size();
122+
while (size > 0) {
123+
int written = write(fd, constData, size);
124+
if (written == -1) {
125+
fprintf(stderr, "Cannot forward application output: %d - %s\n", errno, strerror(errno));
126+
qApp->quit();
127+
break;
128+
}
129+
size -= written;
130+
constData += written;
131+
}
119132

120133
if (mConfig.flags.testFlag(Config::PrintDebugMessages))
121-
qDebug() << b;
134+
qDebug() << data;
135+
}
136+
137+
138+
void Process::readyReadStandardOutput()
139+
{
140+
forwardProcessOutput(mStdoutFd, mProcess->readAllStandardOutput());
122141
}
123142

124143
void Process::readyReadStandardError()
@@ -131,10 +150,7 @@ void Process::readyReadStandardError()
131150
}
132151
mDebug = false; // only search once
133152
}
134-
write(2, b.constData(), b.size());
135-
136-
if (mConfig.flags.testFlag(Config::PrintDebugMessages))
137-
qDebug() << b;
153+
forwardProcessOutput(2, b);
138154
}
139155

140156
void Process::setDebug()
@@ -246,6 +262,11 @@ void Process::setConfig(const Config &config)
246262
mConfig = config;
247263
}
248264

265+
void Process::setStdoutFd(qintptr stdoutFd)
266+
{
267+
mStdoutFd = stdoutFd;
268+
}
269+
249270
QProcessEnvironment Process::interactiveProcessEnvironment() const
250271
{
251272
QProcessEnvironment env;
@@ -311,4 +332,3 @@ QProcessEnvironment Process::interactiveProcessEnvironment() const
311332

312333
return env;
313334
}
314-

process.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
**
1717
****************************************************************************/
1818

19+
#ifndef PROCESS_H
20+
#define PROCESS_H
21+
1922
#include <QObject>
2023
#include <QProcess>
2124
#include <QMap>
25+
#include <QTcpServer>
2226

2327
class QSocketNotifier;
2428

@@ -53,6 +57,7 @@ class Process : public QObject
5357
void setSocketNotifier(QSocketNotifier*);
5458
void setDebug();
5559
void setConfig(const Config &);
60+
void setStdoutFd(qintptr stdoutFd);
5661
public slots:
5762
void stop();
5863
private slots:
@@ -62,11 +67,15 @@ private slots:
6267
void error(QProcess::ProcessError);
6368
void incomingConnection(int);
6469
private:
70+
void forwardProcessOutput(qintptr fd, const QByteArray &data);
6571
void startup(QStringList);
6672
QProcessEnvironment interactiveProcessEnvironment() const;
6773
QProcess *mProcess;
6874
int mDebuggee;
6975
bool mDebug;
7076
Config mConfig;
7177
QString mBinary;
78+
qintptr mStdoutFd;
7279
};
80+
81+
#endif // PROCESS_H

0 commit comments

Comments
 (0)