diff options
Diffstat (limited to 'src/qml/debugger/qqmlprofilerservice.cpp')
-rw-r--r-- | src/qml/debugger/qqmlprofilerservice.cpp | 526 |
1 files changed, 131 insertions, 395 deletions
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index af2aea21ae..a9ef5ff6b1 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -47,97 +47,118 @@ #include <QtCore/qthread.h> #include <QtCore/qcoreapplication.h> -// this contains QUnifiedTimer -#include <private/qabstractanimation_p.h> - QT_BEGIN_NAMESPACE // instance will be set, unset in constructor. Allows static methods to be inlined. -QQmlProfilerService *QQmlProfilerService::instance = 0; +QQmlProfilerService *QQmlProfilerService::m_instance = 0; Q_GLOBAL_STATIC(QQmlProfilerService, profilerInstance) bool QQmlProfilerService::enabled = false; -// convert to a QByteArray that can be sent to the debug client +// convert to QByteArrays that can be sent to the debug client // use of QDataStream can skew results // (see tst_qqmldebugtrace::trace() benchmark) -QByteArray QQmlProfilerData::toByteArray() const +void QQmlProfilerData::toByteArrays(QList<QByteArray> &messages) const { QByteArray data; - //### using QDataStream is relatively expensive - QQmlDebugStream ds(&data, QIODevice::WriteOnly); - ds << time << messageType << detailType; - if (messageType == (int)QQmlProfilerService::RangeStart && - detailType == (int)QQmlProfilerService::Binding) - ds << bindingType; - if (messageType == (int)QQmlProfilerService::RangeData) - ds << detailData; - if (messageType == (int)QQmlProfilerService::RangeLocation) - ds << detailData << line << column; - if (messageType == (int)QQmlProfilerService::Event && - detailType == (int)QQmlProfilerService::AnimationFrame) - ds << framerate << animationcount; - if (messageType == (int)QQmlProfilerService::PixmapCacheEvent) { - ds << detailData; - switch (detailType) { - case QQmlProfilerService::PixmapSizeKnown: ds << line << column; break; - case QQmlProfilerService::PixmapReferenceCountChanged: ds << animationcount; break; - case QQmlProfilerService::PixmapCacheCountChanged: ds << animationcount; break; - default: break; - } - } - if (messageType == (int)QQmlProfilerService::SceneGraphFrame) { - switch (detailType) { - // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime - case QQmlProfilerService::SceneGraphRendererFrame: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; - // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime - case QQmlProfilerService::SceneGraphAdaptationLayerFrame: ds << (int)subtime_1 << subtime_2 << subtime_3; break; - // ContextFrame: compiling material time - case QQmlProfilerService::SceneGraphContextFrame: ds << subtime_1; break; - // RenderLoop: syncTime, renderTime, swapTime - case QQmlProfilerService::SceneGraphRenderLoopFrame: ds << subtime_1 << subtime_2 << subtime_3; break; - // TexturePrepare: bind, convert, swizzle, upload, mipmap - case QQmlProfilerService::SceneGraphTexturePrepare: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4 << subtime_5; break; - // TextureDeletion: deletionTime - case QQmlProfilerService::SceneGraphTextureDeletion: ds << subtime_1; break; - // PolishAndSync: polishTime, waitTime, syncTime, animationsTime, - case QQmlProfilerService::SceneGraphPolishAndSync: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; - // WindowsRenderLoop: GL time, make current time, SceneGraph time - case QQmlProfilerService::SceneGraphWindowsRenderShow: ds << subtime_1 << subtime_2 << subtime_3; break; - // WindowsAnimations: update time - case QQmlProfilerService::SceneGraphWindowsAnimations: ds << subtime_1; break; - // WindowsRenderWindow: polish time - case QQmlProfilerService::SceneGraphWindowsPolishFrame: ds << subtime_1; break; - default:break; + 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 QQmlProfilerService::Event: + if (decodedDetailType == (int)QQmlProfilerService::AnimationFrame) + ds << framerate << count; + break; + case QQmlProfilerService::RangeStart: + if (decodedDetailType == (int)QQmlProfilerService::Binding) + ds << bindingType; + break; + case QQmlProfilerService::RangeData: + ds << detailString; + break; + case QQmlProfilerService::RangeLocation: + ds << (detailUrl.isEmpty() ? detailString : detailUrl.toString()) << x << y; + break; + case QQmlProfilerService::RangeEnd: break; + case QQmlProfilerService::PixmapCacheEvent: + ds << detailUrl.toString(); + switch (decodedDetailType) { + case QQmlProfilerService::PixmapSizeKnown: ds << x << y; break; + case QQmlProfilerService::PixmapReferenceCountChanged: ds << count; break; + case QQmlProfilerService::PixmapCacheCountChanged: ds << count; break; + default: break; + } + break; + case QQmlProfilerService::SceneGraphFrame: + switch (decodedDetailType) { + // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime + case QQmlProfilerService::SceneGraphRendererFrame: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; + // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime + case QQmlProfilerService::SceneGraphAdaptationLayerFrame: ds << (int)subtime_1 << subtime_2 << subtime_3; break; + // ContextFrame: compiling material time + case QQmlProfilerService::SceneGraphContextFrame: ds << subtime_1; break; + // RenderLoop: syncTime, renderTime, swapTime + case QQmlProfilerService::SceneGraphRenderLoopFrame: ds << subtime_1 << subtime_2 << subtime_3; break; + // TexturePrepare: bind, convert, swizzle, upload, mipmap + case QQmlProfilerService::SceneGraphTexturePrepare: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4 << subtime_5; break; + // TextureDeletion: deletionTime + case QQmlProfilerService::SceneGraphTextureDeletion: ds << subtime_1; break; + // PolishAndSync: polishTime, waitTime, syncTime, animationsTime, + case QQmlProfilerService::SceneGraphPolishAndSync: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; + // WindowsRenderLoop: GL time, make current time, SceneGraph time + case QQmlProfilerService::SceneGraphWindowsRenderShow: ds << subtime_1 << subtime_2 << subtime_3; break; + // WindowsAnimations: update time + case QQmlProfilerService::SceneGraphWindowsAnimations: ds << subtime_1; break; + // WindowsRenderWindow: polish time; always comes packed after a RenderLoop + case QQmlProfilerService::SceneGraphWindowsPolishFrame: ds << subtime_4; break; + default:break; + } + break; + case QQmlProfilerService::Complete: break; + } + messages << data; + data.clear(); } } +} - return data; +void QQmlProfilerService::animationTimerCallback(qint64 delta) +{ + Q_QML_PROFILE(animationFrame(delta)); } QQmlProfilerService::QQmlProfilerService() - : QQmlDebugService(QStringLiteral("CanvasFrameRate"), 1) + : QQmlConfigurableDebugService(QStringLiteral("CanvasFrameRate"), 1) { m_timer.start(); - // don't execute stateAboutToBeChanged(), messageReceived() in parallel - QMutexLocker lock(&m_initializeMutex); - - if (registerService() == Enabled) { - QUnifiedTimer::instance()->registerProfilerCallback(&animationFrame); - if (blockingMode()) - m_initializeCondition.wait(&m_initializeMutex); - } + 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); } QQmlProfilerService::~QQmlProfilerService() { - instance = 0; + enabled = false; + m_instance = 0; } -void QQmlProfilerService::initialize() +QQmlProfilerService *QQmlProfilerService::instance() { // just make sure that the service is properly registered - instance = profilerInstance(); + m_instance = profilerInstance(); + return m_instance; } bool QQmlProfilerService::startProfiling() @@ -150,26 +171,6 @@ bool QQmlProfilerService::stopProfiling() return profilerInstance()->stopProfilingImpl(); } -void QQmlProfilerService::sendStartedProfilingMessage() -{ - profilerInstance()->sendStartedProfilingMessageImpl(); -} - -void QQmlProfilerService::addEvent(EventType t) -{ - profilerInstance()->addEventImpl(t); -} - -void QQmlProfilerService::animationFrame(qint64 delta) -{ - profilerInstance()->animationFrameImpl(delta); -} - -void QQmlProfilerService::sceneGraphFrame(SceneGraphFrameType frameType, qint64 value1, qint64 value2, qint64 value3, qint64 value4, qint64 value5) -{ - profilerInstance()->sceneGraphFrameImpl(frameType, value1, value2, value3, value4, value5); -} - void QQmlProfilerService::sendProfilingData() { profilerInstance()->sendMessages(); @@ -177,193 +178,31 @@ void QQmlProfilerService::sendProfilingData() bool QQmlProfilerService::startProfilingImpl() { - bool success = false; - if (QQmlDebugService::isDebuggingEnabled() && !profilingEnabled()) { - setProfilingEnabled(true); - sendStartedProfilingMessageImpl(); - success = true; + if (QQmlDebugService::isDebuggingEnabled() && !enabled) { + enabled = true; + QList<QByteArray> messages; + QQmlProfilerData(m_timer.nsecsElapsed(), 1 << Event, 1 << StartTrace).toByteArrays(messages); + QQmlDebugService::sendMessages(messages); + return true; + } else { + return false; } - return success; } bool QQmlProfilerService::stopProfilingImpl() { - bool success = false; - if (profilingEnabled()) { - addEventImpl(EndTrace); - setProfilingEnabled(false); - success = true; - } - return success; -} - -void QQmlProfilerService::sendStartedProfilingMessageImpl() -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)StartTrace, - QString(), -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0}; - QQmlDebugService::sendMessage(ed.toByteArray()); -} - -void QQmlProfilerService::addEventImpl(EventType event) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)event, - QString(), -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(ed); -} - -void QQmlProfilerService::startRange(RangeType range, BindingType bindingType) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeStart, (int)range, - QString(), -1, -1, 0, 0, (int)bindingType, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::rangeData(RangeType range, const QString &rData) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, - rData, -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::rangeData(RangeType range, const QUrl &rData) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, - rData.toString(), -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::rangeLocation(RangeType range, const QString &fileName, int line, int column) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, - fileName, line, column, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::rangeLocation(RangeType range, const QUrl &fileName, int line, int column) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, - fileName.toString(), line, column, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::endRange(RangeType range) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeEnd, (int)range, - QString(), -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::pixmapEventImpl(PixmapEventType eventType, const QUrl &url) -{ - // assuming enabled checked by caller - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)PixmapCacheEvent, (int)eventType, - url.toString(), -1, -1, -1, -1, -1, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::pixmapEventImpl(PixmapEventType eventType, const QUrl &url, int width, int height) -{ - // assuming enabled checked by caller - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)PixmapCacheEvent, (int)eventType, - url.toString(), width, height, -1, -1, -1, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::pixmapEventImpl(PixmapEventType eventType, const QUrl &url, int count) -{ - // assuming enabled checked by caller - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)PixmapCacheEvent, (int)eventType, - url.toString(), -1, -1, -1, count, -1, - 0, 0, 0, 0, 0}; - processMessage(rd); -} - -void QQmlProfilerService::sceneGraphFrameImpl(SceneGraphFrameType frameType, qint64 value1, qint64 value2, qint64 value3, qint64 value4, qint64 value5) -{ - if (!QQmlDebugService::isDebuggingEnabled() || !enabled) - return; - - // because I already have some space to store ints in the struct, I'll use it to store the frame data - // even though the field names do not match - QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)SceneGraphFrame, (int)frameType, QString(), - -1, -1, -1, -1, -1, - value1, value2, value3, value4, value5}; - processMessage(rd); -} - -void QQmlProfilerService::animationFrameImpl(qint64 delta) -{ - Q_ASSERT(QQmlDebugService::isDebuggingEnabled()); - if (!enabled) - return; - - int animCount = QUnifiedTimer::instance()->runningAnimationCount(); - - if (animCount > 0 && delta > 0) { - // trim fps to integer - int fps = 1000 / delta; - QQmlProfilerData ed = {m_timer.nsecsElapsed(), (int)Event, (int)AnimationFrame, - QString(), -1, -1, fps, animCount, 0, - 0, 0, 0, 0, 0}; - processMessage(ed); + if (enabled) { + enabled = false; + // We cannot use instance here as this is called from the debugger thread. + // It may be called before the QML engine (and the profiler) is ready. + processMessage(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << Event, 1 << EndTrace)); + return true; + } else { + return false; } } /* - Either send the message directly, or queue up - a list of messages to send later (via sendMessages) -*/ -void QQmlProfilerService::processMessage(const QQmlProfilerData &message) -{ - QMutexLocker locker(&m_dataMutex); - m_data.append(message); -} - -bool QQmlProfilerService::profilingEnabled() -{ - return enabled; -} - -void QQmlProfilerService::setProfilingEnabled(bool enable) -{ - enabled = enable; -} - -/* Send the messages queued up by processMessage */ void QQmlProfilerService::sendMessages() @@ -372,7 +211,7 @@ void QQmlProfilerService::sendMessages() QList<QByteArray> messages; for (int i = 0; i < m_data.count(); ++i) - messages << m_data.at(i).toByteArray(); + m_data.at(i).toByteArrays(messages); m_data.clear(); //indicate completion @@ -386,27 +225,20 @@ void QQmlProfilerService::sendMessages() void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState) { - QMutexLocker lock(&m_initializeMutex); + QMutexLocker lock(configMutex()); if (state() == newState) return; - if (state() == Enabled - && enabled) { + if (newState != Enabled && enabled) { stopProfilingImpl(); sendMessages(); } - - if (state() != Enabled) { - // wake up constructor in blocking mode - // (we might got disabled before first message arrived) - m_initializeCondition.wakeAll(); - } } void QQmlProfilerService::messageReceived(const QByteArray &message) { - QMutexLocker lock(&m_initializeMutex); + QMutexLocker lock(configMutex()); QByteArray rwData = message; QQmlDebugStream stream(&rwData, QIODevice::ReadOnly); @@ -421,158 +253,62 @@ void QQmlProfilerService::messageReceived(const QByteArray &message) sendMessages(); } - // wake up constructor in blocking mode - m_initializeCondition.wakeAll(); -} - -/*! - * \brief QQmlVmeProfiler::Data::clear Reset to defaults - * Reset the profiling data to defaults. - */ -void QQmlVmeProfiler::Data::clear() -{ - url.clear(); - line = 0; - column = 0; - typeName.clear(); + stopWaiting(); } /*! - * \brief QQmlVmeProfiler::start Start profiler without data - * Clears the current range data, then stops the profiler previously running in the - * foreground if any, then starts a new one. + * \fn void QQmlVmeProfiler::Data::clear() + * Resets the profiling data to defaults. */ -bool QQmlVmeProfiler::start() -{ - if (QQmlProfilerService::enabled) { - currentRange.clear(); - if (running) - QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); - else - running = true; - QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating); - return true; - } - return false; -} /*! - * \brief QQmlVmeProfiler::updateLocation Update current location information - * \param url URL of file being executed - * \param line line Curent line in file - * \param column column Current column in file - * Updates the current profiler's location information. + * \fn bool QQmlVmeProfiler::startBackground(const QString &typeName) + * If profiling is enabled clears the current range data, then stops the + * profiler previously running in the foreground if any, then starts a new one + * in the background, setting the given typeName. \a typeName is the type of + * object being created. */ -void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column) -{ - if (QQmlProfilerService::enabled && running) { - currentRange.url = url; - currentRange.line = line; - currentRange.column = column; - QQmlProfilerService::instance->rangeLocation( - QQmlProfilerService::Creating, url, line, column); - } -} /*! - * \brief QQmlVmeProfiler::updateTypeName Update current type information - * \param typeName Type of object being created - * Updates the current profiler's type information. + * \fn bool QQmlVmeProfiler::start(const QString &typeName, const QUrl &url, int line, int column) + * If profiling is enabled clears the current range data, then stops the + * profiler previously running in the foreground if any, then starts a new one + * in the foreground, setting the given location. \a url is the URL of + * file being executed, \line line is the current line in in that file, and + * \a column is the current column in that file. */ -void QQmlVmeProfiler::updateTypeName(const QString &typeName) -{ - if (QQmlProfilerService::enabled && running) { - currentRange.typeName = typeName; - QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName); - } -} /*! - * \brief QQmlVmeProfiler::pop Pops a paused profiler from the stack and restarts it + * \fn bool QQmlVmeProfiler::pop() * Stops the currently running profiler, if any, then retrieves an old one from the stack - * of paused profilers and starts that. + * of paused profilers and starts that if possible. */ -void QQmlVmeProfiler::pop() -{ - if (QQmlProfilerService::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); - } -} /*! - * \brief QQmlVmeProfiler::push Pushes the currently running profiler on the stack. + * \fn void QQmlVmeProfiler::push() * Pushes the currently running profiler on the stack of paused profilers. Note: The profiler * isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that * won't do any harm, though. */ -void QQmlVmeProfiler::push() -{ - if (QQmlProfilerService::enabled && running) - ranges.push(currentRange); -} /*! - * \brief QQmlVmeProfiler::clear Stop all running profilers and clear all data. + * \fn void QQmlVmeProfiler::clear() * Stops the currently running (foreground and background) profilers and removes all saved * data about paused profilers. */ -void QQmlVmeProfiler::clear() -{ - stop(); - ranges.clear(); - if (QQmlProfilerService::enabled) { - for (int i = 0; i < backgroundRanges.count(); ++i) { - QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); - } - } - backgroundRanges.clear(); - running = false; -} /*! - * \brief QQmlVmeProfiler::stop Stop profiler running in the foreground, if any. + * \fn void QQmlVmeProfiler::stop() + * Stop profiler running in the foreground, if any. */ -void QQmlVmeProfiler::stop() -{ - if (QQmlProfilerService::enabled && running) { - QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); - currentRange.clear(); - running = false; - } -} /*! - * \brief QQmlVmeProfiler::background Push the current profiler to the background. - * Push the profiler currently running in the foreground to the background so that it - * won't be stopped by stop() or start(). There can be multiple profilers in the background. - * You can retrieve them in reverse order by calling foreground(). + * \fn bool QQmlVmeProfiler::foreground(const QUrl &url, int line, int column) + * Stops the profiler currently running in the foreground, if any and puts the + * next profiler from the background in its place if there are any profilers in + * the background. Additionally the rangeLocation is set. \a url is the URL of + * file being executed, \line line is the current line in in that file, and + * \a column is the current column in that file. */ -void QQmlVmeProfiler::background() -{ - if (QQmlProfilerService::enabled && running) { - backgroundRanges.push(currentRange); - running = false; - } -} - -/*! - * \brief QQmlVmeProfiler::foreground Retrieve a profiler from the background - * Stop the profiler currently running in the foreground, if any and put the next profiler - * from the background in its place. - */ -bool QQmlVmeProfiler::foreground() -{ - if (QQmlProfilerService::enabled && backgroundRanges.count() > 0) { - stop(); - currentRange = backgroundRanges.pop(); - running = true; - return true; - } - return false; -} QT_END_NAMESPACE |