From 9424383e6d0ea1dd02dcf1070259e21550da692a Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 24 Jan 2014 13:24:19 +0100 Subject: Move QtQuick profiling to own profiler adapter The QtQuick parts of the QML profiler service thus become a proper global profiler which can be independently enabled and disabled. Change-Id: Ifad03801cab2be66a264fc46fdebdae582fcc99b Reviewed-by: Kai Koehne --- src/qml/debugger/qqmlprofilerservice.cpp | 10 - src/qml/debugger/qqmlprofilerservice_p.h | 58 ------ src/quick/items/qquickview.cpp | 12 +- src/quick/qtquick2.cpp | 4 +- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 11 +- src/quick/scenegraph/coreapi/qsgrenderer.cpp | 8 +- src/quick/scenegraph/qsgadaptationlayer.cpp | 6 +- src/quick/scenegraph/qsgrenderloop.cpp | 6 +- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 10 +- src/quick/scenegraph/qsgwindowsrenderloop.cpp | 12 +- src/quick/scenegraph/util/qsgatlastexture.cpp | 6 +- src/quick/scenegraph/util/qsgtexture.cpp | 8 +- src/quick/util/qquickpixmapcache.cpp | 22 +-- src/quick/util/qquickprofiler.cpp | 205 +++++++++++++++++++ src/quick/util/qquickprofiler_p.h | 227 ++++++++++++++++++++++ src/quick/util/util.pri | 6 +- 16 files changed, 490 insertions(+), 121 deletions(-) create mode 100644 src/quick/util/qquickprofiler.cpp create mode 100644 src/quick/util/qquickprofiler_p.h diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index 56d6cf14c5..e4620a282a 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -134,22 +134,12 @@ void QQmlProfilerData::toByteArrays(QList &messages) const } } -void QQmlProfilerService::animationTimerCallback(qint64 delta) -{ - Q_QML_PROFILE(animationFrame(delta)); -} - QQmlProfilerService::QQmlProfilerService() : QQmlConfigurableDebugService(QStringLiteral("CanvasFrameRate"), 1) { m_timer.start(); QMutexLocker lock(configMutex()); - // TODO: This is problematic as the service could be enabled at a later point in time. In that - // case we might miss the callback registration. - if (state() == Enabled) - QUnifiedTimer::instance()->registerProfilerCallback(&animationTimerCallback); - // If there is no debug server it doesn't matter as we'll never get enabled anyway. if (QQmlDebugServer::instance() != 0) moveToThread(QQmlDebugServer::instance()->thread()); diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 4549814a02..a5d85a76e6 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -58,8 +58,6 @@ #include "qqmlabstractprofileradapter_p.h" #include -// this contains QUnifiedTimer -#include #include #include @@ -78,11 +76,6 @@ #define Q_QML_PROFILE(Method)\ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerService::Method) -#define Q_QML_SG_PROFILE2(Type1, Type2, Params)\ - Q_QML_PROFILE_IF_ENABLED((QQmlProfilerService::sceneGraphFrame Params)) - -#define Q_QML_SG_PROFILE1(Type, Params) Q_QML_SG_PROFILE2(Type, Type, Params) - QT_BEGIN_NAMESPACE // This struct is somewhat dangerous to use: @@ -183,55 +176,6 @@ public: void startProfiling(QQmlEngine *engine); void stopProfiling(QQmlEngine *engine); - template - static void addEvent() - { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << Event, - 1 << DetailType)); - } - - static void animationFrame(qint64 delta) - { - int animCount = QUnifiedTimer::instance()->runningAnimationCount(); - - if (animCount > 0 && delta > 0) { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << Event, - 1 << AnimationFrame, QString(), 0, 0, - 1000 / (int)delta /* trim fps to integer */, - animCount)); - } - } - - template - static void sceneGraphFrame(qint64 value1, qint64 value2 = -1, qint64 value3 = -1, - qint64 value4 = -1, qint64 value5 = -1) - { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << SceneGraphFrame, - 1 << FrameType1 | 1 << FrameType2, - value1, value2, value3, value4, value5)); - } - - template - static void pixmapStateChanged(const QUrl &url) - { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent, - 1 << PixmapState, url)); - } - - static void pixmapLoadingFinished(const QUrl &url, const QSize &size) - { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent, - (1 << PixmapLoadingFinished) | ((size.width() > 0 && size.height() > 0) ? (1 << PixmapSizeKnown) : 0), - url, size.width(), size.height())); - } - - template - static void pixmapCountChanged(const QUrl &url, int count) - { - m_instance->processMessage(QQmlProfilerData(m_instance->timestamp(), 1 << PixmapCacheEvent, - 1 << CountType, url, 0, 0, 0, count)); - } - qint64 timestamp() {return m_timer.nsecsElapsed();} QQmlProfilerService(); @@ -307,8 +251,6 @@ private: m_data.append(message); } - static void animationTimerCallback(qint64 delta); - public: static bool enabled; private: diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 1a3d225995..5c9ecb93dd 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -46,7 +46,7 @@ #include "qquickitem_p.h" #include "qquickitemchangelistener_p.h" -#include +#include #include #include @@ -603,7 +603,7 @@ void QQuickView::resizeEvent(QResizeEvent *e) /*! \reimp */ void QQuickView::keyPressEvent(QKeyEvent *e) { - Q_QML_PROFILE(addEvent()); + Q_QUICK_PROFILE(addEvent()); QQuickWindow::keyPressEvent(e); } @@ -611,7 +611,7 @@ void QQuickView::keyPressEvent(QKeyEvent *e) /*! \reimp */ void QQuickView::keyReleaseEvent(QKeyEvent *e) { - Q_QML_PROFILE(addEvent()); + Q_QUICK_PROFILE(addEvent()); QQuickWindow::keyReleaseEvent(e); } @@ -619,7 +619,7 @@ void QQuickView::keyReleaseEvent(QKeyEvent *e) /*! \reimp */ void QQuickView::mouseMoveEvent(QMouseEvent *e) { - Q_QML_PROFILE(addEvent()); + Q_QUICK_PROFILE(addEvent()); QQuickWindow::mouseMoveEvent(e); } @@ -627,7 +627,7 @@ void QQuickView::mouseMoveEvent(QMouseEvent *e) /*! \reimp */ void QQuickView::mousePressEvent(QMouseEvent *e) { - Q_QML_PROFILE(addEvent()); + Q_QUICK_PROFILE(addEvent()); QQuickWindow::mousePressEvent(e); } @@ -635,7 +635,7 @@ void QQuickView::mousePressEvent(QMouseEvent *e) /*! \reimp */ void QQuickView::mouseReleaseEvent(QMouseEvent *e) { - Q_QML_PROFILE(addEvent()); + Q_QUICK_PROFILE(addEvent()); QQuickWindow::mouseReleaseEvent(e); } diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index ee5034c108..9d2a0b0f75 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -189,9 +190,10 @@ void QQmlQtQuick2Module::defineModule() QQuickValueTypes::registerValueTypes(); - if (QQmlEngineDebugService::isDebuggingEnabled()) { + if (QQmlDebugService::isDebuggingEnabled()) { QQmlEngineDebugService::instance()->setStatesDelegate( new QQmlQtQuick2DebugStatesDelegate); + QQuickProfiler::initialize(); } } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 8dfa0d2c2c..f121e16523 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -48,12 +48,13 @@ #include #include +#include #include #include #include -#include +#include #include @@ -133,7 +134,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) return shader; #ifndef QSG_NO_RENDER_TIMING - if (qsg_render_timing || QQmlProfilerService::enabled) + if (qsg_render_timing || QQuickProfiler::enabled) qsg_renderer_timer.start(); #endif @@ -176,7 +177,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) if (qsg_render_timing) qDebug(" - compiling material: %dms", (int) qsg_renderer_timer.elapsed()); - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphContextFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphContextFrame, ( qsg_renderer_timer.nsecsElapsed())); #endif @@ -192,7 +193,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate return shader; #ifndef QSG_NO_RENDER_TIMING - if (qsg_render_timing || QQmlProfilerService::enabled) + if (qsg_render_timing || QQuickProfiler::enabled) qsg_renderer_timer.start(); #endif @@ -212,7 +213,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate if (qsg_render_timing) qDebug(" - compiling material: %dms", (int) qsg_renderer_timer.elapsed()); - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphContextFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphContextFrame, ( qsg_renderer_timer.nsecsElapsed())); #endif diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index 047891e17c..cc8793c0cf 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -54,7 +54,7 @@ #include -#include +#include QT_BEGIN_NAMESPACE @@ -227,7 +227,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) #ifndef QSG_NO_RENDER_TIMING - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) frameTimer.start(); qint64 bindTime = 0; @@ -287,7 +287,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) int(renderTime / 1000000)); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphRendererFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRendererFrame, ( preprocessTime, updatePassTime - preprocessTime, bindTime - updatePassTime, @@ -375,7 +375,7 @@ void QSGRenderer::preprocess() } #ifndef QSG_NO_RENDER_TIMING - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) preprocessTime = frameTimer.nsecsElapsed(); #endif diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index aa678b34a6..17f4ba1243 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -48,7 +48,7 @@ #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -164,7 +164,7 @@ void QSGDistanceFieldGlyphCache::update() return; #ifndef QSG_NO_RENDER_TIMING - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) qsg_render_timer.start(); #endif @@ -196,7 +196,7 @@ void QSGDistanceFieldGlyphCache::update() (int) qsg_render_timer.elapsed()); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphAdaptationLayerFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphAdaptationLayerFrame, ( count, renderTime, qsg_render_timer.nsecsElapsed() - renderTime)); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 7b6e6d55ee..4e8fa67869 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -57,7 +57,7 @@ #include #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -304,7 +304,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) qint64 renderTime = 0, syncTime = 0; QElapsedTimer renderTimer; - bool profileFrames = qsg_render_timing() || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing() || QQuickProfiler::enabled; if (profileFrames) renderTimer.start(); @@ -343,7 +343,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) lastFrameTime = QTime::currentTime(); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphRenderLoopFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, ( syncTime, renderTime, swapTime)); diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 7cc4293f6c..ffc6d31aa7 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -58,7 +58,7 @@ #include "qsgthreadedrenderloop_p.h" #include -#include +#include /* Overall design: @@ -539,7 +539,7 @@ void QSGRenderThread::sync() void QSGRenderThread::syncAndRender() { #ifndef QSG_NO_RENDER_TIMING - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) { sinceLastTime = threadTimer.nsecsElapsed(); threadTimer.start(); @@ -609,7 +609,7 @@ void QSGRenderThread::syncAndRender() int((renderTime - syncTime)/1000000), int(threadTimer.elapsed() - renderTime/1000000)); - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphRenderLoopFrame, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphRenderLoopFrame, ( syncTime, renderTime - syncTime, threadTimer.nsecsElapsed() - renderTime)); @@ -1081,7 +1081,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w) qint64 polishTime = 0; qint64 waitTime = 0; qint64 syncTime = 0; - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) timer.start(); #endif @@ -1140,7 +1140,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w) int((syncTime - waitTime)/1000000), int((timer.nsecsElapsed() - syncTime)/1000000)); - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphPolishAndSync, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphPolishAndSync, ( polishTime, waitTime - polishTime, syncTime - waitTime, diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 63e3e958f6..995d80bb82 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -51,7 +51,7 @@ #include -#include +#include QT_BEGIN_NAMESPACE @@ -69,7 +69,7 @@ static QElapsedTimer qsg_debug_timer; #ifndef QSG_NO_RENDER_TIMING static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty(); static QElapsedTimer qsg_render_timer; -#define QSG_RENDER_TIMING_SAMPLE(sampleName) qint64 sampleName = 0; if (qsg_render_timing || QQmlProfilerService::enabled) sampleName = qsg_render_timer.nsecsElapsed() +#define QSG_RENDER_TIMING_SAMPLE(sampleName) qint64 sampleName = 0; if (qsg_render_timing || QQuickProfiler::enabled) sampleName = qsg_render_timer.nsecsElapsed() #else #define QSG_RENDER_TIMING_SAMPLE(sampleName) #endif @@ -202,7 +202,7 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window) int((time_current - time_created)/1000000), int((qsg_render_timer.nsecsElapsed() - time_current)/1000000)); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphWindowsRenderShow, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphWindowsRenderShow, ( time_created - time_start, time_current - time_created, qsg_render_timer.nsecsElapsed() - time_current)); @@ -404,7 +404,7 @@ void QSGWindowsRenderLoop::render() qDebug("WindowsRenderLoop: animations=%d ms", int((qsg_render_timer.nsecsElapsed() - time_start)/1000000)); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphWindowsAnimations, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphWindowsAnimations, ( qsg_render_timer.nsecsElapsed() - time_start)); #endif @@ -468,8 +468,8 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window) int((time_swapped - time_rendered)/1000000)); } - Q_QML_SG_PROFILE2(QQmlProfilerService::SceneGraphWindowsPolishFrame, - QQmlProfilerService::SceneGraphRenderLoopFrame, ( + Q_QUICK_SG_PROFILE2(QQuickProfiler::SceneGraphWindowsPolishFrame, + QQuickProfiler::SceneGraphRenderLoopFrame, ( time_synced - time_polished, time_rendered - time_synced, time_swapped - time_rendered, diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index e39949253f..fe659c9add 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -52,7 +52,7 @@ #include -#include +#include QT_BEGIN_NAMESPACE @@ -374,7 +374,7 @@ bool Atlas::bind(QSGTexture::Filtering filtering) for (int i=0; i #include #include -#include +#include #include #include #include @@ -613,7 +613,7 @@ void QSGPlainTexture::bind() m_dirty_texture = false; #ifndef QSG_NO_RENDER_TIMING - bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled; + bool profileFrames = qsg_render_timing || QQuickProfiler::enabled; if (profileFrames) qsg_renderer_timer.start(); #endif @@ -628,7 +628,7 @@ void QSGPlainTexture::bind() m_texture_size.width(), m_texture_size.height()); } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphTextureDeletion, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphTextureDeletion, ( qsg_renderer_timer.nsecsElapsed())); #endif } @@ -738,7 +738,7 @@ void QSGPlainTexture::bind() } - Q_QML_SG_PROFILE1(QQmlProfilerService::SceneGraphTexturePrepare, ( + Q_QUICK_SG_PROFILE1(QQuickProfiler::SceneGraphTexturePrepare, ( bindTime, convertTime - bindTime, swizzleTime - convertTime, diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 3bff2bb890..a7f9174219 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -71,7 +71,7 @@ #include #include -#include +#include #define IMAGEREQUEST_MAX_REQUEST_COUNT 8 #define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16 @@ -519,7 +519,7 @@ void QQuickPixmapReader::processJobs() runningJob->loading = true; QUrl url = runningJob->url; - Q_QML_PROFILE(pixmapStateChanged(url)); + Q_QUICK_PROFILE(pixmapStateChanged(url)); QSize requestSize = runningJob->requestSize; locker.unlock(); @@ -897,10 +897,10 @@ bool QQuickPixmapReply::event(QEvent *event) if (data->pixmapStatus == QQuickPixmap::Ready) { data->textureFactory = de->textureFactory; data->implicitSize = de->implicitSize; - Q_QML_PROFILE(pixmapLoadingFinished(data->url, + Q_QUICK_PROFILE(pixmapLoadingFinished(data->url, data->requestSize.width() > 0 ? data->requestSize : data->implicitSize)); } else { - Q_QML_PROFILE(pixmapStateChanged(data->url)); + Q_QUICK_PROFILE(pixmapStateChanged(data->url)); data->errorString = de->errorString; data->removeFromCache(); // We don't continue to cache error'd pixmaps } @@ -926,7 +926,7 @@ int QQuickPixmapData::cost() const void QQuickPixmapData::addref() { ++refCount; - Q_QML_PROFILE(pixmapCountChanged(url, refCount)); + Q_QUICK_PROFILE(pixmapCountChanged(url, refCount)); if (prevUnreferencedPtr) pixmapStore()->referencePixmap(this); } @@ -935,7 +935,7 @@ void QQuickPixmapData::release() { Q_ASSERT(refCount > 0); --refCount; - Q_QML_PROFILE(pixmapCountChanged(url, refCount)); + Q_QUICK_PROFILE(pixmapCountChanged(url, refCount)); if (refCount == 0) { if (reply) { QQuickPixmapReply *cancelReply = reply; @@ -966,7 +966,7 @@ void QQuickPixmapData::addToCache() QQuickPixmapKey key = { &url, &requestSize }; pixmapStore()->m_cache.insert(key, this); inCache = true; - Q_QML_PROFILE(pixmapCountChanged( + Q_QUICK_PROFILE(pixmapCountChanged( url, pixmapStore()->m_cache.count())); } } @@ -975,7 +975,7 @@ void QQuickPixmapData::removeFromCache() { if (inCache) { QQuickPixmapKey key = { &url, &requestSize }; - Q_QML_PROFILE(pixmapCountChanged( + Q_QUICK_PROFILE(pixmapCountChanged( url, pixmapStore()->m_cache.count())); pixmapStore()->m_cache.remove(key); inCache = false; @@ -1239,17 +1239,17 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques if (!(options & QQuickPixmap::Asynchronous)) { bool ok = false; - Q_QML_PROFILE(pixmapStateChanged(url)); + Q_QUICK_PROFILE(pixmapStateChanged(url)); d = createPixmapDataSync(this, engine, url, requestSize, &ok); if (ok) { - Q_QML_PROFILE(pixmapLoadingFinished(url, + Q_QUICK_PROFILE(pixmapLoadingFinished(url, d->requestSize.width() > 0 ? d->requestSize : d->implicitSize)); if (options & QQuickPixmap::Cache) d->addToCache(); return; } if (d) { // loadable, but encountered error while loading - Q_QML_PROFILE(pixmapStateChanged(url)); + Q_QUICK_PROFILE(pixmapStateChanged(url)); return; } } diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp new file mode 100644 index 0000000000..a706fb1e77 --- /dev/null +++ b/src/quick/util/qquickprofiler.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickprofiler_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +// instance will be set, unset in constructor. Allows static methods to be inlined. +QQuickProfiler *QQuickProfiler::s_instance = 0; +bool QQuickProfiler::enabled = false; + +// convert to QByteArrays that can be sent to the debug client +// use of QDataStream can skew results +// (see tst_qqmldebugtrace::trace() benchmark) +void QQuickProfilerData::toByteArrays(QList &messages) const +{ + QByteArray data; + Q_ASSERT_X(((messageType | detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); + for (uint decodedMessageType = 0; (messageType >> decodedMessageType) != 0; ++decodedMessageType) { + if ((messageType & (1 << decodedMessageType)) == 0) + continue; + + for (uint decodedDetailType = 0; (detailType >> decodedDetailType) != 0; ++decodedDetailType) { + if ((detailType & (1 << decodedDetailType)) == 0) + continue; + + //### using QDataStream is relatively expensive + QQmlDebugStream ds(&data, QIODevice::WriteOnly); + ds << time << decodedMessageType << decodedDetailType; + + switch (decodedMessageType) { + case QQuickProfiler::Event: + if (decodedDetailType == (int)QQuickProfiler::AnimationFrame) + ds << framerate << count; + break; + case QQuickProfiler::PixmapCacheEvent: + ds << detailUrl.toString(); + switch (decodedDetailType) { + case QQuickProfiler::PixmapSizeKnown: ds << x << y; break; + case QQuickProfiler::PixmapReferenceCountChanged: ds << count; break; + case QQuickProfiler::PixmapCacheCountChanged: ds << count; break; + default: break; + } + break; + case QQuickProfiler::SceneGraphFrame: + switch (decodedDetailType) { + // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime + case QQuickProfiler::SceneGraphRendererFrame: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; + // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime + case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << (int)subtime_1 << subtime_2 << subtime_3; break; + // ContextFrame: compiling material time + case QQuickProfiler::SceneGraphContextFrame: ds << subtime_1; break; + // RenderLoop: syncTime, renderTime, swapTime + case QQuickProfiler::SceneGraphRenderLoopFrame: ds << subtime_1 << subtime_2 << subtime_3; break; + // TexturePrepare: bind, convert, swizzle, upload, mipmap + case QQuickProfiler::SceneGraphTexturePrepare: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4 << subtime_5; break; + // TextureDeletion: deletionTime + case QQuickProfiler::SceneGraphTextureDeletion: ds << subtime_1; break; + // PolishAndSync: polishTime, waitTime, syncTime, animationsTime, + case QQuickProfiler::SceneGraphPolishAndSync: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; + // WindowsRenderLoop: GL time, make current time, SceneGraph time + case QQuickProfiler::SceneGraphWindowsRenderShow: ds << subtime_1 << subtime_2 << subtime_3; break; + // WindowsAnimations: update time + case QQuickProfiler::SceneGraphWindowsAnimations: ds << subtime_1; break; + // WindowsRenderWindow: polish time; always comes packed after a RenderLoop + case QQuickProfiler::SceneGraphWindowsPolishFrame: ds << subtime_4; break; + default:break; + } + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); + break; + } + messages << data; + data.clear(); + } + } +} + +qint64 QQuickProfiler::sendMessages(qint64 until, QList &messages) +{ + QMutexLocker lock(&m_dataMutex); + while (next < m_data.size() && m_data[next].time <= until) { + m_data[next++].toByteArrays(messages); + } + return next < m_data.size() ? m_data[next].time : -1; +} + +void QQuickProfiler::initialize() +{ + Q_ASSERT(s_instance == 0); + QQmlProfilerService *service = QQmlProfilerService::instance(); + s_instance = new QQuickProfiler(service); + QQmlProfilerService::instance()->addGlobalProfiler(s_instance); +} + +void animationTimerCallback(qint64 delta) +{ + Q_QUICK_PROFILE(animationFrame(delta)); +} + +QQuickProfiler::QQuickProfiler(QQmlProfilerService *service) : + QQmlAbstractProfilerAdapter(service), next(0) +{ + // This is safe because at this point the m_instance isn't initialized, yet. + m_timer.start(); + + // We can always do DirectConnection here as all methods are protected by mutexes + connect(this, SIGNAL(profilingEnabled()), this, SLOT(startProfilingImpl()), + Qt::DirectConnection); + connect(this, SIGNAL(profilingEnabledWhileWaiting()), this, SLOT(startProfilingImpl()), + Qt::DirectConnection); + connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), this, SLOT(setTimer(QElapsedTimer)), + Qt::DirectConnection); + connect(this, SIGNAL(profilingDisabled()), this, SLOT(stopProfilingImpl()), + Qt::DirectConnection); + connect(this, SIGNAL(profilingDisabledWhileWaiting()), this, SLOT(stopProfilingImpl()), + Qt::DirectConnection); + connect(this, SIGNAL(dataRequested()), this, SLOT(reportDataImpl()), + Qt::DirectConnection); + + QUnifiedTimer::instance()->registerProfilerCallback(&animationTimerCallback); +} + +QQuickProfiler::~QQuickProfiler() +{ + QMutexLocker lock(&m_dataMutex); + enabled = false; + s_instance = 0; +} + +void QQuickProfiler::startProfilingImpl() +{ + QMutexLocker lock(&m_dataMutex); + next = 0; + m_data.clear(); + enabled = true; +} + +void QQuickProfiler::stopProfilingImpl() +{ + { + QMutexLocker lock(&m_dataMutex); + enabled = false; + next = 0; + } + service->dataReady(this); +} + +void QQuickProfiler::reportDataImpl() +{ + { + QMutexLocker lock(&m_dataMutex); + next = 0; + } + service->dataReady(this); +} + +void QQuickProfiler::setTimer(const QElapsedTimer &t) +{ + QMutexLocker lock(&m_dataMutex); + m_timer = t; +} + +QT_END_NAMESPACE diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h new file mode 100644 index 0000000000..d5ad0e9285 --- /dev/null +++ b/src/quick/util/qquickprofiler_p.h @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPROFILER_P_H +#define QQUICKPROFILER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qqmlabstractprofileradapter_p.h" +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#define Q_QUICK_PROFILE_IF_ENABLED(Code)\ + if (QQuickProfiler::enabled) {\ + Code;\ + } else\ + (void)0 + +#define Q_QUICK_PROFILE(Method)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::Method) + +#define Q_QUICK_SG_PROFILE2(Type1, Type2, Params)\ + Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::sceneGraphFrame Params)) + +#define Q_QUICK_SG_PROFILE1(Type, Params) Q_QUICK_SG_PROFILE2(Type, Type, Params) + + +// This struct is somewhat dangerous to use: +// You can save values either with 32 or 64 bit precision. toByteArrays will +// guess the precision from messageType. If you state the wrong messageType +// you will get undefined results. +// The messageType is itself a bit field. You can pack multiple messages into +// one object, e.g. RangeStart and RangeLocation. Each one will be read +// independently by toByteArrays. Thus you can only pack messages if their data +// doesn't overlap. Again, it's up to you to figure that out. +struct Q_AUTOTEST_EXPORT QQuickProfilerData +{ + QQuickProfilerData() {} + + QQuickProfilerData(qint64 time, int messageType, int detailType, const QUrl &url, int x = 0, + int y = 0, int framerate = 0, int count = 0) : + time(time), messageType(messageType), detailType(detailType), detailUrl(url), x(x), y(y), + framerate(framerate), count(count) {} + + QQuickProfilerData(qint64 time, int messageType, int detailType, int framerate = 0, + int count = 0) : + time(time), messageType(messageType), detailType(detailType), framerate(framerate), + count(count) {} + + // Special ctor for scenegraph frames. Note that it's missing the QString/QUrl params. + // This is slightly ugly, but makes it easier to disambiguate between int and qint64 params. + QQuickProfilerData(qint64 time, int messageType, int detailType, qint64 d1, qint64 d2, + qint64 d3, qint64 d4, qint64 d5) : + time(time), messageType(messageType), detailType(detailType), subtime_1(d1), subtime_2(d2), + subtime_3(d3), subtime_4(d4), subtime_5(d5) {} + + + qint64 time; + int messageType; //bit field of Message + int detailType; + + QUrl detailUrl; + + union { + qint64 subtime_1; + int x; //used for pixmaps + }; + + union { + qint64 subtime_2; + int y; //used for pixmaps + }; + + union { + qint64 subtime_3; + int framerate; //used by animation events + }; + + union { + qint64 subtime_4; + int count; //used by animation events and for pixmaps + }; + + qint64 subtime_5; + + void toByteArrays(QList &messages) const; +}; + +Q_DECLARE_TYPEINFO(QQuickProfilerData, Q_MOVABLE_TYPE); + +class QQuickProfiler : public QQmlAbstractProfilerAdapter { + Q_OBJECT +public: + + template + static void addEvent() + { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << Event, + 1 << DetailType)); + } + + static void animationFrame(qint64 delta) + { + int animCount = QUnifiedTimer::instance()->runningAnimationCount(); + + if (animCount > 0 && delta > 0) { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << Event, + 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */, animCount)); + } + } + + template + static void sceneGraphFrame(qint64 value1, qint64 value2 = -1, qint64 value3 = -1, + qint64 value4 = -1, qint64 value5 = -1) + { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << SceneGraphFrame, + 1 << FrameType1 | 1 << FrameType2, value1, value2, value3, value4, value5)); + } + + template + static void pixmapStateChanged(const QUrl &url) + { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), + 1 << PixmapCacheEvent, 1 << PixmapState, url)); + } + + static void pixmapLoadingFinished(const QUrl &url, const QSize &size) + { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), + 1 << PixmapCacheEvent, + (1 << PixmapLoadingFinished) | ((size.width() > 0 && size.height() > 0) ? (1 << PixmapSizeKnown) : 0), + url, size.width(), size.height())); + } + + template + static void pixmapCountChanged(const QUrl &url, int count) + { + s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), + 1 << PixmapCacheEvent, 1 << CountType, url, 0, 0, 0, count)); + } + + qint64 timestamp() { return m_timer.nsecsElapsed(); } + + qint64 sendMessages(qint64 until, QList &messages); + + static bool enabled; + + static void initialize(); + + virtual ~QQuickProfiler(); + +protected: + int next; + static QQuickProfiler *s_instance; + QMutex m_dataMutex; + QElapsedTimer m_timer; + QVarLengthArray m_data; + + QQuickProfiler(QQmlProfilerService *service); + + void processMessage(const QQuickProfilerData &message) + { + QMutexLocker lock(&m_dataMutex); + m_data.append(message); + } + +protected slots: + void startProfilingImpl(); + void stopProfilingImpl(); + void reportDataImpl(); + void setTimer(const QElapsedTimer &t); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index fae1103d47..ce409bd10d 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -25,7 +25,8 @@ SOURCES += \ $$PWD/qquickglobal.cpp \ $$PWD/qquickanimator.cpp \ $$PWD/qquickanimatorjob.cpp \ - $$PWD/qquickanimatorcontroller.cpp + $$PWD/qquickanimatorcontroller.cpp \ + $$PWD/qquickprofiler.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ @@ -58,4 +59,5 @@ HEADERS += \ $$PWD/qquickanimator_p.h \ $$PWD/qquickanimator_p_p.h \ $$PWD/qquickanimatorjob_p.h \ - $$PWD/qquickanimatorcontroller_p.h + $$PWD/qquickanimatorcontroller_p.h \ + $$PWD/qquickprofiler_p.h -- cgit v1.2.3