Add a stack-based object creation profiler
authorUlf Hermann <ulf.hermann@digia.com>
Wed, 27 Nov 2013 11:58:13 +0000 (12:58 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 29 Nov 2013 10:35:16 +0000 (11:35 +0100)
The simple instantiate-in-context way of profiling object
creation doesn't work anymore because the VME's contexts don't
necessarily map to C++ contexts anymore. The new profiler
introduces two stacks of contexts, one for currently running
ranges (such as components) and one for ranges that will be
revived later to profile componentComplete() and similar things.

Task-number: QTCREATORBUG-10631

Change-Id: Idf19b2adf062bc9c185b3bb5ff5229381f577645
Reviewed-by: Ulf Hermann <ulf.hermann@digia.com>
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/debugger/qqmlprofilerservice.cpp
src/qml/debugger/qqmlprofilerservice_p.h

index 0ba939c..9daa6ac 100644 (file)
@@ -425,4 +425,128 @@ void QQmlProfilerService::messageReceived(const QByteArray &message)
     m_initializeCondition.wakeAll();
 }
 
+void QQmlVmeProfiler::Data::clear()
+{
+    url = QUrl();
+    line = 0;
+    column = 0;
+    typeName = QString();
+}
+
+void QQmlVmeProfiler::start(const QUrl &url, int line, int column, const QString &typeName)
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    if (enabled) {
+        switchRange();
+        updateLocation(url, line, column);
+        updateTypeName(typeName);
+    }
+}
+
+void QQmlVmeProfiler::start()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    if (enabled) {
+        currentRange.clear();
+        switchRange();
+    }
+}
+
+void QQmlVmeProfiler::switchRange()
+{
+    if (running)
+        QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+    else
+        running = true;
+    QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating);
+}
+
+void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column)
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update location on stopped profiler");
+    if (enabled && running) {
+        currentRange.url = url;
+        currentRange.line = line;
+        currentRange.column = column;
+        QQmlProfilerService::instance->rangeLocation(
+                QQmlProfilerService::Creating, url, line, column);
+    }
+}
+
+void QQmlVmeProfiler::updateTypeName(const QString &typeName)
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update typeName on stopped profiler");
+    if (enabled && running) {
+        currentRange.typeName = typeName;
+        QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
+    }
+}
+
+void QQmlVmeProfiler::pop()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(ranges.count() > 0, Q_FUNC_INFO, "trying to pop an invalid profiler");
+    if (enabled && ranges.count() > 0) {
+        start();
+        currentRange = ranges.pop();
+        QQmlProfilerService::instance->rangeLocation(
+                QQmlProfilerService::Creating, currentRange.url, currentRange.line, currentRange.column);
+        QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, currentRange.typeName);
+    }
+}
+
+void QQmlVmeProfiler::push()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler");
+    if (enabled && running)
+        ranges.push(currentRange);
+}
+
+void QQmlVmeProfiler::clear()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    if (enabled) {
+        stop();
+        ranges.clear();
+        for (int i = 0; i < backgroundRanges.count(); ++i) {
+            QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+        }
+        backgroundRanges.clear();
+    }
+}
+
+void QQmlVmeProfiler::stop()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    if (enabled && running) {
+        QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+        currentRange.clear();
+        running = false;
+    }
+}
+
+void QQmlVmeProfiler::background()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler to the background.");
+    if (enabled && running) {
+        backgroundRanges.push(currentRange);
+        running = false;
+    }
+}
+
+void QQmlVmeProfiler::foreground()
+{
+    Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+    Q_ASSERT_X(backgroundRanges.count() > 0, Q_FUNC_INFO, "trying to foreground stopped profiler.");
+    if (enabled && backgroundRanges.count() > 0) {
+        stop();
+        currentRange = backgroundRanges.pop();
+        running = true;
+    }
+}
+
 QT_END_NAMESPACE
index 52a1dea..c2e9eb4 100644 (file)
@@ -225,6 +225,7 @@ private:
 
     friend struct QQmlBindingProfiler;
     friend struct QQmlHandlingSignalProfiler;
+    friend struct QQmlVmeProfiler;
     friend struct QQmlCompilingProfiler;
     friend struct QQmlPixmapProfiler;
 };
@@ -298,6 +299,54 @@ struct QQmlCompilingProfiler {
     bool enabled;
 };
 
+struct QQmlVmeProfiler {
+public:
+    const bool enabled;
+
+    struct Data {
+        Data() : line(0), column(0) {}
+        QUrl url;
+        int line;
+        int column;
+        QString typeName;
+        void clear();
+    };
+
+    QQmlVmeProfiler() :
+        enabled(QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false),
+        running(false)
+    {}
+
+    ~QQmlVmeProfiler()
+    {
+        if (enabled)
+            clear();
+    }
+
+    void clear();
+
+    void start(const QUrl &url, int line, int column, const QString &typeName);
+    void start();
+    void stop();
+
+    void updateLocation(const QUrl &url, int line, int column);
+    void updateTypeName(const QString &typeName);
+
+    void pop();
+    void push();
+
+    void background();
+    void foreground();
+
+private:
+    void switchRange();
+
+    Data currentRange;
+    QStack<Data> ranges;
+    QStack<Data> backgroundRanges;
+    bool running;
+};
+
 struct QQmlPixmapProfiler {
     QQmlPixmapProfiler() {
         QQmlProfilerService *instance = QQmlProfilerService::instance;