summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-01-29 19:02:16 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-03-02 11:48:36 +0200
commitadf95bca87410244fde97fc732dcc346e25e0dca (patch)
tree938d8ac9c83582860c990d6179afb67c0aedbbec
parentddbf08f7403e4faca5acc9e99e873ebbc8e4bf52 (diff)
Add perf profiler run mode
Change-Id: If2f84bec32957ab9c45df503efaf592cebbd4f72 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
-rw-r--r--appcontroller.pro2
-rw-r--r--main.cpp47
-rw-r--r--perfprocesshandler.cpp39
-rw-r--r--perfprocesshandler.h42
-rw-r--r--process.cpp38
-rw-r--r--process.h9
6 files changed, 162 insertions, 15 deletions
diff --git a/appcontroller.pro b/appcontroller.pro
index b467652..97b208e 100644
--- a/appcontroller.pro
+++ b/appcontroller.pro
@@ -3,11 +3,13 @@ QT+=network
HEADERS=\
process.h \
portlist.h \
+ perfprocesshandler.h
SOURCES=\
main.cpp \
process.cpp \
portlist.cpp \
+ perfprocesshandler.cpp
android {
target.path = $$[INSTALL_ROOT]/system/bin
diff --git a/main.cpp b/main.cpp
index 9eef26e..741523c 100644
--- a/main.cpp
+++ b/main.cpp
@@ -18,6 +18,7 @@
#include "process.h"
#include "portlist.h"
+#include "perfprocesshandler.h"
#include <QCoreApplication>
#include <QTcpServer>
#include <QProcess>
@@ -144,17 +145,21 @@ static void stop()
connectSocket();
}
-static int findFirstFreePort(Utils::PortList &range)
+static int openServer(QTcpServer *s, Utils::PortList &range)
{
- QTcpServer s;
-
while (range.hasMore()) {
- if (s.listen(QHostAddress::Any, range.getNext()))
- return s.serverPort();
+ if (s->listen(QHostAddress::Any, range.getNext()))
+ return s->serverPort();
}
return -1;
}
+static int findFirstFreePort(Utils::PortList &range)
+{
+ QTcpServer s;
+ return openServer(&s, range);
+}
+
static Config parseConfigFile()
{
Config config;
@@ -244,6 +249,7 @@ int main(int argc, char **argv)
quint16 gdbDebugPort = 0;
bool useGDB = false;
bool useQML = false;
+ QStringList perfParams;
bool fireAndForget = false;
bool detach = false;
Utils::PortList range;
@@ -274,6 +280,14 @@ int main(int argc, char **argv)
setsid();
} else if (arg == "--debug-qml") {
useQML = true;
+ } else if (arg == "--profile-perf") {
+ if (args.isEmpty() ||
+ (perfParams = args.takeFirst().split(QLatin1Char(','))).length() != 3) {
+ fprintf(stderr, "--profile-perf requires a parameter specification of"
+ " \"<method>,<size>,<freq>\" where <method> can be \"fp\" or "
+ " \"dwarf\", amd <size> and <freq> are integers.");
+ return 1;
+ }
} else if (arg == "--stop") {
stop();
return 0;
@@ -403,7 +417,28 @@ int main(int argc, char **argv)
if (gdbDebugPort)
process.setDebug();
process.setSocketNotifier(new QSocketNotifier(serverSocket, QSocketNotifier::Read, &process));
- process.start(defaultArgs);
+
+ if (perfParams.length() == 3) {
+ QStringList allArgs;
+ allArgs << QLatin1String("perf") << QLatin1String("record") << QLatin1String("--call-graph");
+ if (perfParams[0] == QLatin1String("dwarf"))
+ allArgs << QString(QLatin1String("dwarf,%1")).arg(perfParams[1]);
+ else
+ allArgs << perfParams[0];
+ allArgs << QLatin1String("-F") << perfParams[2] << QLatin1String("-o") << QLatin1String("-")
+ << QLatin1String("--") << defaultArgs.join(QLatin1Char(' '));
+
+ PerfProcessHandler *server = new PerfProcessHandler(&process, allArgs);
+ int port = openServer(server->server(), range);
+ if (port < 0) {
+ fprintf(stderr, "Could not find an unused port in range\n");
+ return 1;
+ }
+ printf("AppController: Going to wait for perf connection on port %d...\n", port);
+ } else {
+ process.start(defaultArgs);
+ }
+
app.exec();
if (!fireAndForget)
close(serverSocket);
diff --git a/perfprocesshandler.cpp b/perfprocesshandler.cpp
new file mode 100644
index 0000000..9b609ab
--- /dev/null
+++ b/perfprocesshandler.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of QtEnterprise Embedded.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#include "perfprocesshandler.h"
+#include <QTcpSocket>
+
+PerfProcessHandler::PerfProcessHandler(Process *process, const QStringList &allArgs) : mProcess(process), mAllArgs(allArgs)
+{
+ QObject::connect(&mServer, &QTcpServer::newConnection, this, &PerfProcessHandler::acceptConnection);
+}
+
+QTcpServer *PerfProcessHandler::server()
+{
+ return &mServer;
+}
+
+void PerfProcessHandler::acceptConnection()
+{
+ QTcpSocket *socket = mServer.nextPendingConnection();
+ socket->setParent(mProcess);
+ mProcess->setStdoutFd(socket->socketDescriptor());
+ mProcess->start(mAllArgs);
+ this->deleteLater();
+}
diff --git a/perfprocesshandler.h b/perfprocesshandler.h
new file mode 100644
index 0000000..f10e8a6
--- /dev/null
+++ b/perfprocesshandler.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of QtEnterprise Embedded.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#ifndef PERFPROCESSHANDLER_H
+#define PERFPROCESSHANDLER_H
+
+#include "process.h"
+#include <QTcpServer>
+
+// Starts the process once a connection to the TCP server is established and then deletes itself.
+class PerfProcessHandler : public QObject {
+ Q_OBJECT
+
+private:
+ QTcpServer mServer;
+ Process *mProcess;
+ QStringList mAllArgs;
+
+public:
+ PerfProcessHandler(Process *process, const QStringList &allArgs);
+ QTcpServer *server();
+
+public slots:
+ void acceptConnection();
+};
+
+#endif // PERFPROCESSHANDLER_H
diff --git a/process.cpp b/process.cpp
index 4c9140d..1320d02 100644
--- a/process.cpp
+++ b/process.cpp
@@ -26,6 +26,8 @@
#include <signal.h>
#include <fcntl.h>
#include <QFileInfo>
+#include <QTcpSocket>
+#include <errno.h>
static int pipefd[2];
@@ -86,6 +88,7 @@ Process::Process()
, mProcess(new QProcess(this))
, mDebuggee(0)
, mDebug(false)
+ , mStdoutFd(1)
{
mProcess->setProcessChannelMode(QProcess::SeparateChannels);
connect(mProcess, &QProcess::readyReadStandardError, this, &Process::readyReadStandardError);
@@ -112,13 +115,29 @@ Process::~Process()
close(pipefd[1]);
}
-void Process::readyReadStandardOutput()
+void Process::forwardProcessOutput(qintptr fd, const QByteArray &data)
{
- QByteArray b = mProcess->readAllStandardOutput();
- write(1, b.constData(), b.size());
+ const char *constData = data.constData();
+ int size = data.size();
+ while (size > 0) {
+ int written = write(fd, constData, size);
+ if (written == -1) {
+ fprintf(stderr, "Cannot forward application output: %d - %s\n", errno, strerror(errno));
+ qApp->quit();
+ break;
+ }
+ size -= written;
+ constData += written;
+ }
if (mConfig.flags.testFlag(Config::PrintDebugMessages))
- qDebug() << b;
+ qDebug() << data;
+}
+
+
+void Process::readyReadStandardOutput()
+{
+ forwardProcessOutput(mStdoutFd, mProcess->readAllStandardOutput());
}
void Process::readyReadStandardError()
@@ -131,10 +150,7 @@ void Process::readyReadStandardError()
}
mDebug = false; // only search once
}
- write(2, b.constData(), b.size());
-
- if (mConfig.flags.testFlag(Config::PrintDebugMessages))
- qDebug() << b;
+ forwardProcessOutput(2, b);
}
void Process::setDebug()
@@ -246,6 +262,11 @@ void Process::setConfig(const Config &config)
mConfig = config;
}
+void Process::setStdoutFd(qintptr stdoutFd)
+{
+ mStdoutFd = stdoutFd;
+}
+
QProcessEnvironment Process::interactiveProcessEnvironment() const
{
QProcessEnvironment env;
@@ -311,4 +332,3 @@ QProcessEnvironment Process::interactiveProcessEnvironment() const
return env;
}
-
diff --git a/process.h b/process.h
index 386dfb2..bf67d96 100644
--- a/process.h
+++ b/process.h
@@ -16,9 +16,13 @@
**
****************************************************************************/
+#ifndef PROCESS_H
+#define PROCESS_H
+
#include <QObject>
#include <QProcess>
#include <QMap>
+#include <QTcpServer>
class QSocketNotifier;
@@ -53,6 +57,7 @@ public:
void setSocketNotifier(QSocketNotifier*);
void setDebug();
void setConfig(const Config &);
+ void setStdoutFd(qintptr stdoutFd);
public slots:
void stop();
private slots:
@@ -62,6 +67,7 @@ private slots:
void error(QProcess::ProcessError);
void incomingConnection(int);
private:
+ void forwardProcessOutput(qintptr fd, const QByteArray &data);
void startup(QStringList);
QProcessEnvironment interactiveProcessEnvironment() const;
QProcess *mProcess;
@@ -69,4 +75,7 @@ private:
bool mDebug;
Config mConfig;
QString mBinary;
+ qintptr mStdoutFd;
};
+
+#endif // PROCESS_H