From: Christiaan Janssen Date: Wed, 24 Oct 2012 14:09:29 +0000 (+0200) Subject: QmlProfiler: Pixmap Cache X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=107444f7c479ed6a1a3d2c42b026ebc9c1fe4b29;p=konrad%2Fqtdeclarative.git QmlProfiler: Pixmap Cache Change-Id: Ibc237bb162c24030438b89d54fa8802ee66b080a Reviewed-by: Kai Koehne --- diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index cb85fc0..e016b2f 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -76,6 +76,15 @@ QByteArray QQmlProfilerData::toByteArray() const 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; + } + } return data; } @@ -238,6 +247,30 @@ void QQmlProfilerService::endRange(RangeType range) 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}; + 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}; + 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}; + processMessage(rd); +} + void QQmlProfilerService::animationFrameImpl(qint64 delta) { Q_ASSERT(QQmlDebugService::isDebuggingEnabled()); diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index a50fb5e..30eb2eb 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -74,10 +74,10 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData //### QString detailData; //used by RangeData and RangeLocation - int line; //used by RangeLocation - int column; //used by RangeLocation + int line; //used by RangeLocation, also as "width" for pixmaps + int column; //used by RangeLocation, also as "height" for pixmaps int framerate; //used by animation events - int animationcount; //used by animation events + int animationcount; //used by animation events, also as "cache/reference count" for pixmaps int bindingType; QByteArray toByteArray() const; @@ -99,6 +99,7 @@ public: RangeLocation, RangeEnd, Complete, // end of transmission + PixmapCacheEvent, MaximumMessage }; @@ -132,6 +133,17 @@ public: MaximumBindingType }; + enum PixmapEventType { + PixmapSizeKnown, + PixmapReferenceCountChanged, + PixmapCacheCountChanged, + PixmapLoadingStarted, + PixmapLoadingFinished, + PixmapLoadingError, + + MaximumPixmapEventType + }; + static void initialize(); static bool startProfiling(); @@ -163,6 +175,10 @@ private: void rangeLocation(RangeType, const QUrl &, int, int); void endRange(RangeType); + // overloading depending on parameters + void pixmapEventImpl(PixmapEventType eventType, const QUrl &url); + void pixmapEventImpl(PixmapEventType eventType, const QUrl &url, int width, int height); + void pixmapEventImpl(PixmapEventType eventType, const QUrl &url, int count); bool profilingEnabled(); void setProfilingEnabled(bool enable); @@ -183,6 +199,7 @@ private: friend struct QQmlHandlingSignalProfiler; friend struct QQmlObjectCreatingProfiler; friend struct QQmlCompilingProfiler; + friend struct QQmlPixmapProfiler; }; // @@ -288,6 +305,49 @@ struct QQmlCompilingProfiler { bool enabled; }; +struct QQmlPixmapProfiler { + QQmlPixmapProfiler() { + QQmlProfilerService *instance = QQmlProfilerService::instance; + enabled = instance ? + instance->profilingEnabled() : false; + } + + ~QQmlPixmapProfiler() {} + + void startLoading(const QUrl &pixmapUrl) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapLoadingStarted, pixmapUrl); + } + } + void finishLoading(const QUrl &pixmapUrl) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapLoadingFinished, pixmapUrl); + } + } + void errorLoading(const QUrl &pixmapUrl) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapLoadingError, pixmapUrl); + } + } + void cacheCountChanged(const QUrl &pixmapUrl, int cacheCount) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapCacheCountChanged, pixmapUrl, cacheCount); + } + } + void referenceCountChanged(const QUrl &pixmapUrl, int referenceCount) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapReferenceCountChanged, pixmapUrl, referenceCount); + } + } + void setSize(const QUrl &pixmapUrl, int width, int height) { + if (enabled) { + QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapSizeKnown, pixmapUrl, width, height); + } + } + + bool enabled; +}; + QT_END_NAMESPACE #endif // QQMLPROFILERSERVICE_P_H diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index c5968c2..9cf8c58 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -71,6 +71,8 @@ #include #include +#include + #define IMAGEREQUEST_MAX_REQUEST_COUNT 8 #define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16 #define CACHE_EXPIRE_TIME 30 @@ -890,11 +892,15 @@ bool QQuickPixmapReply::event(QEvent *event) if (data) { Event *de = static_cast(event); data->pixmapStatus = (de->error == NoError) ? QQuickPixmap::Ready : QQuickPixmap::Error; - + QQmlPixmapProfiler pixmapProfiler; if (data->pixmapStatus == QQuickPixmap::Ready) { + pixmapProfiler.finishLoading(data->url); data->textureFactory = de->textureFactory; data->implicitSize = de->implicitSize; + if (data->implicitSize.width() > 0) + pixmapProfiler.setSize(url, data->implicitSize.width(), data->implicitSize.height()); } else { + pixmapProfiler.errorLoading(data->url); data->errorString = de->errorString; data->removeFromCache(); // We don't continue to cache error'd pixmaps } @@ -920,6 +926,7 @@ int QQuickPixmapData::cost() const void QQuickPixmapData::addref() { ++refCount; + QQmlPixmapProfiler().referenceCountChanged(url, refCount); if (prevUnreferencedPtr) pixmapStore()->referencePixmap(this); } @@ -928,6 +935,7 @@ void QQuickPixmapData::release() { Q_ASSERT(refCount > 0); --refCount; + QQmlPixmapProfiler().referenceCountChanged(url, refCount); if (refCount == 0) { if (reply) { QQuickPixmapReply *cancelReply = reply; @@ -958,6 +966,10 @@ void QQuickPixmapData::addToCache() QQuickPixmapKey key = { &url, &requestSize }; pixmapStore()->m_cache.insert(key, this); inCache = true; + QQmlPixmapProfiler pixmapProfiler; + pixmapProfiler.cacheCountChanged(url, pixmapStore()->m_cache.count()); + if (implicitSize.width() > 0) + pixmapProfiler.setSize(url, implicitSize.width(), implicitSize.height()); } } @@ -965,6 +977,7 @@ void QQuickPixmapData::removeFromCache() { if (inCache) { QQuickPixmapKey key = { &url, &requestSize }; + QQmlPixmapProfiler().cacheCountChanged(url, pixmapStore()->m_cache.count()); pixmapStore()->m_cache.remove(key); inCache = false; } @@ -1238,14 +1251,21 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques if (!(options & QQuickPixmap::Asynchronous)) { bool ok = false; + QQmlPixmapProfiler pixmapProfiler; + pixmapProfiler.startLoading(url); d = createPixmapDataSync(this, engine, url, requestSize, &ok); if (ok) { + pixmapProfiler.finishLoading(url); + if (d->implicitSize.width() > 0) + QQmlPixmapProfiler().setSize(url, d->implicitSize.width(), d->implicitSize.height()); if (options & QQuickPixmap::Cache) d->addToCache(); return; } - if (d) // loadable, but encountered error while loading + if (d) { // loadable, but encountered error while loading + pixmapProfiler.errorLoading(url); return; + } } if (!engine) diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/TestImage_2x2.png b/tests/auto/qml/debugger/qqmlprofilerservice/data/TestImage_2x2.png new file mode 100644 index 0000000..30228cb Binary files /dev/null and b/tests/auto/qml/debugger/qqmlprofilerservice/data/TestImage_2x2.png differ diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/pixmapCacheTest.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/pixmapCacheTest.qml new file mode 100644 index 0000000..d56786b --- /dev/null +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/pixmapCacheTest.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + Image { + source: "TestImage_2x2.png" + onStatusChanged: switch (status) { + case 0: console.log("no image"); break; + case 1: console.log("image loaded"); break; + case 2: console.log("image loading"); break; + case 3: console.log("image error"); break; + } + } +} diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro index 5bff33d..b2b325d 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro +++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro @@ -12,3 +12,6 @@ TESTDATA = data/* QT += core qml testlib gui-private DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 + +OTHER_FILES += \ + data/pixmapCacheTest.qml diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 9982e5d..8ad4f52 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -77,6 +77,7 @@ public: RangeLocation, RangeEnd, Complete, // end of transmission + PixmapCacheEvent, MaximumMessage }; @@ -102,6 +103,17 @@ public: MaximumRangeType }; + enum PixmapEventType { + PixmapSizeKnown, + PixmapReferenceCountChanged, + PixmapCacheCountChanged, + PixmapLoadingStarted, + PixmapLoadingFinished, + PixmapLoadingError, + + MaximumPixmapEventType + }; + QQmlProfilerClient(QQmlDebugConnection *connection) : QQmlDebugClient(QLatin1String("CanvasFrameRate"), connection) { @@ -148,6 +160,7 @@ private slots: void blockingConnectWithTraceEnabled(); void blockingConnectWithTraceDisabled(); void nonBlockingConnect(); + void pixmapCacheData(); void profileOnExit(); }; @@ -219,6 +232,16 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message) QVERIFY(data.line >= -2); break; } + case QQmlProfilerClient::PixmapCacheEvent: { + stream >> data.detailType >> data.detailData; + if (data.detailType == QQmlProfilerClient::PixmapSizeKnown) + stream >> data.line >> data.column; + if (data.detailType == QQmlProfilerClient::PixmapReferenceCountChanged) + stream >> data.animationcount; + if (data.detailType == QQmlProfilerClient::PixmapCacheCountChanged) + stream >> data.animationcount; + break; + } default: QString failMsg = QString("Unknown message type:") + data.messageType; QFAIL(qPrintable(failMsg)); @@ -320,6 +343,51 @@ void tst_QQmlProfilerService::nonBlockingConnect() QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); } +void tst_QQmlProfilerService::pixmapCacheData() +{ + connect(true, "pixmapCacheTest.qml"); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + + m_client->setTraceState(true); + QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); + + QVERIFY(m_process->output().indexOf(QLatin1String("image loaded")) != -1 || + m_process->output().indexOf(QLatin1String("image error")) != -1 ); + + + m_client->setTraceState(false); + + QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); + QVERIFY(m_client->traceMessages.count()); + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); + + // image starting to load + QCOMPARE(m_client->traceMessages[8].messageType, (int)QQmlProfilerClient::PixmapCacheEvent); + QCOMPARE(m_client->traceMessages[8].detailType, (int)QQmlProfilerClient::PixmapLoadingStarted); + + // image loaded + QCOMPARE(m_client->traceMessages[9].messageType, (int)QQmlProfilerClient::PixmapCacheEvent); + QCOMPARE(m_client->traceMessages[9].detailType, (int)QQmlProfilerClient::PixmapLoadingFinished); + + // image size + QCOMPARE(m_client->traceMessages[10].messageType, (int)QQmlProfilerClient::PixmapCacheEvent); + QCOMPARE(m_client->traceMessages[10].detailType, (int)QQmlProfilerClient::PixmapSizeKnown); + QCOMPARE(m_client->traceMessages[10].line, 2); // width + QCOMPARE(m_client->traceMessages[10].column, 2); // height + + // cache size + QCOMPARE(m_client->traceMessages[11].messageType, (int)QQmlProfilerClient::PixmapCacheEvent); + QCOMPARE(m_client->traceMessages[11].detailType, (int)QQmlProfilerClient::PixmapCacheCountChanged); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); + +} + void tst_QQmlProfilerService::profileOnExit() { connect(true, "exit.qml"); diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp index 6585f7e..ff3140f 100644 --- a/tests/auto/qml/debugger/shared/debugutil.cpp +++ b/tests/auto/qml/debugger/shared/debugutil.cpp @@ -182,6 +182,8 @@ void QQmlDebugProcess::processAppOutput() { m_mutex.lock(); + bool outputFromAppItself = false; + QString newOutput = m_process.readAll(); m_output.append(newOutput); m_outputBuffer.append(newOutput); @@ -208,7 +210,13 @@ void QQmlDebugProcess::processAppOutput() m_eventLoop.quit(); continue; } + } else { + // set to true if there is output not coming from the debugger + outputFromAppItself = true; } } m_mutex.unlock(); + + if (outputFromAppItself) + emit readyReadStandardOutput(); } diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 363aabb..11b16a1 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -98,6 +98,9 @@ public: QString output() const; void stop(); +signals: + void readyReadStandardOutput(); + private slots: void timeout(); void processAppOutput();