From d72c6954174ac2469d4b4324bc9739b4854b84fd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 16:21:32 -0700 Subject: [PATCH 01/11] Sanitize ResourceCache to expose to JS/QML fix sanitize --- interface/src/Application.cpp | 5 ++--- libraries/networking/src/ResourceCache.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bd1a44fc76..f11fd22e2f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -588,9 +588,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // Model background downloads need to happen on the Datagram Processor Thread. The idle loop will // emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background // downloads. - QSharedPointer modelCacheP = DependencyManager::get(); - ResourceCache* modelCache = modelCacheP.data(); - connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets); + auto modelCache = DependencyManager::get(); + connect(this, &Application::checkBackgroundDownloads, modelCache.data(), &ModelCache::checkAsynchronousGets); // put the audio processing on a separate thread QThread* audioThread = new QThread(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f674c96a1e..10f0289052 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -109,7 +109,7 @@ protected: /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \param extra extra data to pass to the creator, if appropriate - Q_INVOKABLE QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), + QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false, void* extra = NULL); /// Creates a new resource. @@ -123,7 +123,7 @@ protected: /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue - Q_INVOKABLE static bool attemptRequest(Resource* resource); + static bool attemptRequest(Resource* resource); static void requestCompleted(Resource* resource); static bool attemptHighestPriorityRequest(); From 3b45a57e1d785d63830e2d31eb989271d0a86b21 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:02:44 -0700 Subject: [PATCH 02/11] Remove resource completely when uncached --- libraries/networking/src/ResourceCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b5f5ca7c25..54b70c7da3 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -142,8 +142,9 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _unusedResourcesSize -= it.value()->getBytes(); + _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); + _unusedResourcesSize -= it.value()->getBytes(); _unusedResources.erase(it); } } From b70a4d043bdfa9f6906e76e732198a796eb5c062 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:33:12 -0700 Subject: [PATCH 03/11] Expose resource cache count props --- libraries/networking/src/ResourceCache.cpp | 23 +++++++++++++++--- libraries/networking/src/ResourceCache.h | 27 ++++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 54b70c7da3..c10b96ca19 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -114,6 +114,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); + emit dirty(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -127,6 +128,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); + emit dirty(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -134,6 +136,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } + emit dirty(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -142,9 +145,13 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - _resources.remove(it.value()->getURL()); it.value()->setCache(nullptr); - _unusedResourcesSize -= it.value()->getBytes(); + auto size = it.value()->getBytes(); + + _totalResourcesSize -= size; + _resources.remove(it.value()->getURL()); + + _unusedResourcesSize -= size; _unusedResources.erase(it); } } @@ -160,6 +167,11 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { + _totalResourcesSize += (newSize - oldSize); + emit dirty(); +} + void ResourceCacheSharedItems::appendActiveRequest(Resource* resource) { Lock lock(_mutex); _loadingRequests.append(resource); @@ -378,6 +390,11 @@ void Resource::finishedLoading(bool success) { emit finished(success); } +void Resource::setBytes(const qint64& bytes) { + QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); + _bytes = bytes; +} + void Resource::reinsert() { _cache->_resources.insert(_url, _self); } @@ -413,7 +430,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - _bytes = _bytesTotal; + setBytes(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 10f0289052..f113254995 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -79,8 +79,18 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT + Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) public: + int getNumTotalResources() const { return _resources.size(); } + qint64 getSizeTotalResources() const { return _totalResourcesSize; } + + int getNumCachedResources() const { return _unusedResources.size(); } + qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -101,9 +111,15 @@ public: void refreshAll(); void refresh(const QUrl& url); +signals: + void dirty(); + public slots: void checkAsynchronousGets(); +protected slots: + void updateTotalSize(const qint64& oldSize, const qint64& newSize); + protected: /// Loads a resource from the specified URL. /// \param fallback a fallback URL to load if the desired one is unavailable @@ -118,8 +134,6 @@ protected: void addUnusedResource(const QSharedPointer& resource); void removeUnusedResource(const QSharedPointer& resource); - void reserveUnusedResource(qint64 resourceSize); - void clearUnusedResource(); /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue @@ -130,6 +144,9 @@ protected: private: friend class Resource; + void reserveUnusedResource(qint64 resourceSize); + void clearUnusedResource(); + QHash> _resources; int _lastLRUKey = 0; @@ -140,8 +157,10 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; + qint64 _totalResourcesSize { 0 }; + qint64 _unusedResourcesSize { 0 }; + qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; - qint64 _unusedResourcesSize = 0; QMap> _unusedResources; }; @@ -226,7 +245,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(qint64 bytes) { _bytes = bytes; } + void setBytes(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing. From 5b9198ed3d5df8b6cb69b95b8a6afb6b6dc433e9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 17:41:57 -0700 Subject: [PATCH 04/11] Expose tex/model cache to js/qml --- interface/src/Application.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f11fd22e2f..802c2569c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1351,7 +1351,6 @@ void Application::initializeUi() { // though I can't find it. Hence, "ApplicationInterface" rootContext->setContextProperty("SnapshotUploader", new SnapshotUploader()); rootContext->setContextProperty("ApplicationInterface", this); - rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); rootContext->setContextProperty("Audio", &AudioScriptingInterface::getInstance()); rootContext->setContextProperty("Controller", DependencyManager::get().data()); rootContext->setContextProperty("Entities", DependencyManager::get().data()); @@ -1381,8 +1380,13 @@ void Application::initializeUi() { rootContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); rootContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); rootContext->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches rootContext->setContextProperty("AnimationCache", DependencyManager::get().data()); + rootContext->setContextProperty("TextureCache", DependencyManager::get().data()); + rootContext->setContextProperty("ModelCache", DependencyManager::get().data()); rootContext->setContextProperty("SoundCache", DependencyManager::get().data()); + rootContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); rootContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface); rootContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); @@ -4334,8 +4338,13 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + + // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); From 36e04f4434ec71894cf211d3ded0a039aabb231c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 18:22:51 -0700 Subject: [PATCH 05/11] Mv PlotPerf to shared dir --- examples/utilities/{render => lib}/plotperf/PlotPerf.qml | 0 examples/utilities/{render => lib}/plotperf/qmldir | 0 examples/utilities/render/stats.qml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/utilities/{render => lib}/plotperf/PlotPerf.qml (100%) rename examples/utilities/{render => lib}/plotperf/qmldir (100%) diff --git a/examples/utilities/render/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml similarity index 100% rename from examples/utilities/render/plotperf/PlotPerf.qml rename to examples/utilities/lib/plotperf/PlotPerf.qml diff --git a/examples/utilities/render/plotperf/qmldir b/examples/utilities/lib/plotperf/qmldir similarity index 100% rename from examples/utilities/render/plotperf/qmldir rename to examples/utilities/lib/plotperf/qmldir diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0e51cb8834..0902695f93 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 -import "plotperf" +import "../lib/plotperf" Item { id: statsUI From 41cdb29bd23ab44ee6d2864566ce6a82bc1c4b94 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:51:05 -0700 Subject: [PATCH 06/11] Use a timer in plotperf --- examples/utilities/lib/plotperf/PlotPerf.qml | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/examples/utilities/lib/plotperf/PlotPerf.qml b/examples/utilities/lib/plotperf/PlotPerf.qml index 179707c0f1..6871ffe6a6 100644 --- a/examples/utilities/lib/plotperf/PlotPerf.qml +++ b/examples/utilities/lib/plotperf/PlotPerf.qml @@ -19,12 +19,8 @@ Item { // The title of the graph property string title - // THe object used as the default source object for the prop plots + // The object used as the default source object for the prop plots property var object - - // THis is my hack to get a property and assign it to a trigger var in order to get - // a signal called whenever the value changed - property var trigger // Plots is an array of plot descriptor // a default plot descriptor expects the following object: @@ -55,45 +51,38 @@ Item { property var tick : 0 function createValues() { - print("trigger is: " + JSON.stringify(trigger)) - if (Array.isArray(plots)) { - for (var i =0; i < plots.length; i++) { - var plot = plots[i]; - print(" a pnew Plot:" + JSON.stringify(plot)); - _values.push( { - object: (plot["object"] !== undefined ? plot["object"] : root.object), - value: plot["prop"], - valueMax: 1, - numSamplesConstantMax: 0, - valueHistory: new Array(), - label: (plot["label"] !== undefined ? plot["label"] : ""), - color: (plot["color"] !== undefined ? plot["color"] : "white"), - scale: (plot["scale"] !== undefined ? plot["scale"] : 1), - unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) - }) - } + for (var i =0; i < plots.length; i++) { + var plot = plots[i]; + _values.push( { + object: (plot["object"] !== undefined ? plot["object"] : root.object), + value: plot["prop"], + valueMax: 1, + numSamplesConstantMax: 0, + valueHistory: new Array(), + label: (plot["label"] !== undefined ? plot["label"] : ""), + color: (plot["color"] !== undefined ? plot["color"] : "white"), + scale: (plot["scale"] !== undefined ? plot["scale"] : 1), + unit: (plot["unit"] !== undefined ? plot["unit"] : valueUnit) + }) } - print("in creator" + JSON.stringify(_values)); - + pullFreshValues(); } Component.onCompleted: { createValues(); - print(JSON.stringify(_values)); - } function pullFreshValues() { - //print("pullFreshValues"); + // Wait until values are created to begin pulling + if (!_values) { return; } + var VALUE_HISTORY_SIZE = 100; - var UPDATE_CANVAS_RATE = 20; tick++; - var currentValueMax = 0 for (var i = 0; i < _values.length; i++) { - var currentVal = _values[i].object[_values[i].value] * _values[i].scale; + var currentVal = (+_values[i].object[_values[i].value]) * _values[i].scale; _values[i].valueHistory.push(currentVal) _values[i].numSamplesConstantMax++; @@ -125,11 +114,13 @@ Item { valueMax = currentValueMax; } - if (tick % UPDATE_CANVAS_RATE == 0) { - mycanvas.requestPaint() - } + mycanvas.requestPaint() + } + + Timer { + interval: 100; running: true; repeat: true + onTriggered: pullFreshValues() } - onTriggerChanged: pullFreshValues() Canvas { id: mycanvas @@ -165,9 +156,9 @@ Item { ctx.fillStyle = val.color; var bestValue = val.valueHistory[val.valueHistory.length -1]; ctx.textAlign = "right"; - ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); + ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1); ctx.textAlign = "left"; - ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); + ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1); } function displayTitle(ctx, text, maxVal) { From b0185dc355590eb578004b4f6c7e47eedf07dfad Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:52:08 -0700 Subject: [PATCH 07/11] Add cacheStats.js --- examples/utilities/cache/cacheStats.js | 21 +++++++ examples/utilities/cache/stats.qml | 77 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 examples/utilities/cache/cacheStats.js create mode 100644 examples/utilities/cache/stats.qml diff --git a/examples/utilities/cache/cacheStats.js b/examples/utilities/cache/cacheStats.js new file mode 100644 index 0000000000..e58a5d0e21 --- /dev/null +++ b/examples/utilities/cache/cacheStats.js @@ -0,0 +1,21 @@ +// +// cacheStats.js +// examples/utilities/cache +// +// Zach Pomerantz, created on 4/1/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Set up the qml ui +var qml = Script.resolvePath('stats.qml'); +var window = new OverlayWindow({ + title: 'Cache Stats', + source: qml, + width: 300, + height: 200 +}); +window.setPosition(500, 50); +window.closed.connect(function() { Script.stop(); }); diff --git a/examples/utilities/cache/stats.qml b/examples/utilities/cache/stats.qml new file mode 100644 index 0000000000..d7888eb1aa --- /dev/null +++ b/examples/utilities/cache/stats.qml @@ -0,0 +1,77 @@ +// +// stats.qml +// examples/utilities/cache +// +// Created by Zach Pomerantz on 4/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../lib/plotperf" + +Item { + id: root + anchors.fill: parent + + property var caches: [["Animation", AnimationCache], ["Model", ModelCache], ["Texture", TextureCache], ["Sound", SoundCache]] + + Grid { + id: grid + rows: root.caches.length; columns: 1; spacing: 8 + anchors.fill: parent + + Repeater { + id: repeater + + model: root.caches + + Row { + PlotPerf { + title: modelData[0] + " Count" + anchors.left: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueNumDigits: "1" + plots: [ + { + prop: "numTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "numCached", + label: "cached", + color: "#1AC567" + } + ] + } + PlotPerf { + title: modelData[0] + " Size" + anchors.right: parent + height: (grid.height - (grid.spacing * (root.caches.length + 1))) / root.caches.length + width: grid.width / 2 - grid.spacing * 1.5 + object: modelData[1] + valueScale: 1048576 + valueUnit: "Mb" + valueNumDigits: "1" + plots: [ + { + prop: "sizeTotal", + label: "total", + color: "#00B4EF" + }, + { + prop: "sizeCached", + label: "cached", + color: "#1AC567" + } + ] + } + } + } + } +} From d78338330c70a8328f2c4a9ee604b5ffb78a3beb Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 1 Apr 2016 19:53:41 -0700 Subject: [PATCH 08/11] Rm unused trigger from renderStats --- examples/utilities/render/stats.qml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index 0902695f93..4988c23e3b 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -32,7 +32,6 @@ Item { title: "Num Buffers" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUCount"] plots: [ { prop: "bufferCPUCount", @@ -50,7 +49,6 @@ Item { title: "gpu::Buffer Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["bufferCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -71,7 +69,6 @@ Item { title: "Num Textures" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUCount"] plots: [ { prop: "textureCPUCount", @@ -94,7 +91,6 @@ Item { title: "gpu::Texture Memory" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["textureCPUMemoryUsage"] valueScale: 1048576 valueUnit: "Mb" valueNumDigits: "1" @@ -116,7 +112,6 @@ Item { title: "Triangles" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameTriangleCount"] valueScale: 1000 valueUnit: "K" plots: [ @@ -138,7 +133,6 @@ Item { title: "Drawcalls" height: parent.evalEvenHeight() object: stats.config - trigger: stats.config["frameDrawcallCount"] plots: [ { prop: "frameAPIDrawcallCount", @@ -168,7 +162,6 @@ Item { title: "Items" height: parent.evalEvenHeight() object: parent.drawOpaqueConfig - trigger: Render.getConfig("DrawOpaqueDeferred")["numDrawn"] plots: [ { object: Render.getConfig("DrawOpaqueDeferred"), From 3c86191a59f7f68cdcb0526b071480151e598cb5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sat, 2 Apr 2016 17:17:06 -0700 Subject: [PATCH 09/11] Add resources prop to caches --- libraries/networking/src/ResourceCache.cpp | 10 ++++++++++ libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index c10b96ca19..1f687593bb 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -56,6 +56,16 @@ void ResourceCache::refresh(const QUrl& url) { } } +const QVariantList ResourceCache::getResourceList() const { + QVariantList list; + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } + return list; +} + void ResourceCache::setRequestLimit(int limit) { _requestLimit = limit; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index f113254995..3f930a1f11 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -83,6 +83,7 @@ class ResourceCache : public QObject { Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) + Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) public: int getNumTotalResources() const { return _resources.size(); } @@ -91,6 +92,8 @@ public: int getNumCachedResources() const { return _unusedResources.size(); } qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + const QVariantList getResourceList() const; + static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } From f34e951c3f06de3c04b27c2553a5cab82e4b8880 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:13 -0700 Subject: [PATCH 10/11] Make resource cache props thread-safe --- libraries/networking/src/ResourceCache.cpp | 32 ++++++++++++++++------ libraries/networking/src/ResourceCache.h | 31 +++++++++++++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1f687593bb..2e2b89046b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() { void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResource(); + resetResourceCounters(); // Refresh all remaining resources in use foreach (auto resource, _resources) { @@ -53,16 +54,24 @@ void ResourceCache::refresh(const QUrl& url) { resource->refresh(); } else { _resources.remove(url); + resetResourceCounters(); } } -const QVariantList ResourceCache::getResourceList() const { +QVariantList ResourceCache::getResourceList() { QVariantList list; - auto resources = _resources.uniqueKeys(); - list.reserve(resources.size()); - for (auto& resource : resources) { - list << resource; + if (QThread::currentThread() != thread()) { + // NOTE: invokeMethod does not allow a const QObject* + QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariantList, list)); + } else { + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } } + return list; } @@ -124,7 +133,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); - emit dirty(); + resetResourceCounters(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -138,7 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); - emit dirty(); + + resetResourceCounters(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -146,7 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } - emit dirty(); + resetResourceCounters(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -177,6 +187,12 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::resetResourceCounters() { + _numTotalResources = _resources.size(); + _numUnusedResources = _unusedResources.size(); + emit dirty(); +} + void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { _totalResourcesSize += (newSize - oldSize); emit dirty(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 3f930a1f11..933eb1a6d9 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -12,7 +12,9 @@ #ifndef hifi_ResourceCache_h #define hifi_ResourceCache_h +#include #include + #include #include #include @@ -29,6 +31,8 @@ #include "ResourceManager.h" +Q_DECLARE_METATYPE(size_t) + class QNetworkReply; class QTimer; @@ -79,20 +83,19 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT - Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) - Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) - Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) + Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) public: - int getNumTotalResources() const { return _resources.size(); } - qint64 getSizeTotalResources() const { return _totalResourcesSize; } + size_t getNumTotalResources() const { return _numTotalResources; } + size_t getSizeTotalResources() const { return _totalResourcesSize; } - int getNumCachedResources() const { return _unusedResources.size(); } - qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + size_t getNumCachedResources() const { return _numUnusedResources; } + size_t getSizeCachedResources() const { return _unusedResourcesSize; } - const QVariantList getResourceList() const; + Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -149,6 +152,7 @@ private: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); + void resetResourceCounters(); QHash> _resources; int _lastLRUKey = 0; @@ -160,8 +164,11 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; - qint64 _totalResourcesSize { 0 }; - qint64 _unusedResourcesSize { 0 }; + std::atomic _numTotalResources { 0 }; + std::atomic _numUnusedResources { 0 }; + + std::atomic _totalResourcesSize { 0 }; + std::atomic _unusedResourcesSize { 0 }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; QMap> _unusedResources; From 107cfcf10b5acf675a9fb5102b25c737f29663d2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:30 -0700 Subject: [PATCH 11/11] Change Resource setBytes->setSize --- .../model-networking/src/model-networking/TextureCache.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 4 ++-- libraries/networking/src/ResourceCache.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3ba36dc2da..2ffd7e18a0 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -338,7 +338,7 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth, if (gpuTexture) { _width = gpuTexture->getWidth(); _height = gpuTexture->getHeight(); - setBytes(gpuTexture->getStoredSize()); + setSize(gpuTexture->getStoredSize()); } else { // FIXME: If !gpuTexture, we failed to load! _width = _height = 0; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 2e2b89046b..c661c2f32a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -416,7 +416,7 @@ void Resource::finishedLoading(bool success) { emit finished(success); } -void Resource::setBytes(const qint64& bytes) { +void Resource::setSize(const qint64& bytes) { QMetaObject::invokeMethod(_cache.data(), "updateTotalSize", Q_ARG(qint64, _bytes), Q_ARG(qint64, bytes)); _bytes = bytes; } @@ -456,7 +456,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota void Resource::handleReplyFinished() { Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - setBytes(_bytesTotal); + setSize(_bytesTotal); if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 933eb1a6d9..84eba1cdc0 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -255,7 +255,7 @@ protected: virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); } /// Called when the download is finished and processed, sets the number of actual bytes. - void setBytes(const qint64& bytes); + void setSize(const qint64& bytes); /// Called when the download is finished and processed. /// This should be called by subclasses that override downloadFinished to mark the end of processing.