Merge remote-tracking branch 'origin/4.4'

Conflicts:
	src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
	src/tools/clangbackend/ipcsource/clangjobrequest.cpp
	src/tools/clangbackend/ipcsource/clangjobrequest.h

Change-Id: Ib8602530663813ade418f995dfd2a736908cfe75
This commit is contained in:
Eike Ziller
2017-08-15 10:07:51 +02:00
209 changed files with 5006 additions and 2423 deletions

View File

@@ -38,6 +38,11 @@
namespace QmlProfiler {
namespace Internal {
static inline quint64 supportedFeatures()
{
return Constants::QML_JS_RANGE_FEATURES | (1ULL << ProfileMemory);
}
FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
QObject *parent) : QAbstractItemModel(parent)
{
@@ -51,8 +56,9 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed,
this, [this](int typeId, int, int){loadNotes(typeId, true);});
m_modelId = modelManager->registerModelProxy();
m_acceptedFeatures = supportedFeatures();
modelManager->announceFeatures(Constants::QML_JS_RANGE_FEATURES | 1 << ProfileMemory,
modelManager->announceFeatures(m_acceptedFeatures,
[this](const QmlEvent &event, const QmlEventType &type) {
loadEvent(event, type);
}, [this](){
@@ -63,7 +69,7 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
void FlameGraphModel::clear()
{
beginResetModel();
m_stackBottom = FlameGraphData(0, -1, 1);
m_stackBottom = FlameGraphData(0, -1, 0);
m_callStack.clear();
m_compileStack.clear();
m_callStack.append(QmlEvent());
@@ -98,7 +104,8 @@ void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal)
void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
{
Q_UNUSED(type);
if (!(m_acceptedFeatures & (1ULL << type.feature())))
return;
if (m_stackBottom.children.isEmpty())
beginResetModel();
@@ -150,6 +157,31 @@ void FlameGraphModel::onModelManagerStateChanged()
clear();
}
void FlameGraphModel::restrictToFeatures(quint64 visibleFeatures)
{
visibleFeatures = visibleFeatures & supportedFeatures();
if (visibleFeatures == m_acceptedFeatures)
return;
m_acceptedFeatures = visibleFeatures;
if (m_modelManager->state() != QmlProfilerModelManager::Done)
return;
clear();
beginResetModel();
if (!m_modelManager->replayEvents(m_modelManager->traceTime()->startTime(),
m_modelManager->traceTime()->endTime(),
std::bind(&FlameGraphModel::loadEvent,
this, std::placeholders::_1,
std::placeholders::_2))) {
emit m_modelManager->error(tr("Could not re-read events from temporary trace file."));
endResetModel();
clear();
} else {
finalize();
}
}
static QString nameForType(RangeType typeNumber)
{
switch (typeNumber) {

View File

@@ -91,6 +91,7 @@ public slots:
void loadEvent(const QmlEvent &event, const QmlEventType &type);
void finalize();
void onModelManagerStateChanged();
void restrictToFeatures(quint64 visibleFeatures);
void loadNotes(int typeId, bool emitSignal);
void clear();
@@ -105,6 +106,7 @@ private:
FlameGraphData *m_callStackTop;
FlameGraphData *m_compileStackTop;
quint64 m_acceptedFeatures;
int m_modelId;
QmlProfilerModelManager *m_modelManager;

View File

@@ -80,13 +80,7 @@ void FlameGraphView::selectByTypeId(int typeIndex)
void FlameGraphView::onVisibleFeaturesChanged(quint64 features)
{
int rangeTypeMask = 0;
for (int rangeType = 0; rangeType < MaximumRangeType; ++rangeType) {
if (features & (1ULL << featureFromRangeType(RangeType(rangeType))))
rangeTypeMask |= (1 << rangeType);
}
if (m_content->rootObject())
m_content->rootObject()->setProperty("visibleRangeTypes", rangeTypeMask);
m_model->restrictToFeatures(features);
}
void FlameGraphView::contextMenuEvent(QContextMenuEvent *ev)

View File

@@ -36,7 +36,6 @@ ScrollView {
signal gotoSourceLocation(string filename, int line, int column)
property int selectedTypeId: -1
property int visibleRangeTypes: -1
property int sizeRole: QmlProfilerFlameGraphModel.DurationRole
readonly property var trRoleNames: [
@@ -86,11 +85,9 @@ ScrollView {
property int typeId: FlameGraph.data(QmlProfilerFlameGraphModel.TypeIdRole) || -1
property bool isBindingLoop: parent.checkBindingLoop(typeId)
property bool rangeTypeVisible:
root.visibleRangeTypes & (1 << FlameGraph.data(QmlProfilerFlameGraphModel.RangeTypeRole))
itemHeight: rangeTypeVisible ? flamegraph.delegateHeight : 0
isSelected: typeId !== -1 && typeId === root.selectedTypeId && rangeTypeVisible
itemHeight: flamegraph.delegateHeight
isSelected: typeId !== -1 && typeId === root.selectedTypeId
borderColor: {
if (isSelected)

View File

@@ -92,6 +92,7 @@ QtcPlugin {
"qmlprofilerbindingloopsrenderpass_test.h",
"qmlprofilerclientmanager_test.cpp", "qmlprofilerclientmanager_test.h",
"qmlprofilerconfigwidget_test.cpp", "qmlprofilerconfigwidget_test.h",
"qmlprofilertraceview_test.cpp", "qmlprofilertraceview_test.h",
]
}
}

View File

@@ -48,6 +48,7 @@
#include "tests/qmlprofilerbindingloopsrenderpass_test.h"
#include "tests/qmlprofilerclientmanager_test.h"
#include "tests/qmlprofilerconfigwidget_test.h"
#include "tests/qmlprofilertraceview_test.h"
// Force QML Debugging to be enabled, so that we can selftest the profiler
#define QT_QML_DEBUG_NO_WARNING
@@ -141,6 +142,7 @@ QList<QObject *> QmlProfiler::Internal::QmlProfilerPlugin::createTestObjects() c
tests << new QmlProfilerBindingLoopsRenderPassTest;
tests << new QmlProfilerClientManagerTest;
tests << new QmlProfilerConfigWidgetTest;
tests << new QmlProfilerTraceViewTest;
tests << new QQmlEngine; // Trigger debug connector to be started
#endif

View File

@@ -23,20 +23,15 @@
**
****************************************************************************/
#include "qmlprofilerclientmanager.h"
#include "qmlprofilerruncontrol.h"
#include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"
#include <debugger/analyzer/analyzermanager.h>
#include "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h"
#include <coreplugin/icore.h>
#include <coreplugin/helpmanager.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/environmentaspect.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorericons.h>
#include <projectexplorer/runconfiguration.h>
@@ -47,18 +42,13 @@
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>
#include <qmldebug/qmloutputparser.h>
#include <qmldebug/qmldebugcommandlinearguments.h>
#include <utils/qtcassert.h>
#include <utils/qtcfallthrough.h>
#include <QApplication>
#include <QMainWindow>
#include <QMessageBox>
#include <QPushButton>
#include <QTimer>
using namespace Debugger;
using namespace Core;
using namespace ProjectExplorer;
using namespace QmlProfiler::Internal;
@@ -75,7 +65,6 @@ class QmlProfilerRunner::QmlProfilerRunnerPrivate
{
public:
QmlProfilerStateManager *m_profilerState = 0;
QTimer m_noDebugOutputTimer;
};
//
@@ -89,14 +78,6 @@ QmlProfilerRunner::QmlProfilerRunner(RunControl *runControl)
setDisplayName("QmlProfilerRunner");
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
setSupportsReRunning(false);
// Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect
// (application output might be redirected / blocked)
d->m_noDebugOutputTimer.setSingleShot(true);
d->m_noDebugOutputTimer.setInterval(4000);
connect(&d->m_noDebugOutputTimer, &QTimer::timeout, this, [this]() {
notifyRemoteSetupDone(Utils::Port());
});
}
QmlProfilerRunner::~QmlProfilerRunner()
@@ -113,13 +94,45 @@ void QmlProfilerRunner::start()
QUrl serverUrl = this->serverUrl();
QmlProfilerClientManager *clientManager = Internal::QmlProfilerTool::clientManager();
connect(clientManager, &QmlProfilerClientManager::connectionFailed,
this, [this, clientManager] {
QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(QmlProfilerTool::tr("Qt Creator"));
infoBox->setText(QmlProfilerTool::tr("Could not connect to the in-process QML profiler.\n"
"Do you want to retry?"));
infoBox->setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
connect(infoBox, &QDialog::finished, this, [clientManager, this](int result) {
switch (result) {
case QMessageBox::Retry:
clientManager->retryConnect();
break;
case QMessageBox::Help:
HelpManager::handleHelpRequest(
"qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html");
Q_FALLTHROUGH();
case QMessageBox::Cancel:
// The actual error message has already been logged.
QmlProfilerTool::logState(QmlProfilerTool::tr("Failed to connect."));
cancelProcess();
break;
}
});
infoBox->show();
});
clientManager->setServerUrl(serverUrl);
if (serverUrl.port() != -1) {
QmlProfilerClientManager *clientManager = Internal::QmlProfilerTool::clientManager();
clientManager->setServerUrl(serverUrl);
clientManager->connectToTcpServer();
} else {
clientManager->startLocalServer();
}
else if (serverUrl.path().isEmpty())
d->m_noDebugOutputTimer.start();
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
@@ -137,6 +150,7 @@ void QmlProfilerRunner::stop()
case QmlProfilerStateManager::AppStopRequested:
// Pressed "stop" a second time. Kill the application without collecting data
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
reportStopped();
break;
case QmlProfilerStateManager::Idle:
case QmlProfilerStateManager::AppDying:
@@ -149,7 +163,6 @@ void QmlProfilerRunner::stop()
}
break;
}
reportStopped();
}
void QmlProfilerRunner::notifyRemoteFinished()
@@ -190,53 +203,6 @@ void QmlProfilerRunner::cancelProcess()
runControl()->initiateStop();
}
void QmlProfilerRunner::notifyRemoteSetupFailed(const QString &errorMessage)
{
QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
//: %1 is detailed error message
infoBox->setText(tr("Could not connect to the in-process QML debugger:\n%1")
.arg(errorMessage));
infoBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Ok);
infoBox->setModal(true);
connect(infoBox, &QDialog::finished,
this, &QmlProfilerRunner::wrongSetupMessageBoxFinished);
infoBox->show();
// KILL
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying);
d->m_noDebugOutputTimer.stop();
}
void QmlProfilerRunner::wrongSetupMessageBoxFinished(int button)
{
if (button == QMessageBox::Help) {
HelpManager::handleHelpRequest(QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html"
"#setting-up-qml-debugging"));
}
}
void QmlProfilerRunner::notifyRemoteSetupDone(Utils::Port port)
{
d->m_noDebugOutputTimer.stop();
QUrl serverUrl = this->serverUrl();
if (!port.isValid())
port = Utils::Port(serverUrl.port());
if (port.isValid()) {
serverUrl.setPort(port.number());
auto clientManager = Internal::QmlProfilerTool::clientManager();
clientManager->setServerUrl(serverUrl);
clientManager->connectToTcpServer();
reportStarted();
}
}
void QmlProfilerRunner::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
// disconnect old
@@ -256,7 +222,7 @@ void QmlProfilerRunner::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::Idle:
d->m_noDebugOutputTimer.stop();
reportStopped();
break;
default:
break;
@@ -302,13 +268,17 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl)
}
LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const QUrl &serverUrl)
: RunWorker(runControl)
: SimpleTargetRunner(runControl)
{
setDisplayName("LocalQmlProfilerSupport");
m_profiler = new QmlProfilerRunner(runControl);
m_profiler->setServerUrl(serverUrl);
m_profiler->addDependency(this);
addStopDependency(m_profiler);
// We need to open the local server before the application tries to connect.
// In the TCP case, it doesn't hurt either to start the profiler before.
addStartDependency(m_profiler);
StandardRunnable debuggee = runnable().as<StandardRunnable>();
QString arguments = QmlDebug::qmlDebugArguments(QmlDebug::QmlProfilerServices, serverUrl);
@@ -319,21 +289,7 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const Q
debuggee.commandLineArguments = arguments;
debuggee.runMode = ApplicationLauncher::Gui;
m_profilee = new SimpleTargetRunner(runControl);
m_profilee->setRunnable(debuggee);
addDependency(m_profilee);
}
void LocalQmlProfilerSupport::start()
{
reportStarted();
emit localRunnerStarted();
}
void LocalQmlProfilerSupport::stop()
{
reportStopped();
emit localRunnerStopped();
setRunnable(debuggee);
}
} // namespace QmlProfiler

View File

@@ -50,8 +50,6 @@ public:
void registerProfilerStateManager( QmlProfilerStateManager *profilerState );
void notifyRemoteSetupDone(Utils::Port port);
void notifyRemoteSetupFailed(const QString &errorMessage);
void cancelProcess();
void notifyRemoteFinished();
@@ -59,14 +57,13 @@ private:
void start() override;
void stop() override;
void wrongSetupMessageBoxFinished(int);
void profilerStateChanged();
class QmlProfilerRunnerPrivate;
QmlProfilerRunnerPrivate *d;
};
class LocalQmlProfilerSupport : public ProjectExplorer::RunWorker
class LocalQmlProfilerSupport : public ProjectExplorer::SimpleTargetRunner
{
Q_OBJECT
@@ -75,15 +72,7 @@ public:
LocalQmlProfilerSupport(ProjectExplorer::RunControl *runControl,
const QUrl &serverUrl);
void start() override;
void stop() override;
signals:
void localRunnerStarted();
void localRunnerStopped();
private:
ProjectExplorer::SimpleTargetRunner *m_profilee;
QmlProfilerRunner *m_profiler;
};

View File

@@ -578,9 +578,8 @@ void QmlProfilerStatisticsMainView::updateNotes(int typeIndex)
item->setToolTip(it.value());
} else if (stats.durationRecursive > 0) {
item->setBackground(colors()->noteBackground);
item->setToolTip(tr("%1 / %2% of total in recursive calls")
.arg(Timeline::formatTime(stats.durationRecursive))
.arg(stats.durationRecursive * 100l / stats.duration));
item->setToolTip(tr("+%1 in recursive calls")
.arg(Timeline::formatTime(stats.durationRecursive)));
} else if (!item->toolTip().isEmpty()){
item->setBackground(colors()->defaultBackground);
item->setToolTip(QString());
@@ -619,8 +618,9 @@ void QmlProfilerStatisticsMainView::parseModel()
}
if (d->m_fieldShown[TotalTime]) {
newRow << new StatisticsViewItem(Timeline::formatTime(stats.duration),
stats.duration);
newRow << new StatisticsViewItem(
Timeline::formatTime(stats.duration - stats.durationRecursive),
stats.duration - stats.durationRecursive);
}
if (d->m_fieldShown[SelfTimeInPercent]) {

View File

@@ -139,8 +139,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
d->m_profilerState = new QmlProfilerStateManager(this);
connect(d->m_profilerState, &QmlProfilerStateManager::stateChanged,
this, &QmlProfilerTool::profilerStateChanged);
connect(d->m_profilerState, &QmlProfilerStateManager::clientRecordingChanged,
this, &QmlProfilerTool::clientRecordingChanged);
connect(d->m_profilerState, &QmlProfilerStateManager::serverRecordingChanged,
this, &QmlProfilerTool::serverRecordingChanged);
connect(d->m_profilerState, &QmlProfilerStateManager::recordedFeaturesChanged,
@@ -206,8 +204,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
connect(d->m_recordFeaturesMenu, &QMenu::triggered,
this, &QmlProfilerTool::toggleRequestedFeature);
setRecording(d->m_profilerState->clientRecording());
d->m_clearButton = new QToolButton;
d->m_clearButton->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
d->m_clearButton->setToolTip(tr("Discard data"));
@@ -240,6 +236,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
d->m_timeLabel->setPalette(palette);
d->m_timeLabel->setIndent(10);
updateTimeDisplay();
connect(d->m_timeLabel, &QObject::destroyed, &d->m_recordingTimer, &QTimer::stop);
setAvailableFeatures(d->m_profilerModelManager->availableFeatures());
setRecordedFeatures(0);
@@ -296,6 +293,46 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
model->createMarks(this, fileName);
});
}
auto updateRecordButton = [this]() {
const bool recording =
d->m_profilerState->currentState() != QmlProfilerStateManager::AppRunning
? d->m_profilerState->clientRecording() : d->m_profilerState->serverRecording();
const static QIcon recordOn = Debugger::Icons::RECORD_ON.icon();
const static QIcon recordOff = Debugger::Icons::RECORD_OFF.icon();
// update display
d->m_recordButton->setToolTip(recording ? tr("Disable Profiling") : tr("Enable Profiling"));
d->m_recordButton->setIcon(recording ? recordOn : recordOff);
d->m_recordButton->setChecked(recording);
switch (d->m_profilerModelManager->state()) {
case QmlProfilerModelManager::Empty:
case QmlProfilerModelManager::AcquiringData:
case QmlProfilerModelManager::Done:
// Don't change the recording button if the application cannot react to it.
d->m_recordButton->setEnabled(d->m_profilerState->currentState()
!= QmlProfilerStateManager::AppStopRequested
&& d->m_profilerState->currentState()
!= QmlProfilerStateManager::AppDying);
break;
case QmlProfilerModelManager::ProcessingData:
case QmlProfilerModelManager::ClearingData:
d->m_recordButton->setEnabled(false);
break;
}
};
connect(d->m_profilerState, &QmlProfilerStateManager::stateChanged,
d->m_recordButton, updateRecordButton);
connect(d->m_profilerState, &QmlProfilerStateManager::serverRecordingChanged,
d->m_recordButton, updateRecordButton);
connect(d->m_profilerState, &QmlProfilerStateManager::clientRecordingChanged,
d->m_recordButton, updateRecordButton);
connect(d->m_profilerModelManager, &QmlProfilerModelManager::stateChanged,
d->m_recordButton, updateRecordButton);
updateRecordButton();
}
QmlProfilerTool::~QmlProfilerTool()
@@ -351,16 +388,6 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
updateRunActions();
runWorker->registerProfilerStateManager(d->m_profilerState);
QmlProfilerClientManager *clientManager = d->m_profilerConnections;
// FIXME: Check that there's something sensible in sp.connParams
auto serverUrl = runWorker->serverUrl();
clientManager->setServerUrl(serverUrl);
if (!serverUrl.path().isEmpty()) {
// That's the local socket case.
// We open the server and the application connects to it, so let's do that right away.
clientManager->startLocalServer();
}
//
// Initialize m_projectFinder
@@ -369,37 +396,6 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
if (runConfiguration) {
d->m_profilerModelManager->populateFileFinder(runConfiguration);
}
connect(clientManager, &QmlProfilerClientManager::connectionFailed,
runWorker, [this, clientManager, runWorker]() {
QMessageBox *infoBox = new QMessageBox(ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
"Do you want to retry?"));
infoBox->setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
connect(infoBox, &QDialog::finished, runWorker, [clientManager, runWorker](int result) {
switch (result) {
case QMessageBox::Retry:
clientManager->retryConnect();
break;
case QMessageBox::Help:
HelpManager::handleHelpRequest(
"qthelp://org.qt-project.qtcreator/doc/creator-debugging-qml.html");
Q_FALLTHROUGH();
case QMessageBox::Cancel:
// The actual error message has already been logged.
logState(tr("Failed to connect."));
runWorker->cancelProcess();
break;
}
});
infoBox->show();
});
}
void QmlProfilerTool::recordingButtonChanged(bool recording)
@@ -425,28 +421,6 @@ void QmlProfilerTool::recordingButtonChanged(bool recording)
}
}
void QmlProfilerTool::setRecording(bool recording)
{
const static QIcon recordOn = Debugger::Icons::RECORD_ON.icon();
const static QIcon recordOff = Debugger::Icons::RECORD_OFF.icon();
// update display
d->m_recordButton->setToolTip( recording ? tr("Disable Profiling") : tr("Enable Profiling"));
d->m_recordButton->setIcon(recording ? recordOn : recordOff);
d->m_recordButton->setChecked(recording);
// manage timer
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (recording) {
d->m_recordingTimer.start();
d->m_recordingElapsedTime.start();
} else {
d->m_recordingTimer.stop();
}
}
}
void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber)
{
if (lineNumber < 0 || fileUrl.isEmpty())
@@ -538,7 +512,7 @@ void QmlProfilerTool::clearTextMarks()
bool QmlProfilerTool::prepareTool()
{
if (d->m_recordButton->isChecked()) {
if (d->m_profilerState->clientRecording()) {
if (checkForUnsavedNotes()) {
clearData(); // clear right away to suppress second warning on server recording change
return true;
@@ -794,28 +768,23 @@ void QmlProfilerTool::profilerDataModelStateChanged()
{
switch (d->m_profilerModelManager->state()) {
case QmlProfilerModelManager::Empty :
d->m_recordButton->setEnabled(true);
setButtonsEnabled(true);
break;
case QmlProfilerModelManager::ClearingData :
clearTextMarks();
d->m_recordButton->setEnabled(false);
setButtonsEnabled(false);
clearDisplay();
break;
case QmlProfilerModelManager::AcquiringData :
restoreFeatureVisibility();
d->m_recordButton->setEnabled(true); // Press recording button to stop recording
setButtonsEnabled(false); // Other buttons disabled
break;
case QmlProfilerModelManager::ProcessingData :
d->m_recordButton->setEnabled(false);
setButtonsEnabled(false);
break;
case QmlProfilerModelManager::Done :
showSaveOption();
updateTimeDisplay();
d->m_recordButton->setEnabled(true);
setButtonsEnabled(true);
createTextMarks();
break;
@@ -866,13 +835,10 @@ void QmlProfilerTool::profilerStateChanged()
break;
}
case QmlProfilerStateManager::Idle :
// when the app finishes, set recording display to client status
setRecording(d->m_profilerState->clientRecording());
break;
case QmlProfilerStateManager::AppStopRequested:
// Don't allow toggling the recording while data is loaded when application quits
if (d->m_profilerState->serverRecording()) {
d->m_recordButton->setEnabled(false);
// Turn off recording and wait for remaining data
d->m_profilerConnections->stopRecording();
} else {
@@ -886,14 +852,6 @@ void QmlProfilerTool::profilerStateChanged()
}
}
void QmlProfilerTool::clientRecordingChanged()
{
// if application is running, display server record changes
// if application is stopped, display client record changes
if (d->m_profilerState->currentState() != QmlProfilerStateManager::AppRunning)
setRecording(d->m_profilerState->clientRecording());
}
void QmlProfilerTool::serverRecordingChanged()
{
showLoadOption();
@@ -911,19 +869,16 @@ void QmlProfilerTool::serverRecordingChanged()
QMessageBox::Save)
showSaveDialog();
setRecording(true);
d->m_recordingTimer.start();
d->m_recordingElapsedTime.start();
if (!d->m_profilerModelManager->aggregateTraces() ||
d->m_profilerModelManager->state() == QmlProfilerModelManager::Done)
clearData();
d->m_profilerModelManager->startAcquiring();
} else {
setRecording(false);
// changes back once loading is finished, see profilerDataModelStateChanged()
if (!d->m_profilerModelManager->aggregateTraces()) {
d->m_recordButton->setEnabled(false);
d->m_recordingTimer.stop();
if (!d->m_profilerModelManager->aggregateTraces())
d->m_profilerModelManager->acquiringDone();
}
}
} else if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested) {
d->m_profilerModelManager->acquiringDone();

View File

@@ -69,14 +69,11 @@ public:
public slots:
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
void clientsDisconnected();
void setAvailableFeatures(quint64 features);
void setRecordedFeatures(quint64 features);
void recordingButtonChanged(bool recording);
void setRecording(bool recording);
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber);
void selectType(int typeId);

View File

@@ -115,13 +115,16 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, QmlProfilerViewManag
break;
case QmlProfilerModelManager::ClearingData:
d->m_zoomControl->clear();
if (!d->m_suspendedModels.isEmpty())
break; // Models are suspended already. AcquiringData was aborted.
Q_FALLTHROUGH();
case QmlProfilerModelManager::AcquiringData:
// Temporarily remove the models, while we're changing them
d->m_suspendedModels = d->m_modelProxy->models();
d->m_modelProxy->setModels(QVariantList());
if (d->m_suspendedModels.isEmpty()) {
// Temporarily remove the models, while we're changing them
d->m_suspendedModels = d->m_modelProxy->models();
d->m_modelProxy->setModels(QVariantList());
}
// Otherwise models are suspended already. This can happen if either acquiring was
// aborted or we're doing a "restrict to range" which consists of a partial clearing and
// then re-acquiring of data.
break;
}
});
@@ -309,6 +312,11 @@ bool QmlProfilerTraceView::isUsable() const
#endif
}
bool QmlProfilerTraceView::isSuspended() const
{
return !d->m_suspendedModels.isEmpty();
}
void QmlProfilerTraceView::changeEvent(QEvent *e)
{
if (e->type() == QEvent::EnabledChange) {

View File

@@ -53,6 +53,7 @@ public:
qint64 selectionEnd() const;
void showContextMenu(QPoint position);
bool isUsable() const;
bool isSuspended() const;
public slots:
void clear();

View File

@@ -25,17 +25,13 @@
#include "localqmlprofilerrunner_test.h"
#include "../qmlprofilerruncontrol.h"
#include <debugger/analyzer/analyzermanager.h>
#include <projectexplorer/runnables.h>
#include <qmlprofiler/qmlprofilerruncontrol.h>
#include <QtTest>
#include <QTcpServer>
using namespace ProjectExplorer;
namespace QmlProfiler {
namespace Internal {
@@ -43,83 +39,115 @@ LocalQmlProfilerRunnerTest::LocalQmlProfilerRunnerTest(QObject *parent) : QObjec
{
}
void LocalQmlProfilerRunnerTest::start()
{
delete runControl;
runControl = new ProjectExplorer::RunControl(nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE);
runControl->setRunnable(debuggee);
auto runner = new LocalQmlProfilerSupport(runControl, serverUrl);
connect(runner, &LocalQmlProfilerSupport::localRunnerStarted, this, [this] {
QVERIFY(!running);
++runCount;
running = true;
});
connect(runner, &LocalQmlProfilerSupport::localRunnerStopped, this, [this] {
QVERIFY(running);
running = false;
});
runControl->initiateStart();
}
void LocalQmlProfilerRunnerTest::testRunner()
{
QPointer<ProjectExplorer::RunControl> runControl;
QPointer<LocalQmlProfilerSupport> profiler;
ProjectExplorer::StandardRunnable debuggee;
QUrl serverUrl;
bool running = false;
bool started = false;
int startCount = 0;
int runCount = 0;
int stopCount = 0;
debuggee.executable = "\\-/|\\-/";
debuggee.environment = Utils::Environment::systemEnvironment();
// should not be used anywhere but cannot be empty
serverUrl.setPath("invalid");
start();
runControl = new ProjectExplorer::RunControl(nullptr,
ProjectExplorer::Constants::QML_PROFILER_RUN_MODE);
runControl->setRunnable(debuggee);
profiler = new LocalQmlProfilerSupport(runControl, serverUrl);
QTimer::singleShot(0, this, &LocalQmlProfilerRunnerTest::testRunner1);
}
auto connectRunner = [&]() {
connect(runControl, &ProjectExplorer::RunControl::aboutToStart, this, [&]() {
QVERIFY(!started);
QVERIFY(!running);
++startCount;
started = true;
});
connect(runControl, &ProjectExplorer::RunControl::started, this, [&]() {
QVERIFY(started);
QVERIFY(!running);
++runCount;
running = true;
});
connect(runControl, &ProjectExplorer::RunControl::stopped, this, [&]() {
QVERIFY(started);
++stopCount;
running = false;
started = false;
});
connect(runControl, &ProjectExplorer::RunControl::finished, this, [&]() {
running = false;
started = false;
});
};
void LocalQmlProfilerRunnerTest::testRunner1()
{
QTRY_COMPARE_WITH_TIMEOUT(runCount, 1, 10000);
QTRY_VERIFY_WITH_TIMEOUT(!running, 10000);
connectRunner();
serverUrl = urlFromLocalSocket();
runControl->initiateStart();
QTRY_COMPARE_WITH_TIMEOUT(startCount, 1, 10000);
QTRY_VERIFY_WITH_TIMEOUT(!started, 10000);
QCOMPARE(stopCount, 1);
QCOMPARE(runCount, 0);
runControl->initiateFinish();
QTRY_VERIFY(runControl.isNull());
QVERIFY(profiler.isNull());
serverUrl = ProjectExplorer::urlFromLocalSocket();
debuggee.executable = qApp->applicationFilePath();
debuggee.executable = QCoreApplication::applicationFilePath();
// comma is used to specify a test function. In this case, an invalid one.
debuggee.commandLineArguments = QString("-test QmlProfiler,");
runControl = new ProjectExplorer::RunControl(nullptr,
ProjectExplorer::Constants::QML_PROFILER_RUN_MODE);
runControl->setRunnable(debuggee);
profiler = new LocalQmlProfilerSupport(runControl, serverUrl);
connectRunner();
runControl->initiateStart();
start();
QTimer::singleShot(0, this, &LocalQmlProfilerRunnerTest::testRunner2);
}
void LocalQmlProfilerRunnerTest::testRunner2()
{
QTRY_COMPARE_WITH_TIMEOUT(runCount, 2, 10000);
QTRY_VERIFY_WITH_TIMEOUT(running, 10000);
QTRY_VERIFY_WITH_TIMEOUT(!running, 10000);
QCOMPARE(startCount, 2);
QCOMPARE(stopCount, 2);
QCOMPARE(runCount, 1);
runControl->initiateFinish();
QTRY_VERIFY(runControl.isNull());
QVERIFY(profiler.isNull());
debuggee.commandLineArguments.clear();
serverUrl = urlFromLocalHostAndFreePort();
serverUrl.clear();
serverUrl = ProjectExplorer::urlFromLocalHostAndFreePort();
runControl = new ProjectExplorer::RunControl(nullptr,
ProjectExplorer::Constants::QML_PROFILER_RUN_MODE);
runControl->setRunnable(debuggee);
profiler = new LocalQmlProfilerSupport(runControl, serverUrl);
connectRunner();
runControl->initiateStart();
start();
QTimer::singleShot(0, this, &LocalQmlProfilerRunnerTest::testRunner3);
}
void LocalQmlProfilerRunnerTest::testRunner3()
{
QTRY_COMPARE_WITH_TIMEOUT(runCount, 3, 10000);
QTRY_VERIFY_WITH_TIMEOUT(running, 10000);
runControl->initiateStop();
QTimer::singleShot(0, this, &LocalQmlProfilerRunnerTest::testRunner4);
}
void LocalQmlProfilerRunnerTest::testRunner4()
{
QTRY_VERIFY_WITH_TIMEOUT(!running, 10000);
delete runControl;
QCOMPARE(startCount, 3);
QCOMPARE(stopCount, 3);
QCOMPARE(runCount, 2);
runControl->initiateFinish();
QTRY_VERIFY(runControl.isNull());
QVERIFY(profiler.isNull());
}
void LocalQmlProfilerRunnerTest::testFindFreePort()
{
QUrl serverUrl = urlFromLocalHostAndFreePort();
QUrl serverUrl = ProjectExplorer::urlFromLocalHostAndFreePort();
QVERIFY(serverUrl.port() != -1);
QVERIFY(!serverUrl.host().isEmpty());
QTcpServer server;
@@ -128,7 +156,7 @@ void LocalQmlProfilerRunnerTest::testFindFreePort()
void LocalQmlProfilerRunnerTest::testFindFreeSocket()
{
QUrl serverUrl = urlFromLocalSocket();
QUrl serverUrl = ProjectExplorer::urlFromLocalSocket();
QString socket = serverUrl.path();
QVERIFY(!socket.isEmpty());
QVERIFY(!QFile::exists(socket));

View File

@@ -43,19 +43,6 @@ private slots:
void testRunner();
void testFindFreePort();
void testFindFreeSocket();
private:
void start();
void testRunner1();
void testRunner2();
void testRunner3();
void testRunner4();
bool running = false;
int runCount = 0;
ProjectExplorer::RunControl *runControl = nullptr;
ProjectExplorer::StandardRunnable debuggee;
QUrl serverUrl;
};
} // namespace Internal

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qmlprofilertraceview_test.h"
#include <QtTest>
namespace QmlProfiler {
namespace Internal {
QmlProfilerTraceViewTest::QmlProfilerTraceViewTest(QObject *parent) :
QObject(parent), traceView(nullptr, nullptr, &modelManager)
{
}
void QmlProfilerTraceViewTest::testStateChanges()
{
// Standard acquire-process-clear work flow
modelManager.startAcquiring();
QVERIFY(traceView.isSuspended());
modelManager.acquiringDone();
QVERIFY(!traceView.isSuspended());
modelManager.clear();
QVERIFY(!traceView.isSuspended());
// Restrict to range
modelManager.startAcquiring();
QVERIFY(traceView.isSuspended());
modelManager.acquiringDone();
QVERIFY(!traceView.isSuspended());
modelManager.restrictToRange(10, 14);
QVERIFY(!traceView.isSuspended());
modelManager.restrictToRange(-1, -1);
QVERIFY(!traceView.isSuspended());
modelManager.clear();
QVERIFY(!traceView.isSuspended());
// Abort Acquiring
modelManager.startAcquiring();
QVERIFY(traceView.isSuspended());
modelManager.clear();
QVERIFY(!traceView.isSuspended());
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qmlprofiler/qmlprofilermodelmanager.h>
#include <qmlprofiler/qmlprofilertraceview.h>
#include <QObject>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTraceViewTest : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerTraceViewTest(QObject *parent = nullptr);
private slots:
void testStateChanges();
private:
QmlProfilerModelManager modelManager;
QmlProfilerTraceView traceView;
};
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -14,7 +14,8 @@ SOURCES += \
$$PWD/qmlprofilerattachdialog_test.cpp \
$$PWD/qmlprofilerbindingloopsrenderpass_test.cpp \
$$PWD/qmlprofilerclientmanager_test.cpp \
$$PWD/qmlprofilerconfigwidget_test.cpp
$$PWD/qmlprofilerconfigwidget_test.cpp \
$$PWD/qmlprofilertraceview_test.cpp
HEADERS += \
$$PWD/debugmessagesmodel_test.h \
@@ -32,4 +33,5 @@ HEADERS += \
$$PWD/qmlprofilerattachdialog_test.h \
$$PWD/qmlprofilerbindingloopsrenderpass_test.h \
$$PWD/qmlprofilerclientmanager_test.h \
$$PWD/qmlprofilerconfigwidget_test.h
$$PWD/qmlprofilerconfigwidget_test.h \
$$PWD/qmlprofilertraceview_test.h