diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/qmlprofiler/qmlprofilerapplication.cpp | 57 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerapplication.h | 6 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerclient.cpp | 141 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerclient.h | 21 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerdata.cpp | 727 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerdata.h | 23 |
6 files changed, 387 insertions, 588 deletions
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp index 033492b516..0b0417bd7d 100644 --- a/tools/qmlprofiler/qmlprofilerapplication.cpp +++ b/tools/qmlprofiler/qmlprofilerapplication.cpp @@ -83,24 +83,27 @@ QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) : m_verbose(false), m_recording(true), m_interactive(false), - m_qmlProfilerClient(&m_connection, &m_profilerData), m_connectionAttempts(0) { + m_connection.reset(new QQmlDebugConnection); + m_profilerData.reset(new QmlProfilerData); + m_qmlProfilerClient.reset(new QmlProfilerClient(m_connection.data(), m_profilerData.data())); m_connectTimer.setInterval(1000); connect(&m_connectTimer, &QTimer::timeout, this, &QmlProfilerApplication::tryToConnect); - connect(&m_connection, &QQmlDebugConnection::connected, + connect(m_connection.data(), &QQmlDebugConnection::connected, this, &QmlProfilerApplication::connected); - connect(&m_qmlProfilerClient, &QmlProfilerClient::enabledChanged, + connect(m_qmlProfilerClient.data(), &QmlProfilerClient::enabledChanged, this, &QmlProfilerApplication::traceClientEnabledChanged); - connect(&m_qmlProfilerClient, &QmlProfilerClient::recordingStarted, + connect(m_qmlProfilerClient.data(), &QmlProfilerClient::traceStarted, this, &QmlProfilerApplication::notifyTraceStarted); - connect(&m_qmlProfilerClient, &QmlProfilerClient::error, + connect(m_qmlProfilerClient.data(), &QmlProfilerClient::error, this, &QmlProfilerApplication::logError); - connect(&m_profilerData, &QmlProfilerData::error, this, &QmlProfilerApplication::logError); - connect(&m_profilerData, &QmlProfilerData::dataReady, + connect(m_profilerData.data(), &QmlProfilerData::error, + this, &QmlProfilerApplication::logError); + connect(m_profilerData.data(), &QmlProfilerData::dataReady, this, &QmlProfilerApplication::traceFinished); } @@ -239,7 +242,7 @@ void QmlProfilerApplication::parseArguments() if (features == 0) parser.showHelp(4); - m_qmlProfilerClient.setFeatures(features); + m_qmlProfilerClient->setRequestedFeatures(features); if (parser.isSet(verbose)) m_verbose = true; @@ -295,10 +298,10 @@ void QmlProfilerApplication::flush() { if (m_recording) { m_pendingRequest = REQUEST_FLUSH; - m_qmlProfilerClient.sendRecordingStatus(false); + m_qmlProfilerClient->sendRecordingStatus(false); } else { - if (m_profilerData.save(m_interactiveOutputFile)) { - m_profilerData.clear(); + if (m_profilerData->save(m_interactiveOutputFile)) { + m_profilerData->clear(); if (!m_interactiveOutputFile.isEmpty()) prompt(tr("Data written to %1.").arg(m_interactiveOutputFile)); else @@ -313,7 +316,7 @@ void QmlProfilerApplication::flush() void QmlProfilerApplication::output() { - if (m_profilerData.save(m_interactiveOutputFile)) { + if (m_profilerData->save(m_interactiveOutputFile)) { if (!m_interactiveOutputFile.isEmpty()) prompt(tr("Data written to %1.").arg(m_interactiveOutputFile)); else @@ -385,12 +388,12 @@ void QmlProfilerApplication::userCommand(const QString &command) if (cmd == Constants::CMD_RECORD || cmd == Constants::CMD_RECORD2) { m_pendingRequest = REQUEST_TOGGLE_RECORDING; - m_qmlProfilerClient.sendRecordingStatus(!m_recording); + m_qmlProfilerClient->sendRecordingStatus(!m_recording); } else if (cmd == Constants::CMD_QUIT || cmd == Constants::CMD_QUIT2) { m_pendingRequest = REQUEST_QUIT; if (m_recording) { prompt(tr("The application is still generating data. Really quit (y/n)?")); - } else if (!m_profilerData.isEmpty()) { + } else if (!m_profilerData->isEmpty()) { prompt(tr("There is still trace data in memory. Really quit (y/n)?")); } else { quit(); @@ -398,7 +401,7 @@ void QmlProfilerApplication::userCommand(const QString &command) } else if (cmd == Constants::CMD_OUTPUT || cmd == Constants::CMD_OUTPUT2) { if (m_recording) { prompt(tr("Cannot output while recording data.")); - } else if (m_profilerData.isEmpty()) { + } else if (m_profilerData->isEmpty()) { prompt(tr("No data was recorded so far.")); } else { m_interactiveOutputFile = args.length() > 0 ? args.at(0).toString() : m_outputFile; @@ -408,14 +411,14 @@ void QmlProfilerApplication::userCommand(const QString &command) } else if (cmd == Constants::CMD_CLEAR || cmd == Constants::CMD_CLEAR2) { if (m_recording) { prompt(tr("Cannot clear data while recording.")); - } else if (m_profilerData.isEmpty()) { + } else if (m_profilerData->isEmpty()) { prompt(tr("No data was recorded so far.")); } else { - m_profilerData.clear(); + m_profilerData->clear(); prompt(tr("Trace data cleared.")); } } else if (cmd == Constants::CMD_FLUSH || cmd == Constants::CMD_FLUSH2) { - if (!m_recording && m_profilerData.isEmpty()) { + if (!m_recording && m_profilerData->isEmpty()) { prompt(tr("No data was recorded so far.")); } else { m_interactiveOutputFile = args.length() > 0 ? args.at(0).toString() : m_outputFile; @@ -443,9 +446,9 @@ void QmlProfilerApplication::notifyTraceStarted() void QmlProfilerApplication::outputData() { - if (!m_profilerData.isEmpty()) { - m_profilerData.save(m_outputFile); - m_profilerData.clear(); + if (!m_profilerData->isEmpty()) { + m_profilerData->save(m_outputFile); + m_profilerData->clear(); } } @@ -454,7 +457,7 @@ void QmlProfilerApplication::run() if (m_runMode == LaunchMode) { if (!m_socketFile.isEmpty()) { logStatus(QString::fromLatin1("Listening on %1 ...").arg(m_socketFile)); - m_connection.startLocalServer(m_socketFile); + m_connection->startLocalServer(m_socketFile); } m_process = new QProcess(this); QStringList arguments; @@ -481,7 +484,7 @@ void QmlProfilerApplication::run() void QmlProfilerApplication::tryToConnect() { - Q_ASSERT(!m_connection.isConnected()); + Q_ASSERT(!m_connection->isConnected()); ++ m_connectionAttempts; if (!m_verbose && !(m_connectionAttempts % 5)) {// print every 5 seconds @@ -497,7 +500,7 @@ void QmlProfilerApplication::tryToConnect() if (m_socketFile.isEmpty()) { logStatus(QString::fromLatin1("Connecting to %1:%2 ...").arg(m_hostName).arg(m_port)); - m_connection.connectToHost(m_hostName, m_port); + m_connection->connectToHost(m_hostName, m_port); } } @@ -538,7 +541,7 @@ void QmlProfilerApplication::processFinished() if (!m_interactive) exit(exitCode); else - m_qmlProfilerClient.clearPendingData(); + m_qmlProfilerClient->clearAll(); } void QmlProfilerApplication::traceClientEnabledChanged(bool enabled) @@ -547,7 +550,7 @@ void QmlProfilerApplication::traceClientEnabledChanged(bool enabled) logStatus("Trace client is attached."); // blocked server is waiting for recording message from both clients // once the last one is connected, both messages should be sent - m_qmlProfilerClient.sendRecordingStatus(m_recording); + m_qmlProfilerClient->setRecording(m_recording); } } @@ -564,7 +567,7 @@ void QmlProfilerApplication::traceFinished() prompt(tr("Application stopped recording."), false); } - m_qmlProfilerClient.clearPendingData(); + m_qmlProfilerClient->clearEvents(); } void QmlProfilerApplication::prompt(const QString &line, bool ready) diff --git a/tools/qmlprofiler/qmlprofilerapplication.h b/tools/qmlprofiler/qmlprofilerapplication.h index 13f0f041f0..f7a8efd61b 100644 --- a/tools/qmlprofiler/qmlprofilerapplication.h +++ b/tools/qmlprofiler/qmlprofilerapplication.h @@ -105,9 +105,9 @@ private: bool m_recording; bool m_interactive; - QQmlDebugConnection m_connection; - QmlProfilerClient m_qmlProfilerClient; - QmlProfilerData m_profilerData; + QScopedPointer<QQmlDebugConnection> m_connection; + QScopedPointer<QmlProfilerClient> m_qmlProfilerClient; + QScopedPointer<QmlProfilerData> m_profilerData; QTimer m_connectTimer; uint m_connectionAttempts; }; diff --git a/tools/qmlprofiler/qmlprofilerclient.cpp b/tools/qmlprofiler/qmlprofilerclient.cpp index 0c031db914..b69c7e73e1 100644 --- a/tools/qmlprofiler/qmlprofilerclient.cpp +++ b/tools/qmlprofiler/qmlprofilerclient.cpp @@ -43,36 +43,26 @@ public: QmlProfilerClientPrivate(QQmlDebugConnection *connection, QmlProfilerData *data); QmlProfilerData *data; - - qint64 inProgressRanges; - QStack<qint64> rangeStartTimes[QQmlProfilerDefinitions::MaximumRangeType]; - QStack<QStringList> rangeDatas[QQmlProfilerDefinitions::MaximumRangeType]; - QStack<QQmlEventLocation> rangeLocations[QQmlProfilerDefinitions::MaximumRangeType]; - int rangeCount[QQmlProfilerDefinitions::MaximumRangeType]; - bool enabled; }; QmlProfilerClientPrivate::QmlProfilerClientPrivate(QQmlDebugConnection *connection, QmlProfilerData *data) : - QQmlProfilerClientPrivate(connection), data(data), inProgressRanges(0), enabled(false) + QQmlProfilerClientPrivate(connection, data), data(data), enabled(false) { - ::memset(rangeCount, 0, QQmlProfilerDefinitions::MaximumRangeType * sizeof(int)); } QmlProfilerClient::QmlProfilerClient(QQmlDebugConnection *connection, QmlProfilerData *data) : QQmlProfilerClient(*(new QmlProfilerClientPrivate(connection, data))) { -} - -void QmlProfilerClient::clearPendingData() -{ Q_D(QmlProfilerClient); - for (int i = 0; i < QQmlProfilerDefinitions::MaximumRangeType; ++i) { - d->rangeCount[i] = 0; - d->rangeDatas[i].clear(); - d->rangeLocations[i].clear(); - } + setRequestedFeatures(std::numeric_limits<quint64>::max()); + connect(this, &QQmlProfilerClient::traceStarted, + d->data, &QmlProfilerData::setTraceStartTime); + connect(this, &QQmlProfilerClient::traceFinished, + d->data, &QmlProfilerData::setTraceEndTime); + connect(this, &QQmlProfilerClient::complete, + d->data, &QmlProfilerData::complete); } void QmlProfilerClient::stateChanged(State state) @@ -84,119 +74,4 @@ void QmlProfilerClient::stateChanged(State state) } } -void QmlProfilerClient::traceStarted(qint64 time, int engineId) -{ - Q_UNUSED(engineId); - Q_D(QmlProfilerClient); - d->data->setTraceStartTime(time); - emit recordingStarted(); -} - -void QmlProfilerClient::traceFinished(qint64 time, int engineId) -{ - Q_UNUSED(engineId); - Q_D(QmlProfilerClient); - d->data->setTraceEndTime(time); -} - -void QmlProfilerClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) -{ - Q_D(QmlProfilerClient); - d->rangeStartTimes[type].push(startTime); - d->inProgressRanges |= (static_cast<qint64>(1) << type); - ++d->rangeCount[type]; -} - -void QmlProfilerClient::rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QString &data) -{ - Q_UNUSED(time); - Q_D(QmlProfilerClient); - int count = d->rangeCount[type]; - if (count > 0) { - while (d->rangeDatas[type].count() < count) - d->rangeDatas[type].push(QStringList()); - d->rangeDatas[type][count - 1] << data; - } -} - -void QmlProfilerClient::rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QQmlEventLocation &location) -{ - Q_UNUSED(time); - Q_D(QmlProfilerClient); - if (d->rangeCount[type] > 0) - d->rangeLocations[type].push(location); -} - -void QmlProfilerClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) -{ - Q_D(QmlProfilerClient); - - if (d->rangeCount[type] == 0) { - emit error(tr("Spurious range end detected.")); - return; - } - - --d->rangeCount[type]; - if (d->inProgressRanges & (static_cast<qint64>(1) << type)) - d->inProgressRanges &= ~(static_cast<qint64>(1) << type); - QStringList data = d->rangeDatas[type].count() ? d->rangeDatas[type].pop() : QStringList(); - QQmlEventLocation location = d->rangeLocations[type].count() ? d->rangeLocations[type].pop() : - QQmlEventLocation(); - qint64 startTime = d->rangeStartTimes[type].pop(); - - if (d->rangeCount[type] == 0 && d->rangeDatas[type].count() + d->rangeStartTimes[type].count() - + d->rangeLocations[type].count() != 0) { - emit error(tr("Incorrectly nested range data")); - return; - } - - d->data->addQmlEvent(type, QQmlProfilerDefinitions::QmlBinding, startTime, endTime - startTime, - data, location); -} - -void QmlProfilerClient::animationFrame(qint64 time, int frameRate, int animationCount, int threadId) -{ - Q_D(QmlProfilerClient); - d->data->addFrameEvent(time, frameRate, animationCount, threadId); -} - -void QmlProfilerClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, - qint64 time, qint64 numericData1, qint64 numericData2, - qint64 numericData3, qint64 numericData4, - qint64 numericData5) -{ - Q_D(QmlProfilerClient); - d->data->addSceneGraphFrameEvent(type, time, numericData1, numericData2, numericData3, - numericData4, numericData5); -} - -void QmlProfilerClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, qint64 time, - const QString &url, int numericData1, int numericData2) -{ - Q_D(QmlProfilerClient); - d->data->addPixmapCacheEvent(type, time, url, numericData1, numericData2); -} - -void QmlProfilerClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, - qint64 amount) -{ - Q_D(QmlProfilerClient); - d->data->addMemoryEvent(type, time, amount); -} - -void QmlProfilerClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, - int a, int b) -{ - Q_D(QmlProfilerClient); - d->data->addInputEvent(type, time, a, b); -} - -void QmlProfilerClient::complete() -{ - Q_D(QmlProfilerClient); - d->data->complete(); -} - #include "moc_qmlprofilerclient.cpp" diff --git a/tools/qmlprofiler/qmlprofilerclient.h b/tools/qmlprofiler/qmlprofilerclient.h index a04a412bb0..b9d8ce241f 100644 --- a/tools/qmlprofiler/qmlprofilerclient.h +++ b/tools/qmlprofiler/qmlprofilerclient.h @@ -29,9 +29,9 @@ #ifndef QMLPROFILERCLIENT_H #define QMLPROFILERCLIENT_H -#include <private/qqmleventlocation_p.h> #include <private/qqmlprofilerclient_p.h> #include <private/qqmlprofilerdefinitions_p.h> +#include <private/qqmlprofilereventlocation_p.h> class QmlProfilerData; class QmlProfilerClientPrivate; @@ -42,32 +42,13 @@ class QmlProfilerClient : public QQmlProfilerClient public: QmlProfilerClient(QQmlDebugConnection *connection, QmlProfilerData *data); - void clearPendingData(); signals: void enabledChanged(bool enabled); - void recordingStarted(); void error(const QString &error); private: void stateChanged(State state) override; - - void traceStarted(qint64 time, int engineId) override; - void traceFinished(qint64 time, int engineId) override; - void rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) override; - void rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, const QString &data) override; - void rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QQmlEventLocation &location) override; - void rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) override; - void animationFrame(qint64 time, int frameRate, int animationCount, int threadId) override; - void sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, qint64 time, - qint64 numericData1, qint64 numericData2, qint64 numericData3, - qint64 numericData4, qint64 numericData5) override; - void pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, qint64 time, - const QString &url, int numericData1, int numericData2) override; - void memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 amount) override; - void inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b) override; - void complete() override; }; #endif // QMLPROFILERCLIENT_H diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp index 7dcfa4cdaa..32e03298da 100644 --- a/tools/qmlprofiler/qmlprofilerdata.cpp +++ b/tools/qmlprofiler/qmlprofilerdata.cpp @@ -34,6 +34,8 @@ #include <QFile> #include <QXmlStreamReader> #include <QRegularExpression> +#include <QQueue> +#include <QStack> #include <limits> @@ -60,72 +62,13 @@ static const char *MESSAGE_STRINGS[] = { "Complete", "PixmapCache", "SceneGraph", - "MemoryAllocation" + "MemoryAllocation", + "DebugMessage" }; Q_STATIC_ASSERT(sizeof(MESSAGE_STRINGS) == QQmlProfilerDefinitions::MaximumMessage * sizeof(const char *)); -struct QmlRangeEventData { - QmlRangeEventData() {} // never called - QmlRangeEventData(const QString &_displayName, int _detailType, const QString &_eventHashStr, - const QQmlEventLocation &_location, const QString &_details, - QQmlProfilerDefinitions::Message _message, - QQmlProfilerDefinitions::RangeType _rangeType) - : displayName(_displayName), eventHashStr(_eventHashStr), location(_location), - details(_details), message(_message), rangeType(_rangeType), detailType(_detailType) {} - QString displayName; - QString eventHashStr; - QQmlEventLocation location; - QString details; - QQmlProfilerDefinitions::Message message; - QQmlProfilerDefinitions::RangeType rangeType; - int detailType; // can be BindingType, PixmapCacheEventType or SceneGraphFrameType -}; - -struct QmlRangeEventStartInstance { - QmlRangeEventStartInstance() {} // never called - QmlRangeEventStartInstance(qint64 _startTime, qint64 _duration, int _frameRate, - int _animationCount, int _threadId, QmlRangeEventData *_data) - : startTime(_startTime), duration(_duration), frameRate(_frameRate), - animationCount(_animationCount), threadId(_threadId), numericData4(-1), numericData5(-1), - data(_data) - { } - - QmlRangeEventStartInstance(qint64 _startTime, qint64 _numericData1, qint64 _numericData2, - qint64 _numericData3, qint64 _numericData4, qint64 _numericData5, - QmlRangeEventData *_data) - : startTime(_startTime), duration(-1), numericData1(_numericData1), - numericData2(_numericData2), numericData3(_numericData3), numericData4(_numericData4), - numericData5(_numericData5), data(_data) - { } - qint64 startTime; - qint64 duration; - union { - int frameRate; - int inputType; - qint64 numericData1; - }; - union { - int animationCount; - int inputA; - qint64 numericData2; - }; - union { - int threadId; - int inputB; - qint64 numericData3; - }; - qint64 numericData4; - qint64 numericData5; - QmlRangeEventData *data; -}; - -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(QmlRangeEventData, Q_MOVABLE_TYPE); -Q_DECLARE_TYPEINFO(QmlRangeEventStartInstance, Q_MOVABLE_TYPE); -QT_END_NAMESPACE - ///////////////////////////////////////////////////////////////// class QmlProfilerDataPrivate { @@ -133,8 +76,8 @@ public: QmlProfilerDataPrivate(QmlProfilerData *qq){ Q_UNUSED(qq); } // data storage - QHash<QString, QmlRangeEventData *> eventDescriptions; - QVector<QmlRangeEventStartInstance> startInstanceList; + QVector<QQmlProfilerEventType> eventTypes; + QVector<QQmlProfilerEvent> events; qint64 traceStartTime; qint64 traceEndTime; @@ -146,7 +89,7 @@ public: ///////////////////////////////////////////////////////////////// QmlProfilerData::QmlProfilerData(QObject *parent) : - QObject(parent),d(new QmlProfilerDataPrivate(this)) + QQmlProfilerEventReceiver(parent), d(new QmlProfilerDataPrivate(this)) { d->state = Empty; clear(); @@ -160,9 +103,8 @@ QmlProfilerData::~QmlProfilerData() void QmlProfilerData::clear() { - qDeleteAll(d->eventDescriptions); - d->eventDescriptions.clear(); - d->startInstanceList.clear(); + d->eventTypes.clear(); + d->events.clear(); d->traceEndTime = std::numeric_limits<qint64>::min(); d->traceStartTime = std::numeric_limits<qint64>::max(); @@ -171,15 +113,6 @@ void QmlProfilerData::clear() setState(Empty); } -QString QmlProfilerData::getHashStringForQmlEvent(const QQmlEventLocation &location, int eventType) -{ - return QString(QStringLiteral("%1:%2:%3:%4")).arg( - location.filename, - QString::number(location.line), - QString::number(location.column), - QString::number(eventType)); -} - QString QmlProfilerData::qmlRangeTypeAsString(QQmlProfilerDefinitions::RangeType type) { if (type * sizeof(char *) < sizeof(RANGE_TYPE_STRINGS)) @@ -218,20 +151,20 @@ qint64 QmlProfilerData::traceEndTime() const return d->traceEndTime; } -void QmlProfilerData::addQmlEvent(QQmlProfilerDefinitions::RangeType type, - QQmlProfilerDefinitions::BindingType bindingType, - qint64 startTime, - qint64 duration, - const QStringList &data, - const QQmlEventLocation &location) +void QmlProfilerData::addEvent(const QQmlProfilerEvent &event) { setState(AcquiringData); + d->events.append(event); +} + +void QmlProfilerData::addEventType(const QQmlProfilerEventType &type) +{ + QQmlProfilerEventType newType = type; QString details; // generate details string - if (!data.isEmpty()) { - details = data.join(QLatin1Char(' ')).replace( - QLatin1Char('\n'), QLatin1Char(' ')).simplified(); + if (!type.data().isEmpty()) { + details = type.data().simplified(); QRegularExpression rewrite(QStringLiteral("^\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)$")); QRegularExpressionMatch match = rewrite.match(details); if (match.hasMatch()) { @@ -241,223 +174,132 @@ void QmlProfilerData::addQmlEvent(QQmlProfilerDefinitions::RangeType type, details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1); } - QQmlEventLocation eventLocation = location; - QString displayName, eventHashStr; - // generate hash - if (eventLocation.filename.isEmpty()) { - displayName = tr("<bytecode>"); - eventHashStr = getHashStringForQmlEvent(eventLocation, type); - } else { - const QString filePath = QUrl(eventLocation.filename).path(); - displayName = filePath.midRef( - filePath.lastIndexOf(QLatin1Char('/')) + 1) + - QLatin1Char(':') + QString::number(eventLocation.line); - eventHashStr = getHashStringForQmlEvent(eventLocation, type); - } - - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(displayName, bindingType, eventHashStr, location, details, - QQmlProfilerDefinitions::MaximumMessage, type); - d->eventDescriptions.insert(eventHashStr, newEvent); - } - - QmlRangeEventStartInstance rangeEventStartInstance(startTime, duration, -1, -1, -1, newEvent); - - d->startInstanceList.append(rangeEventStartInstance); -} - -void QmlProfilerData::addFrameEvent(qint64 time, int framerate, int animationcount, int threadId) -{ - setState(AcquiringData); - - QString details = tr("Animation Timer Update"); - QString displayName = tr("<Animation Update>"); - QString eventHashStr = displayName; - - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(displayName, QQmlProfilerDefinitions::AnimationFrame, - eventHashStr, - QQmlEventLocation(), details, - QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::MaximumRangeType); - d->eventDescriptions.insert(eventHashStr, newEvent); - } - - QmlRangeEventStartInstance rangeEventStartInstance(time, -1, framerate, animationcount, - threadId, newEvent); - - d->startInstanceList.append(rangeEventStartInstance); -} - -void QmlProfilerData::addSceneGraphFrameEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, - qint64 time, qint64 numericData1, qint64 numericData2, - qint64 numericData3, qint64 numericData4, - qint64 numericData5) -{ - setState(AcquiringData); - - QString eventHashStr = QString::fromLatin1("SceneGraph:%1").arg(type); - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(QStringLiteral("<SceneGraph>"), type, eventHashStr, - QQmlEventLocation(), QString(), - QQmlProfilerDefinitions::SceneGraphFrame, - QQmlProfilerDefinitions::MaximumRangeType); - d->eventDescriptions.insert(eventHashStr, newEvent); - } + newType.setData(details); - QmlRangeEventStartInstance rangeEventStartInstance(time, numericData1, numericData2, - numericData3, numericData4, numericData5, - newEvent); - d->startInstanceList.append(rangeEventStartInstance); -} - -void QmlProfilerData::addPixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, - qint64 time, const QString &location, - int numericData1, int numericData2) -{ - setState(AcquiringData); - - QString filePath = QUrl(location).path(); - - const QString eventHashStr = filePath.midRef(filePath.lastIndexOf(QLatin1Char('/')) + 1) - + QLatin1Char(':') + QString::number(type); - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(eventHashStr, type, eventHashStr, - QQmlEventLocation(location, -1, -1), QString(), - QQmlProfilerDefinitions::PixmapCacheEvent, - QQmlProfilerDefinitions::MaximumRangeType); - d->eventDescriptions.insert(eventHashStr, newEvent); + QString displayName; + switch (type.message()) { + case QQmlProfilerDefinitions::Event: { + switch (type.detailType()) { + case QQmlProfilerDefinitions::Mouse: + case QQmlProfilerDefinitions::Key: + displayName = QString::fromLatin1("Input:%1").arg(type.detailType()); + break; + case QQmlProfilerDefinitions::AnimationFrame: + displayName = QString::fromLatin1("AnimationFrame"); + break; + default: + displayName = QString::fromLatin1("Unknown"); + } + break; } - - QmlRangeEventStartInstance rangeEventStartInstance(time, numericData1, numericData2, 0, 0, 0, - newEvent); - d->startInstanceList.append(rangeEventStartInstance); -} - -void QmlProfilerData::addMemoryEvent(QQmlProfilerDefinitions::MemoryType type, qint64 time, - qint64 size) -{ - setState(AcquiringData); - QString eventHashStr = QString::fromLatin1("MemoryAllocation:%1").arg(type); - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(eventHashStr, type, eventHashStr, QQmlEventLocation(), - QString(), QQmlProfilerDefinitions::MemoryAllocation, - QQmlProfilerDefinitions::MaximumRangeType); - d->eventDescriptions.insert(eventHashStr, newEvent); + case QQmlProfilerDefinitions::RangeStart: + case QQmlProfilerDefinitions::RangeData: + case QQmlProfilerDefinitions::RangeLocation: + case QQmlProfilerDefinitions::RangeEnd: + case QQmlProfilerDefinitions::Complete: + Q_UNREACHABLE(); + break; + case QQmlProfilerDefinitions::PixmapCacheEvent: { + const QString filePath = QUrl(type.location().filename()).path(); + displayName = filePath.midRef(filePath.lastIndexOf(QLatin1Char('/')) + 1) + + QLatin1Char(':') + QString::number(type.detailType()); + break; } - QmlRangeEventStartInstance rangeEventStartInstance(time, size, 0, 0, 0, 0, newEvent); - d->startInstanceList.append(rangeEventStartInstance); -} - -void QmlProfilerData::addInputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, - int a, int b) -{ - setState(AcquiringData); - - QQmlProfilerDefinitions::EventType eventType; - switch (type) { - case QQmlProfilerDefinitions::InputKeyPress: - case QQmlProfilerDefinitions::InputKeyRelease: - case QQmlProfilerDefinitions::InputKeyUnknown: - eventType = QQmlProfilerDefinitions::Key; + case QQmlProfilerDefinitions::SceneGraphFrame: + displayName = QString::fromLatin1("SceneGraph:%1").arg(type.detailType()); break; - default: - eventType = QQmlProfilerDefinitions::Mouse; + case QQmlProfilerDefinitions::MemoryAllocation: + displayName = QString::fromLatin1("MemoryAllocation:%1").arg(type.detailType()); + break; + case QQmlProfilerDefinitions::DebugMessage: + displayName = QString::fromLatin1("DebugMessage:%1").arg(type.detailType()); + break; + case QQmlProfilerDefinitions::MaximumMessage: { + const QQmlProfilerEventLocation eventLocation = type.location(); + // generate hash + if (eventLocation.filename().isEmpty()) { + displayName = QString::fromLatin1("Unknown"); + } else { + const QString filePath = QUrl(eventLocation.filename()).path(); + displayName = filePath.midRef( + filePath.lastIndexOf(QLatin1Char('/')) + 1) + + QLatin1Char(':') + QString::number(eventLocation.line()); + } break; } - - QString eventHashStr = QString::fromLatin1("Input:%1").arg(eventType); - - QmlRangeEventData *newEvent; - if (d->eventDescriptions.contains(eventHashStr)) { - newEvent = d->eventDescriptions[eventHashStr]; - } else { - newEvent = new QmlRangeEventData(QString(), eventType, eventHashStr, QQmlEventLocation(), - QString(), QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::MaximumRangeType); - d->eventDescriptions.insert(eventHashStr, newEvent); } - d->startInstanceList.append(QmlRangeEventStartInstance(time, -1, type, a, b, newEvent)); + newType.setDisplayName(displayName); + d->eventTypes.append(newType); } void QmlProfilerData::computeQmlTime() { // compute levels - QHash<int, qint64> endtimesPerLevel; - int minimumLevel = 1; - int level = minimumLevel; - - for (int i = 0; i < d->startInstanceList.count(); i++) { - qint64 st = d->startInstanceList.at(i).startTime; + qint64 level0Start = -1; + int level = 0; - if (d->startInstanceList.at(i).data->rangeType == QQmlProfilerDefinitions::Painting) { + for (const QQmlProfilerEvent &event : qAsConst(d->events)) { + const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex()); + if (type.message() != QQmlProfilerDefinitions::MaximumMessage) continue; - } - - // general level - if (endtimesPerLevel.value(level) > st) { - level++; - } else { - while (level > minimumLevel && endtimesPerLevel[level-1] <= st) - level--; - } - endtimesPerLevel[level] = st + d->startInstanceList.at(i).duration; - if (level == minimumLevel) { - d->qmlMeasuredTime += d->startInstanceList.at(i).duration; + switch (type.rangeType()) { + case QQmlProfilerDefinitions::Compiling: + case QQmlProfilerDefinitions::Creating: + case QQmlProfilerDefinitions::Binding: + case QQmlProfilerDefinitions::HandlingSignal: + case QQmlProfilerDefinitions::Javascript: + switch (event.rangeStage()) { + case QQmlProfilerDefinitions::RangeStart: + if (level++ == 0) + level0Start = event.timestamp(); + break; + case QQmlProfilerDefinitions::RangeEnd: + if (--level == 0) + d->qmlMeasuredTime += event.timestamp() - level0Start; + break; + default: + break; + } + break; + default: + break; } } } -bool compareStartTimes(const QmlRangeEventStartInstance &t1, const QmlRangeEventStartInstance &t2) +bool compareStartTimes(const QQmlProfilerEvent &t1, const QQmlProfilerEvent &t2) { - return t1.startTime < t2.startTime; + return t1.timestamp() < t2.timestamp(); } void QmlProfilerData::sortStartTimes() { - if (d->startInstanceList.count() < 2) + if (d->events.count() < 2) return; // assuming startTimes is partially sorted // identify blocks of events and sort them with quicksort - QVector<QmlRangeEventStartInstance>::iterator itFrom = d->startInstanceList.end() - 2; - QVector<QmlRangeEventStartInstance>::iterator itTo = d->startInstanceList.end() - 1; + QVector<QQmlProfilerEvent>::iterator itFrom = d->events.end() - 2; + QVector<QQmlProfilerEvent>::iterator itTo = d->events.end() - 1; - while (itFrom != d->startInstanceList.begin() && itTo != d->startInstanceList.begin()) { + while (itFrom != d->events.begin() && itTo != d->events.begin()) { // find block to sort - while ( itFrom != d->startInstanceList.begin() - && itTo->startTime > itFrom->startTime ) { + while (itFrom != d->events.begin() && itTo->timestamp() > itFrom->timestamp()) { --itTo; itFrom = itTo - 1; } // if we're at the end of the list - if (itFrom == d->startInstanceList.begin()) + if (itFrom == d->events.begin()) break; // find block length - while ( itFrom != d->startInstanceList.begin() - && itTo->startTime <= itFrom->startTime ) + while (itFrom != d->events.begin() && itTo->timestamp() <= itFrom->timestamp()) --itFrom; - if (itTo->startTime <= itFrom->startTime) + if (itTo->timestamp() <= itFrom->timestamp()) std::sort(itFrom, itTo + 1, compareStartTimes); else std::sort(itFrom + 1, itTo + 1, compareStartTimes); @@ -479,9 +321,88 @@ void QmlProfilerData::complete() bool QmlProfilerData::isEmpty() const { - return d->startInstanceList.isEmpty(); + return d->events.isEmpty(); } +struct StreamWriter { + QString error; + + StreamWriter(const QString &filename) + { + if (!filename.isEmpty()) { + file.setFileName(filename); + if (!file.open(QIODevice::WriteOnly)) { + error = QmlProfilerData::tr("Could not open %1 for writing").arg(filename); + return; + } + } else { + if (!file.open(stdout, QIODevice::WriteOnly)) { + error = QmlProfilerData::tr("Could not open stdout for writing"); + return; + } + } + + stream.setDevice(&file); + stream.setAutoFormatting(true); + stream.writeStartDocument(); + writeStartElement("trace"); + } + + ~StreamWriter() { + writeEndElement(); + stream.writeEndDocument(); + file.close(); + } + + template<typename Number> + void writeAttribute(const char *name, Number number) + { + stream.writeAttribute(QLatin1String(name), QString::number(number)); + } + + void writeAttribute(const char *name, const char *value) + { + stream.writeAttribute(QLatin1String(name), QLatin1String(value)); + } + + void writeAttribute(const char *name, const QQmlProfilerEvent &event, int i, bool printZero = true) + { + const qint64 number = event.number<qint64>(i); + if (printZero || number != 0) + writeAttribute(name, number); + } + + template<typename Number> + void writeTextElement(const char *name, Number number) + { + writeTextElement(name, QString::number(number)); + } + + void writeTextElement(const char *name, const char *value) + { + stream.writeTextElement(QLatin1String(name), QLatin1String(value)); + } + + void writeTextElement(const char *name, const QString &value) + { + stream.writeTextElement(QLatin1String(name), value); + } + + void writeStartElement(const char *name) + { + stream.writeStartElement(QLatin1String(name)); + } + + void writeEndElement() + { + stream.writeEndElement(); + } + +private: + QFile file; + QXmlStreamWriter stream; +}; + bool QmlProfilerData::save(const QString &filename) { if (isEmpty()) { @@ -489,157 +410,178 @@ bool QmlProfilerData::save(const QString &filename) return false; } - QFile file; - if (!filename.isEmpty()) { - file.setFileName(filename); - if (!file.open(QIODevice::WriteOnly)) { - emit error(tr("Could not open %1 for writing").arg(filename)); - return false; - } - } else { - if (!file.open(stdout, QIODevice::WriteOnly)) { - emit error(tr("Could not open stdout for writing")); - return false; - } + StreamWriter stream(filename); + if (!stream.error.isEmpty()) { + emit error(stream.error); + return false; } - QXmlStreamWriter stream(&file); - stream.setAutoFormatting(true); - stream.writeStartDocument(); - - stream.writeStartElement(QStringLiteral("trace")); - stream.writeAttribute(QStringLiteral("version"), PROFILER_FILE_VERSION); - - stream.writeAttribute(QStringLiteral("traceStart"), QString::number(traceStartTime())); - stream.writeAttribute(QStringLiteral("traceEnd"), QString::number(traceEndTime())); - - stream.writeStartElement(QStringLiteral("eventData")); - stream.writeAttribute(QStringLiteral("totalTime"), QString::number(d->qmlMeasuredTime)); - - const auto eventDescriptionsKeys = d->eventDescriptions.keys(); - for (auto it = d->eventDescriptions.cbegin(), end = d->eventDescriptions.cend(); - it != end; ++it) { - const QmlRangeEventData *eventData = it.value(); - stream.writeStartElement(QStringLiteral("event")); - stream.writeAttribute(QStringLiteral("index"), QString::number( - eventDescriptionsKeys.indexOf(eventData->eventHashStr))); - if (!eventData->displayName.isEmpty()) - stream.writeTextElement(QStringLiteral("displayname"), eventData->displayName); - if (eventData->rangeType != QQmlProfilerDefinitions::MaximumRangeType) - stream.writeTextElement(QStringLiteral("type"), - qmlRangeTypeAsString(eventData->rangeType)); - else - stream.writeTextElement(QStringLiteral("type"), - qmlMessageAsString(eventData->message)); - if (!eventData->location.filename.isEmpty()) - stream.writeTextElement(QStringLiteral("filename"), eventData->location.filename); - if (eventData->location.line >= 0) - stream.writeTextElement(QStringLiteral("line"), - QString::number(eventData->location.line)); - if (eventData->location.column >= 0) - stream.writeTextElement(QStringLiteral("column"), - QString::number(eventData->location.column)); - if (!eventData->details.isEmpty()) - stream.writeTextElement(QStringLiteral("details"), eventData->details); - if (eventData->rangeType == QQmlProfilerDefinitions::Binding) - stream.writeTextElement(QStringLiteral("bindingType"), - QString::number((int)eventData->detailType)); - else if (eventData->message == QQmlProfilerDefinitions::Event) { - switch (eventData->detailType) { + stream.writeAttribute("version", PROFILER_FILE_VERSION); + stream.writeAttribute("traceStart", traceStartTime()); + stream.writeAttribute("traceEnd", traceEndTime()); + + stream.writeStartElement("eventData"); + stream.writeAttribute("totalTime", d->qmlMeasuredTime); + + for (int typeIndex = 0, end = d->eventTypes.size(); typeIndex < end; ++typeIndex) { + const QQmlProfilerEventType &eventData = d->eventTypes.at(typeIndex); + stream.writeStartElement("event"); + stream.writeAttribute("index", typeIndex); + if (!eventData.displayName().isEmpty()) + stream.writeTextElement("displayname", eventData.displayName()); + + stream.writeTextElement("type", + eventData.rangeType() == QQmlProfilerDefinitions::MaximumRangeType + ? qmlMessageAsString(eventData.message()) + : qmlRangeTypeAsString(eventData.rangeType())); + + const QQmlProfilerEventLocation location = eventData.location(); + if (!location.filename().isEmpty()) + stream.writeTextElement("filename", location.filename()); + if (location.line() >= 0) + stream.writeTextElement("line", location.line()); + if (location.column() >= 0) + stream.writeTextElement("column", location.column()); + if (!eventData.data().isEmpty()) + stream.writeTextElement("details", eventData.data()); + if (eventData.rangeType() == QQmlProfilerDefinitions::Binding) + stream.writeTextElement("bindingType", eventData.detailType()); + else if (eventData.message() == QQmlProfilerDefinitions::Event) { + switch (eventData.detailType()) { case QQmlProfilerDefinitions::AnimationFrame: - stream.writeTextElement(QStringLiteral("animationFrame"), - QString::number((int)eventData->detailType)); + stream.writeTextElement("animationFrame", eventData.detailType()); break; case QQmlProfilerDefinitions::Key: - stream.writeTextElement(QStringLiteral("keyEvent"), - QString::number((int)eventData->detailType)); + stream.writeTextElement("keyEvent", eventData.detailType()); break; case QQmlProfilerDefinitions::Mouse: - stream.writeTextElement(QStringLiteral("mouseEvent"), - QString::number((int)eventData->detailType)); + stream.writeTextElement("mouseEvent", eventData.detailType()); break; } - } else if (eventData->message == QQmlProfilerDefinitions::PixmapCacheEvent) - stream.writeTextElement(QStringLiteral("cacheEventType"), - QString::number((int)eventData->detailType)); - else if (eventData->message == QQmlProfilerDefinitions::SceneGraphFrame) - stream.writeTextElement(QStringLiteral("sgEventType"), - QString::number((int)eventData->detailType)); - else if (eventData->message == QQmlProfilerDefinitions::MemoryAllocation) - stream.writeTextElement(QStringLiteral("memoryEventType"), - QString::number((int)eventData->detailType)); + } else if (eventData.message() == QQmlProfilerDefinitions::PixmapCacheEvent) + stream.writeTextElement("cacheEventType", eventData.detailType()); + else if (eventData.message() == QQmlProfilerDefinitions::SceneGraphFrame) + stream.writeTextElement("sgEventType", eventData.detailType()); + else if (eventData.message() == QQmlProfilerDefinitions::MemoryAllocation) + stream.writeTextElement("memoryEventType", eventData.detailType()); stream.writeEndElement(); } stream.writeEndElement(); // eventData - stream.writeStartElement(QStringLiteral("profilerDataModel")); - for (const QmlRangeEventStartInstance &event : qAsConst(d->startInstanceList)) { - stream.writeStartElement(QStringLiteral("range")); - stream.writeAttribute(QStringLiteral("startTime"), QString::number(event.startTime)); - if (event.duration >= 0) - stream.writeAttribute(QStringLiteral("duration"), - QString::number(event.duration)); - stream.writeAttribute(QStringLiteral("eventIndex"), QString::number( - eventDescriptionsKeys.indexOf(event.data->eventHashStr))); - if (event.data->message == QQmlProfilerDefinitions::Event) { - if (event.data->detailType == QQmlProfilerDefinitions::AnimationFrame) { + stream.writeStartElement("profilerDataModel"); + + auto sendEvent = [&](const QQmlProfilerEvent &event, qint64 duration = 0) { + const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex()); + stream.writeStartElement("range"); + stream.writeAttribute("startTime", event.timestamp()); + if (duration != 0) + stream.writeAttribute("duration", duration); + stream.writeAttribute("eventIndex", event.typeIndex()); + if (type.message() == QQmlProfilerDefinitions::Event) { + if (type.detailType() == QQmlProfilerDefinitions::AnimationFrame) { // special: animation frame - stream.writeAttribute(QStringLiteral("framerate"), QString::number(event.frameRate)); - stream.writeAttribute(QStringLiteral("animationcount"), - QString::number(event.animationCount)); - stream.writeAttribute(QStringLiteral("thread"), QString::number(event.threadId)); - } else if (event.data->detailType == QQmlProfilerDefinitions::Key || - event.data->detailType == QQmlProfilerDefinitions::Mouse) { + stream.writeAttribute("framerate", event, 0); + stream.writeAttribute("animationcount", event, 1); + stream.writeAttribute("thread", event, 2); + } else if (type.detailType() == QQmlProfilerDefinitions::Key || + type.detailType() == QQmlProfilerDefinitions::Mouse) { // numerical value here, to keep the format a bit more compact - stream.writeAttribute(QStringLiteral("type"), - QString::number(event.inputType)); - stream.writeAttribute(QStringLiteral("data1"), - QString::number(event.inputA)); - stream.writeAttribute(QStringLiteral("data2"), - QString::number(event.inputB)); + stream.writeAttribute("type", event, 0); + stream.writeAttribute("data1", event, 1); + stream.writeAttribute("data2", event, 2); } - } else if (event.data->message == QQmlProfilerDefinitions::PixmapCacheEvent) { + } else if (type.message() == QQmlProfilerDefinitions::PixmapCacheEvent) { // special: pixmap cache event - if (event.data->detailType == QQmlProfilerDefinitions::PixmapSizeKnown) { - stream.writeAttribute(QStringLiteral("width"), - QString::number(event.numericData1)); - stream.writeAttribute(QStringLiteral("height"), - QString::number(event.numericData2)); - } else if (event.data->detailType == - QQmlProfilerDefinitions::PixmapReferenceCountChanged || - event.data->detailType == - QQmlProfilerDefinitions::PixmapCacheCountChanged) { - stream.writeAttribute(QStringLiteral("refCount"), - QString::number(event.numericData1)); + if (type.detailType() == QQmlProfilerDefinitions::PixmapSizeKnown) { + stream.writeAttribute("width", event, 0); + stream.writeAttribute("height", event, 1); + } else if (type.detailType() == QQmlProfilerDefinitions::PixmapReferenceCountChanged + || type.detailType() == QQmlProfilerDefinitions::PixmapCacheCountChanged) { + stream.writeAttribute("refCount", event, 1); } - } else if (event.data->message == QQmlProfilerDefinitions::SceneGraphFrame) { - // special: scenegraph frame events - if (event.numericData1 > 0) - stream.writeAttribute(QStringLiteral("timing1"), - QString::number(event.numericData1)); - if (event.numericData2 > 0) - stream.writeAttribute(QStringLiteral("timing2"), - QString::number(event.numericData2)); - if (event.numericData3 > 0) - stream.writeAttribute(QStringLiteral("timing3"), - QString::number(event.numericData3)); - if (event.numericData4 > 0) - stream.writeAttribute(QStringLiteral("timing4"), - QString::number(event.numericData4)); - if (event.numericData5 > 0) - stream.writeAttribute(QStringLiteral("timing5"), - QString::number(event.numericData5)); - } else if (event.data->message == QQmlProfilerDefinitions::MemoryAllocation) { - stream.writeAttribute(QStringLiteral("amount"), QString::number(event.numericData1)); + } else if (type.message() == QQmlProfilerDefinitions::SceneGraphFrame) { + stream.writeAttribute("timing1", event, 0, false); + stream.writeAttribute("timing2", event, 1, false); + stream.writeAttribute("timing3", event, 2, false); + stream.writeAttribute("timing4", event, 3, false); + stream.writeAttribute("timing5", event, 4, false); + } else if (type.message() == QQmlProfilerDefinitions::MemoryAllocation) { + stream.writeAttribute("amount", event, 0); } stream.writeEndElement(); + }; + + QQueue<QQmlProfilerEvent> pointEvents; + QQueue<QQmlProfilerEvent> rangeStarts[QQmlProfilerDefinitions::MaximumRangeType]; + QStack<qint64> rangeEnds[QQmlProfilerDefinitions::MaximumRangeType]; + int level = 0; + + auto sendPending = [&]() { + forever { + int minimum = QQmlProfilerDefinitions::MaximumRangeType; + qint64 minimumTime = std::numeric_limits<qint64>::max(); + for (int i = 0; i < QQmlProfilerDefinitions::MaximumRangeType; ++i) { + const QQueue<QQmlProfilerEvent> &starts = rangeStarts[i]; + if (starts.isEmpty()) + continue; + if (starts.head().timestamp() < minimumTime) { + minimumTime = starts.head().timestamp(); + minimum = i; + } + } + if (minimum == QQmlProfilerDefinitions::MaximumRangeType) + break; + + while (!pointEvents.isEmpty() && pointEvents.front().timestamp() < minimumTime) + sendEvent(pointEvents.dequeue()); + + sendEvent(rangeStarts[minimum].dequeue(), + rangeEnds[minimum].pop() - minimumTime); + } + }; + + for (const QQmlProfilerEvent &event : qAsConst(d->events)) { + const QQmlProfilerEventType &type = d->eventTypes.at(event.typeIndex()); + + if (type.rangeType() != QQmlProfilerDefinitions::MaximumRangeType) { + QQueue<QQmlProfilerEvent> &starts = rangeStarts[type.rangeType()]; + switch (event.rangeStage()) { + case QQmlProfilerDefinitions::RangeStart: { + ++level; + starts.enqueue(event); + break; + } + case QQmlProfilerDefinitions::RangeEnd: { + QStack<qint64> &ends = rangeEnds[type.rangeType()]; + if (starts.length() > ends.length()) { + ends.push(event.timestamp()); + if (--level == 0) + sendPending(); + } + break; + } + default: + break; + } + } else { + if (level == 0) + sendEvent(event); + else + pointEvents.enqueue(event); + } } - stream.writeEndElement(); // profilerDataModel - stream.writeEndElement(); // trace - stream.writeEndDocument(); + for (int i = 0; i < QQmlProfilerDefinitions::MaximumRangeType; ++i) { + while (rangeEnds[i].length() < rangeStarts[i].length()) { + rangeEnds[i].push(d->traceEndTime); + --level; + } + } + + sendPending(); + + stream.writeEndElement(); // profilerDataModel - file.close(); return true; } @@ -683,4 +625,9 @@ void QmlProfilerData::setState(QmlProfilerData::State state) return; } +int QmlProfilerData::numLoadedEventTypes() const +{ + return d->eventTypes.length(); +} + #include "moc_qmlprofilerdata.cpp" diff --git a/tools/qmlprofiler/qmlprofilerdata.h b/tools/qmlprofiler/qmlprofilerdata.h index 00ef037071..2be0b73aee 100644 --- a/tools/qmlprofiler/qmlprofilerdata.h +++ b/tools/qmlprofiler/qmlprofilerdata.h @@ -29,13 +29,14 @@ #ifndef QMLPROFILERDATA_H #define QMLPROFILERDATA_H -#include <private/qqmleventlocation_p.h> #include <private/qqmlprofilerdefinitions_p.h> +#include <private/qqmlprofilereventlocation_p.h> +#include <private/qqmlprofilereventreceiver_p.h> #include <QObject> class QmlProfilerDataPrivate; -class QmlProfilerData : public QObject +class QmlProfilerData : public QQmlProfilerEventReceiver { Q_OBJECT public: @@ -49,7 +50,11 @@ public: explicit QmlProfilerData(QObject *parent = 0); ~QmlProfilerData(); - static QString getHashStringForQmlEvent(const QQmlEventLocation &location, int eventType); + int numLoadedEventTypes() const override; + void addEventType(const QQmlProfilerEventType &type) override; + void addEvent(const QQmlProfilerEvent &event) override; + + static QString getHashStringForQmlEvent(const QQmlProfilerEventLocation &location, int eventType); static QString qmlRangeTypeAsString(QQmlProfilerDefinitions::RangeType type); static QString qmlMessageAsString(QQmlProfilerDefinitions::Message type); @@ -61,18 +66,6 @@ public: void clear(); void setTraceEndTime(qint64 time); void setTraceStartTime(qint64 time); - void addQmlEvent(QQmlProfilerDefinitions::RangeType type, - QQmlProfilerDefinitions::BindingType bindingType, - qint64 startTime, qint64 duration, const QStringList &data, - const QQmlEventLocation &location); - void addFrameEvent(qint64 time, int framerate, int animationcount, int threadId); - void addSceneGraphFrameEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, qint64 time, - qint64 numericData1, qint64 numericData2, qint64 numericData3, - qint64 numericData4, qint64 numericData5); - void addPixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, qint64 time, - const QString &location, int numericData1, int numericData2); - void addMemoryEvent(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 size); - void addInputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b); void complete(); bool save(const QString &filename); |