forked from qt-creator/qt-creator
QmlProfiler: Support local connections on Qt >= 5.6
This removes the need to receive messages from the application via stderr. The "Connecting to socket" is still parsed, but only for diagnostic purposes. If it doesn't arrive, the profiling will still work. Change-Id: I022691293da2a1e671ba1263bc76e4044bf1a5b7 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
@@ -40,6 +40,7 @@ const char STR_UNABLE_TO_LISTEN[] = "Unable to listen ";
|
|||||||
const char STR_IGNORING_DEBUGGER[] = "Ignoring \"-qmljsdebugger=";
|
const char STR_IGNORING_DEBUGGER[] = "Ignoring \"-qmljsdebugger=";
|
||||||
const char STR_IGNORING_DEBUGGER2[] = "Ignoring\"-qmljsdebugger="; // There is (was?) a bug in one of the error strings - safest to handle both
|
const char STR_IGNORING_DEBUGGER2[] = "Ignoring\"-qmljsdebugger="; // There is (was?) a bug in one of the error strings - safest to handle both
|
||||||
const char STR_CONNECTION_ESTABLISHED[] = "Connection established";
|
const char STR_CONNECTION_ESTABLISHED[] = "Connection established";
|
||||||
|
const char STR_CONNECTING_TO_SOCKET[] = "Connecting to socket";
|
||||||
|
|
||||||
const char QDECLARATIVE_ENGINE[] = "QDeclarativeEngine";
|
const char QDECLARATIVE_ENGINE[] = "QDeclarativeEngine";
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ void QmlOutputParser::processOutput(const QString &output)
|
|||||||
static QString debuggingNotEnabled = QLatin1String(Constants::STR_IGNORING_DEBUGGER);
|
static QString debuggingNotEnabled = QLatin1String(Constants::STR_IGNORING_DEBUGGER);
|
||||||
static QString debuggingNotEnabled2 = QLatin1String(Constants::STR_IGNORING_DEBUGGER2);
|
static QString debuggingNotEnabled2 = QLatin1String(Constants::STR_IGNORING_DEBUGGER2);
|
||||||
static QString connectionEstablished = QLatin1String(Constants::STR_CONNECTION_ESTABLISHED);
|
static QString connectionEstablished = QLatin1String(Constants::STR_CONNECTION_ESTABLISHED);
|
||||||
|
static QString connectingToSocket = QLatin1String(Constants::STR_CONNECTING_TO_SOCKET);
|
||||||
|
|
||||||
if (status.startsWith(waitingForConnection)) {
|
if (status.startsWith(waitingForConnection)) {
|
||||||
status.remove(0, waitingForConnection.size()); // chop of 'Waiting for connection '
|
status.remove(0, waitingForConnection.size()); // chop of 'Waiting for connection '
|
||||||
@@ -100,6 +101,8 @@ void QmlOutputParser::processOutput(const QString &output)
|
|||||||
emit errorMessage(tr("The application is not set up for QML/JS debugging."));
|
emit errorMessage(tr("The application is not set up for QML/JS debugging."));
|
||||||
} else if (status.startsWith(connectionEstablished)) {
|
} else if (status.startsWith(connectionEstablished)) {
|
||||||
emit connectionEstablishedMessage();
|
emit connectionEstablishedMessage();
|
||||||
|
} else if (status.startsWith(connectingToSocket)) {
|
||||||
|
emit connectingToSocketMessage();
|
||||||
} else {
|
} else {
|
||||||
emit unknownMessage(status);
|
emit unknownMessage(status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void waitingForConnectionOnPort(quint16 port);
|
void waitingForConnectionOnPort(quint16 port);
|
||||||
void connectionEstablishedMessage();
|
void connectionEstablishedMessage();
|
||||||
|
void connectingToSocketMessage();
|
||||||
void errorMessage(const QString &detailedError);
|
void errorMessage(const QString &detailedError);
|
||||||
void unknownMessage(const QString &unknownMessage);
|
void unknownMessage(const QString &unknownMessage);
|
||||||
void noOutputMessage();
|
void noOutputMessage();
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
QString workingDirectory;
|
QString workingDirectory;
|
||||||
QString sysroot;
|
QString sysroot;
|
||||||
QString analyzerHost;
|
QString analyzerHost;
|
||||||
|
QString analyzerSocket;
|
||||||
quint16 analyzerPort = 0;
|
quint16 analyzerPort = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include <qmldebug/qmldebugcommandlinearguments.h>
|
#include <qmldebug/qmldebugcommandlinearguments.h>
|
||||||
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
using namespace QmlProfiler;
|
using namespace QmlProfiler;
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
@@ -71,7 +72,7 @@ Analyzer::AnalyzerRunControl *LocalQmlProfilerRunner::createLocalRunControl(
|
|||||||
conf.executableArguments = sp.debuggeeArgs;
|
conf.executableArguments = sp.debuggeeArgs;
|
||||||
conf.workingDirectory = sp.workingDirectory;
|
conf.workingDirectory = sp.workingDirectory;
|
||||||
conf.environment = sp.environment;
|
conf.environment = sp.environment;
|
||||||
|
conf.socket = sp.analyzerSocket;
|
||||||
conf.port = sp.analyzerPort;
|
conf.port = sp.analyzerPort;
|
||||||
|
|
||||||
if (conf.executable.isEmpty()) {
|
if (conf.executable.isEmpty()) {
|
||||||
@@ -92,6 +93,17 @@ Analyzer::AnalyzerRunControl *LocalQmlProfilerRunner::createLocalRunControl(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString LocalQmlProfilerRunner::findFreeSocket()
|
||||||
|
{
|
||||||
|
QTemporaryFile file;
|
||||||
|
if (file.open()) {
|
||||||
|
return file.fileName();
|
||||||
|
} else {
|
||||||
|
qWarning() << "Could not open a temporary file to find a debug socket.";
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
quint16 LocalQmlProfilerRunner::findFreePort(QString &host)
|
quint16 LocalQmlProfilerRunner::findFreePort(QString &host)
|
||||||
{
|
{
|
||||||
QTcpServer server;
|
QTcpServer server;
|
||||||
@@ -121,15 +133,21 @@ LocalQmlProfilerRunner::~LocalQmlProfilerRunner()
|
|||||||
|
|
||||||
void LocalQmlProfilerRunner::start()
|
void LocalQmlProfilerRunner::start()
|
||||||
{
|
{
|
||||||
QString arguments = QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices,
|
QString arguments = m_configuration.socket.isEmpty() ?
|
||||||
m_configuration.port);
|
QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices,
|
||||||
|
m_configuration.port) :
|
||||||
|
QmlDebug::qmlDebugLocalArguments(QmlDebug::QmlProfilerServices,
|
||||||
|
m_configuration.socket);
|
||||||
|
|
||||||
|
|
||||||
if (!m_configuration.executableArguments.isEmpty())
|
if (!m_configuration.executableArguments.isEmpty())
|
||||||
arguments += QLatin1Char(' ') + m_configuration.executableArguments;
|
arguments += QLatin1Char(' ') + m_configuration.executableArguments;
|
||||||
|
|
||||||
if (QmlProfilerPlugin::debugOutput)
|
if (QmlProfilerPlugin::debugOutput) {
|
||||||
qWarning("QmlProfiler: Launching %s:%d", qPrintable(m_configuration.executable),
|
qWarning("QmlProfiler: Launching %s:%s", qPrintable(m_configuration.executable),
|
||||||
m_configuration.port);
|
qPrintable(m_configuration.socket.isEmpty() ?
|
||||||
|
QString::number(m_configuration.port) : m_configuration.socket));
|
||||||
|
}
|
||||||
|
|
||||||
m_launcher.setWorkingDirectory(m_configuration.workingDirectory);
|
m_launcher.setWorkingDirectory(m_configuration.workingDirectory);
|
||||||
m_launcher.setEnvironment(m_configuration.environment);
|
m_launcher.setEnvironment(m_configuration.environment);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ public:
|
|||||||
QString executable;
|
QString executable;
|
||||||
QString executableArguments;
|
QString executableArguments;
|
||||||
quint16 port;
|
quint16 port;
|
||||||
|
QString socket;
|
||||||
QString workingDirectory;
|
QString workingDirectory;
|
||||||
Utils::Environment environment;
|
Utils::Environment environment;
|
||||||
};
|
};
|
||||||
@@ -63,6 +64,7 @@ public:
|
|||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|
||||||
static quint16 findFreePort(QString &host);
|
static quint16 findFreePort(QString &host);
|
||||||
|
static QString findFreeSocket();
|
||||||
|
|
||||||
~LocalQmlProfilerRunner();
|
~LocalQmlProfilerRunner();
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public:
|
|||||||
QTimer connectionTimer;
|
QTimer connectionTimer;
|
||||||
int connectionAttempts;
|
int connectionAttempts;
|
||||||
|
|
||||||
|
QString localSocket;
|
||||||
QString tcpHost;
|
QString tcpHost;
|
||||||
quint64 tcpPort;
|
quint64 tcpPort;
|
||||||
QString sysroot;
|
QString sysroot;
|
||||||
@@ -107,6 +108,13 @@ void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
|
|||||||
disconnectClient();
|
disconnectClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerClientManager::setLocalSocket(QString file)
|
||||||
|
{
|
||||||
|
d->localSocket = file;
|
||||||
|
d->tcpPort = 0;
|
||||||
|
connectLocalClient(file);
|
||||||
|
}
|
||||||
|
|
||||||
void QmlProfilerClientManager::clearBufferedData()
|
void QmlProfilerClientManager::clearBufferedData()
|
||||||
{
|
{
|
||||||
if (d->qmlclientplugin)
|
if (d->qmlclientplugin)
|
||||||
@@ -118,7 +126,7 @@ void QmlProfilerClientManager::discardPendingData()
|
|||||||
clearBufferedData();
|
clearBufferedData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerClientManager::connectClient(quint16 port)
|
void QmlProfilerClientManager::connectTcpClient(quint16 port)
|
||||||
{
|
{
|
||||||
if (d->connection) {
|
if (d->connection) {
|
||||||
if (port == d->tcpPort) {
|
if (port == d->tcpPort) {
|
||||||
@@ -129,22 +137,28 @@ void QmlProfilerClientManager::connectClient(quint16 port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d->connection = new QmlDebugConnection;
|
createConnection();
|
||||||
enableServices();
|
|
||||||
connect(d->connection, &QmlDebugConnection::connected,
|
|
||||||
this, &QmlProfilerClientManager::qmlDebugConnectionOpened);
|
|
||||||
connect(d->connection, &QmlDebugConnection::disconnected,
|
|
||||||
this, &QmlProfilerClientManager::qmlDebugConnectionClosed);
|
|
||||||
connect(d->connection, &QmlDebugConnection::socketError,
|
|
||||||
this, &QmlProfilerClientManager::qmlDebugConnectionError);
|
|
||||||
connect(d->connection, &QmlDebugConnection::socketStateChanged,
|
|
||||||
this, &QmlProfilerClientManager::qmlDebugConnectionStateChanged);
|
|
||||||
d->connectionTimer.start();
|
d->connectionTimer.start();
|
||||||
d->tcpPort = port;
|
d->tcpPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerClientManager::enableServices()
|
void QmlProfilerClientManager::connectLocalClient(const QString &file)
|
||||||
{
|
{
|
||||||
|
if (d->connection) {
|
||||||
|
if (file == d->localSocket)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
delete d->connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
createConnection();
|
||||||
|
d->localSocket = file;
|
||||||
|
d->connection->startLocalServer(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlProfilerClientManager::createConnection()
|
||||||
|
{
|
||||||
|
d->connection = new QmlDebugConnection;
|
||||||
QTC_ASSERT(d->profilerState, return);
|
QTC_ASSERT(d->profilerState, return);
|
||||||
|
|
||||||
disconnectClientSignals();
|
disconnectClientSignals();
|
||||||
@@ -155,6 +169,14 @@ void QmlProfilerClientManager::enableServices()
|
|||||||
d->profilerState->requestedFeatures());
|
d->profilerState->requestedFeatures());
|
||||||
d->qmlclientplugin->setFlushInterval(d->flushInterval);
|
d->qmlclientplugin->setFlushInterval(d->flushInterval);
|
||||||
connectClientSignals();
|
connectClientSignals();
|
||||||
|
connect(d->connection, &QmlDebugConnection::connected,
|
||||||
|
this, &QmlProfilerClientManager::qmlDebugConnectionOpened);
|
||||||
|
connect(d->connection, &QmlDebugConnection::disconnected,
|
||||||
|
this, &QmlProfilerClientManager::qmlDebugConnectionClosed);
|
||||||
|
connect(d->connection, &QmlDebugConnection::socketError,
|
||||||
|
this, &QmlProfilerClientManager::qmlDebugConnectionError);
|
||||||
|
connect(d->connection, &QmlDebugConnection::socketStateChanged,
|
||||||
|
this, &QmlProfilerClientManager::qmlDebugConnectionStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerClientManager::connectClientSignals()
|
void QmlProfilerClientManager::connectClientSignals()
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
|
|
||||||
void registerProfilerStateManager(QmlProfilerStateManager *profilerState);
|
void registerProfilerStateManager(QmlProfilerStateManager *profilerState);
|
||||||
void setTcpConnection(QString host, quint64 port);
|
void setTcpConnection(QString host, quint64 port);
|
||||||
|
void setLocalSocket(QString file);
|
||||||
|
|
||||||
void clearBufferedData();
|
void clearBufferedData();
|
||||||
void discardPendingData();
|
void discardPendingData();
|
||||||
@@ -65,7 +66,8 @@ signals:
|
|||||||
void connectionClosed();
|
void connectionClosed();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void connectClient(quint16 port);
|
void connectTcpClient(quint16 port);
|
||||||
|
void connectLocalClient(const QString &file);
|
||||||
void disconnectClient();
|
void disconnectClient();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -89,7 +91,7 @@ private:
|
|||||||
|
|
||||||
void connectToClient();
|
void connectToClient();
|
||||||
|
|
||||||
void enableServices();
|
void createConnection();
|
||||||
void connectClientSignals();
|
void connectClientSignals();
|
||||||
void disconnectClientSignals();
|
void disconnectClientSignals();
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ QmlProfilerRunControl::QmlProfilerRunControl(const AnalyzerStartParameters &sp,
|
|||||||
this, &QmlProfilerRunControl::processIsRunning);
|
this, &QmlProfilerRunControl::processIsRunning);
|
||||||
connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::noOutputMessage,
|
connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::noOutputMessage,
|
||||||
this, [this](){processIsRunning(0);});
|
this, [this](){processIsRunning(0);});
|
||||||
|
connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::connectingToSocketMessage,
|
||||||
|
this, [this](){processIsRunning(0);});
|
||||||
connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::errorMessage,
|
connect(&d->m_outputParser, &QmlDebug::QmlOutputParser::errorMessage,
|
||||||
this, &QmlProfilerRunControl::wrongSetupMessageBox);
|
this, &QmlProfilerRunControl::wrongSetupMessageBox);
|
||||||
}
|
}
|
||||||
@@ -113,7 +115,7 @@ bool QmlProfilerRunControl::startEngine()
|
|||||||
|
|
||||||
if (startParameters().analyzerPort != 0)
|
if (startParameters().analyzerPort != 0)
|
||||||
emit processRunning(startParameters().analyzerPort);
|
emit processRunning(startParameters().analyzerPort);
|
||||||
else
|
else if (startParameters().analyzerSocket.isEmpty())
|
||||||
d->m_noDebugOutputTimer.start();
|
d->m_noDebugOutputTimer.start();
|
||||||
|
|
||||||
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
|
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
#include <qtsupport/baseqtversion.h>
|
||||||
|
#include <qtsupport/qtkitinformation.h>
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
@@ -79,7 +81,19 @@ static AnalyzerStartParameters createQmlProfilerStartParameters(RunConfiguration
|
|||||||
sp.debuggee = rc->executable();
|
sp.debuggee = rc->executable();
|
||||||
sp.debuggeeArgs = rc->commandLineArguments();
|
sp.debuggeeArgs = rc->commandLineArguments();
|
||||||
sp.displayName = rc->displayName();
|
sp.displayName = rc->displayName();
|
||||||
sp.analyzerPort = LocalQmlProfilerRunner::findFreePort(sp.analyzerHost);
|
|
||||||
|
const QtSupport::BaseQtVersion *version =
|
||||||
|
QtSupport::QtKitInformation::qtVersion(runConfiguration->target()->kit());
|
||||||
|
if (version) {
|
||||||
|
QtSupport::QtVersionNumber versionNumber = version->qtVersion();
|
||||||
|
if (versionNumber.majorVersion >= 5 && versionNumber.minorVersion >= 6)
|
||||||
|
sp.analyzerSocket = LocalQmlProfilerRunner::findFreeSocket();
|
||||||
|
else
|
||||||
|
sp.analyzerPort = LocalQmlProfilerRunner::findFreePort(sp.analyzerHost);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Running QML profiler on Kit without Qt version??";
|
||||||
|
sp.analyzerPort = LocalQmlProfilerRunner::findFreePort(sp.analyzerHost);
|
||||||
|
}
|
||||||
|
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,10 +214,10 @@ AnalyzerRunControl *QmlProfilerTool::createRunControl(const AnalyzerStartParamet
|
|||||||
|
|
||||||
engine->registerProfilerStateManager(d->m_profilerState);
|
engine->registerProfilerStateManager(d->m_profilerState);
|
||||||
|
|
||||||
bool isTcpConnection = true;
|
|
||||||
|
|
||||||
// FIXME: Check that there's something sensible in sp.connParams
|
// FIXME: Check that there's something sensible in sp.connParams
|
||||||
if (isTcpConnection)
|
if (!sp.analyzerSocket.isEmpty())
|
||||||
|
d->m_profilerConnections->setLocalSocket(sp.analyzerSocket);
|
||||||
|
else
|
||||||
d->m_profilerConnections->setTcpConnection(sp.analyzerHost, sp.analyzerPort);
|
d->m_profilerConnections->setTcpConnection(sp.analyzerHost, sp.analyzerPort);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -232,8 +232,9 @@ AnalyzerRunControl *QmlProfilerTool::createRunControl(const AnalyzerStartParamet
|
|||||||
|
|
||||||
populateFileFinder(projectDirectory, sp.sysroot);
|
populateFileFinder(projectDirectory, sp.sysroot);
|
||||||
|
|
||||||
connect(engine, &QmlProfilerRunControl::processRunning,
|
if (sp.analyzerSocket.isEmpty())
|
||||||
d->m_profilerConnections, &QmlProfilerClientManager::connectClient);
|
connect(engine, &QmlProfilerRunControl::processRunning,
|
||||||
|
d->m_profilerConnections, &QmlProfilerClientManager::connectTcpClient);
|
||||||
connect(d->m_profilerConnections, &QmlProfilerClientManager::connectionFailed,
|
connect(d->m_profilerConnections, &QmlProfilerClientManager::connectionFailed,
|
||||||
engine, &QmlProfilerRunControl::cancelProcess);
|
engine, &QmlProfilerRunControl::cancelProcess);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user