From ffc11d5e9e1cc7b38ac7f87bfdf40f8a84aec939 Mon Sep 17 00:00:00 2001 From: Ulf Hermann <ulf.hermann@theqtcompany.com> Date: Wed, 18 Nov 2015 12:34:52 +0100 Subject: [PATCH] QmlProfiler: allow for multiple sequential traces to be aggregated Task-number: QTCREATORBUG-13317 Change-Id: Ic7d1d5c94d8d522741b6c4207a21a43f521da5fb Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com> --- .../qmlprofiler/qmlprofilerclientmanager.cpp | 14 ++++++++++- .../qmlprofiler/qmlprofilerclientmanager.h | 3 +++ .../qmlprofiler/qmlprofilerconfigwidget.cpp | 4 ++++ .../qmlprofiler/qmlprofilerconfigwidget.ui | 17 +++++++++++++ .../qmlprofiler/qmlprofilerconstants.h | 1 + .../qmlprofiler/qmlprofilersettings.cpp | 16 +++++++++++++ src/plugins/qmlprofiler/qmlprofilersettings.h | 4 ++++ .../qmlprofiler/qmlprofilerstatewidget.cpp | 24 +++++++++++++++---- src/plugins/qmlprofiler/qmlprofilertool.cpp | 22 ++++++++++++----- 9 files changed, 93 insertions(+), 12 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp index 39e87bb8082..c031a8d3176 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp @@ -63,6 +63,7 @@ public: quint64 tcpPort; QString sysroot; quint32 flushInterval; + bool aggregateTraces; QmlProfilerModelManager *modelManager; }; @@ -77,6 +78,7 @@ QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) : d->connection = 0; d->connectionAttempts = 0; d->flushInterval = 0; + d->aggregateTraces = true; d->modelManager = 0; @@ -101,6 +103,16 @@ void QmlProfilerClientManager::setFlushInterval(quint32 flushInterval) d->flushInterval = flushInterval; } +bool QmlProfilerClientManager::aggregateTraces() const +{ + return d->aggregateTraces; +} + +void QmlProfilerClientManager::setAggregateTraces(bool aggregateTraces) +{ + d->aggregateTraces = aggregateTraces; +} + void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port) { d->tcpHost = host; @@ -349,7 +361,7 @@ void QmlProfilerClientManager::retryMessageBoxFinished(int result) void QmlProfilerClientManager::qmlComplete(qint64 maximumTime) { d->modelManager->traceTime()->increaseEndTime(maximumTime); - if (d->modelManager) + if (d->modelManager && !d->aggregateTraces) d->modelManager->acquiringDone(); } diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.h b/src/plugins/qmlprofiler/qmlprofilerclientmanager.h index 342f254bb6a..2d11ffdb9d3 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.h @@ -61,6 +61,9 @@ public: void setModelManager(QmlProfilerModelManager *m); void setFlushInterval(quint32 flushInterval); + bool aggregateTraces() const; + void setAggregateTraces(bool aggregateTraces); + signals: void connectionFailed(); void connectionClosed(); diff --git a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp index c7fd77db00f..9c130a82d67 100644 --- a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.cpp @@ -46,6 +46,9 @@ QmlProfilerConfigWidget::QmlProfilerConfigWidget(QmlProfilerSettings *settings, connect(m_ui->flushInterval, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), m_settings, &QmlProfilerSettings::setFlushInterval); + connect(m_ui->aggregateTraces, &QCheckBox::toggled, + m_settings, &QmlProfilerSettings::setAggregateTraces); + connect(m_settings, &QmlProfilerSettings::changed, this, &QmlProfilerConfigWidget::updateUi); } @@ -59,6 +62,7 @@ void QmlProfilerConfigWidget::updateUi() m_ui->flushEnabled->setChecked(m_settings->flushEnabled()); m_ui->flushInterval->setEnabled(m_settings->flushEnabled()); m_ui->flushInterval->setValue(m_settings->flushInterval()); + m_ui->aggregateTraces->setChecked(m_settings->aggregateTraces()); } } // Internal diff --git a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui index faa76b3b7b9..28f8139d00a 100644 --- a/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui +++ b/src/plugins/qmlprofiler/qmlprofilerconfigwidget.ui @@ -47,6 +47,23 @@ itself takes time. </string> </property> </widget> </item> + <item row="2" column="0"> + <widget class="QLabel" name="aggregateTracesLabel"> + <property name="text"> + <string>Process data only when process ends:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="aggregateTraces"> + <property name="toolTip"> + <string>Only process data when the process being profiled ends, not when the current recording +session ends. This way multiple recording sessions can be aggregated in a single trace, +for example if multiple QML engines start and stop sequentially during a single run of +the program.</string> + </property> + </widget> + </item> </layout> </widget> <resources/> diff --git a/src/plugins/qmlprofiler/qmlprofilerconstants.h b/src/plugins/qmlprofiler/qmlprofilerconstants.h index 528bddbd101..5b3e0611887 100644 --- a/src/plugins/qmlprofiler/qmlprofilerconstants.h +++ b/src/plugins/qmlprofiler/qmlprofilerconstants.h @@ -41,6 +41,7 @@ const char TASK_SAVE[] = "QmlProfiler.TaskSave"; const char FLUSH_ENABLED[] = "Analyzer.QmlProfiler.FlushEnabled"; const char FLUSH_INTERVAL[] = "Analyzer.QmlProfiler.FlushInterval"; const char LAST_TRACE_FILE[] = "Analyzer.QmlProfiler.LastTraceFile"; +const char AGGREGATE_TRACES[] = "Analyzer.QmlProfiler.AggregateTraces"; const char SETTINGS[] = "Analyzer.QmlProfiler.Settings"; const char ANALYZER[] = "Analyzer"; diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.cpp b/src/plugins/qmlprofiler/qmlprofilersettings.cpp index d1cb5ac1224..be5493a85fe 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.cpp +++ b/src/plugins/qmlprofiler/qmlprofilersettings.cpp @@ -45,6 +45,7 @@ QmlProfilerSettings::QmlProfilerSettings() defaults.insert(QLatin1String(Constants::FLUSH_INTERVAL), 1000); defaults.insert(QLatin1String(Constants::FLUSH_ENABLED), false); defaults.insert(QLatin1String(Constants::LAST_TRACE_FILE), QString()); + defaults.insert(QLatin1String(Constants::AGGREGATE_TRACES), false); // Read stored values QSettings *settings = Core::ICore::settings(); @@ -106,6 +107,19 @@ void QmlProfilerSettings::setLastTraceFile(const QString &lastTracePath) } } +bool QmlProfilerSettings::aggregateTraces() const +{ + return m_aggregateTraces; +} + +void QmlProfilerSettings::setAggregateTraces(bool aggregateTraces) +{ + if (m_aggregateTraces != aggregateTraces) { + m_aggregateTraces = aggregateTraces; + emit changed(); + } +} + void QmlProfilerSettings::writeGlobalSettings() const { QSettings *settings = Core::ICore::settings(); @@ -122,6 +136,7 @@ void QmlProfilerSettings::toMap(QVariantMap &map) const map[QLatin1String(Constants::FLUSH_INTERVAL)] = m_flushInterval; map[QLatin1String(Constants::FLUSH_ENABLED)] = m_flushEnabled; map[QLatin1String(Constants::LAST_TRACE_FILE)] = m_lastTraceFile; + map[QLatin1String(Constants::AGGREGATE_TRACES)] = m_aggregateTraces; } void QmlProfilerSettings::fromMap(const QVariantMap &map) @@ -129,6 +144,7 @@ void QmlProfilerSettings::fromMap(const QVariantMap &map) m_flushEnabled = map.value(QLatin1String(Constants::FLUSH_ENABLED)).toBool(); m_flushInterval = map.value(QLatin1String(Constants::FLUSH_INTERVAL)).toUInt(); m_lastTraceFile = map.value(QLatin1String(Constants::LAST_TRACE_FILE)).toString(); + m_aggregateTraces = map.value(QLatin1String(Constants::AGGREGATE_TRACES)).toBool(); emit changed(); } diff --git a/src/plugins/qmlprofiler/qmlprofilersettings.h b/src/plugins/qmlprofiler/qmlprofilersettings.h index 91d94e89c87..31370e9cd2f 100644 --- a/src/plugins/qmlprofiler/qmlprofilersettings.h +++ b/src/plugins/qmlprofiler/qmlprofilersettings.h @@ -53,6 +53,9 @@ public: QString lastTraceFile() const; void setLastTraceFile(const QString &lastTraceFile); + bool aggregateTraces() const; + void setAggregateTraces(bool aggregateTraces); + void writeGlobalSettings() const; signals: @@ -66,6 +69,7 @@ private: bool m_flushEnabled; quint32 m_flushInterval; QString m_lastTraceFile; + bool m_aggregateTraces; }; } // Internal diff --git a/src/plugins/qmlprofiler/qmlprofilerstatewidget.cpp b/src/plugins/qmlprofiler/qmlprofilerstatewidget.cpp index 5b1bd1c7232..2d1e929a320 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatewidget.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatewidget.cpp @@ -30,6 +30,8 @@ #include "qmlprofilerstatewidget.h" +#include <utils/qtcassert.h> + #include <QPainter> #include <QVBoxLayout> #include <QLabel> @@ -202,11 +204,23 @@ void QmlProfilerStateWidget::updateDisplay() return; } } else if (d->m_modelManager->progress() != 0 && !d->m_modelManager->isEmpty()) { - // When datamodel is acquiring data - if (d->m_profilerState->currentState() != QmlProfilerStateManager::Idle) - showText(tr("Loading data"), true); - else // Application died before all data could be read - showText(tr("Application stopped before loading all data"), true); + // When datamodel is acquiring or processing data + if (state == QmlProfilerModelManager::ProcessingData) { + showText(tr("Processing data"), true); + } else if (d->m_profilerState->currentState() != QmlProfilerStateManager::Idle) { + if (state == QmlProfilerModelManager::AcquiringData) { + // we don't know how much more, so progress numbers are strange here + showText(tr("Waiting for more data")); + } else if (state == QmlProfilerModelManager::ClearingData) { + // when starting a second recording from the same process without aggregation + showText(tr("Clearing old trace")); + } + } else if (state == QmlProfilerModelManager::AcquiringData) { + // Application died before all data could be read + showText(tr("Application stopped before loading all data")); + } else if (state == QmlProfilerModelManager::ClearingData) { + showText(tr("Clearing old trace")); + } return; } else if (state == QmlProfilerModelManager::AcquiringData) { showText(tr("Waiting for data")); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index c80795ebf63..c94337526cb 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -209,6 +209,7 @@ AnalyzerRunControl *QmlProfilerTool::createRunControl(const AnalyzerStartParamet d->m_profilerConnections->setFlushInterval(settings->flushEnabled() ? settings->flushInterval() : 0); + d->m_profilerConnections->setAggregateTraces(settings->aggregateTraces()); QmlProfilerRunControl *engine = new QmlProfilerRunControl(sp, runConfiguration); @@ -373,7 +374,9 @@ void QmlProfilerTool::recordingButtonChanged(bool recording) if (recording && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) { if (checkForUnsavedNotes()) { - clearData(); // clear right away, before the application starts + if (!d->m_profilerConnections->aggregateTraces() || + d->m_profilerModelManager->state() == QmlProfilerModelManager::Done) + clearData(); // clear before the recording starts, unless we aggregate recordings if (d->m_profilerState->clientRecording()) d->m_profilerState->setClientRecording(false); d->m_profilerState->setClientRecording(true); @@ -652,9 +655,13 @@ void QmlProfilerTool::clientsDisconnected() if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppDying || d->m_profilerState->currentState() == QmlProfilerStateManager::Idle) { if (d->m_profilerModelManager->state() == QmlProfilerModelManager::AcquiringData) { - showNonmodalWarning(tr("Application finished before loading profiled data.\n" - "Please use the stop button instead.")); - d->m_profilerModelManager->clear(); + if (d->m_profilerConnections->aggregateTraces()) { + d->m_profilerModelManager->acquiringDone(); + } else { + showNonmodalWarning(tr("Application finished before loading profiled data.\n" + "Please use the stop button instead.")); + d->m_profilerModelManager->clear(); + } } // ... and return to the "base" state @@ -822,13 +829,16 @@ void QmlProfilerTool::serverRecordingChanged() showSaveDialog(); setRecording(true); - clearData(); + if (!d->m_profilerConnections->aggregateTraces() || + d->m_profilerModelManager->state() == QmlProfilerModelManager::Done) + clearData(); d->m_profilerModelManager->prepareForWriting(); } else { setRecording(false); // changes back once loading is finished, see profilerDataModelStateChanged() - d->m_recordButton->setEnabled(false); + if (!d->m_profilerConnections->aggregateTraces()) + d->m_recordButton->setEnabled(false); } } } -- GitLab