From 9f0084dbb13343bebef975f3d00f4dc6431c2731 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 22 Mar 2016 16:01:31 -0700 Subject: [PATCH 1/5] make Blender keep a shared pointer to the model it's blending --- libraries/render-utils/src/Model.cpp | 19 +++++++++---------- libraries/render-utils/src/Model.h | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index df186802f6..0a483914df 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -29,7 +29,7 @@ using namespace std; -static int modelPointerTypeId = qRegisterMetaType >(); +static int nakedModelPointerTypeId = qRegisterMetaType(); static int weakNetworkGeometryPointerTypeId = qRegisterMetaType >(); static int vec3VectorTypeId = qRegisterMetaType >(); float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; @@ -821,21 +821,21 @@ QStringList Model::getJointNames() const { class Blender : public QRunnable { public: - Blender(Model* model, int blendNumber, const QWeakPointer& geometry, + Blender(ModelPointer model, int blendNumber, const QWeakPointer& geometry, const QVector& meshes, const QVector& blendshapeCoefficients); virtual void run(); private: - QPointer _model; + ModelPointer _model; int _blendNumber; QWeakPointer _geometry; QVector _meshes; QVector _blendshapeCoefficients; }; -Blender::Blender(Model* model, int blendNumber, const QWeakPointer& geometry, +Blender::Blender(ModelPointer model, int blendNumber, const QWeakPointer& geometry, const QVector& meshes, const QVector& blendshapeCoefficients) : _model(model), _blendNumber(blendNumber), @@ -847,7 +847,7 @@ Blender::Blender(Model* model, int blendNumber, const QWeakPointer vertices, normals; - if (!_model.isNull()) { + if (_model) { int offset = 0; foreach (const FBXMesh& mesh, _meshes) { if (mesh.blendshapes.isEmpty()) { @@ -877,7 +877,7 @@ void Blender::run() { } // post the result to the geometry cache, which will dispatch to the model if still alive QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices", - Q_ARG(const QPointer&, _model), Q_ARG(int, _blendNumber), + Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(const QWeakPointer&, _geometry), Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); } @@ -1088,7 +1088,7 @@ float Model::getLimbLength(int jointIndex) const { bool Model::maybeStartBlender() { const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); if (fbxGeometry.hasBlendedMeshes()) { - QThreadPool::globalInstance()->start(new Blender(this, ++_blendNumber, _geometry, + QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry, fbxGeometry.meshes, _blendshapeCoefficients)); return true; } @@ -1284,10 +1284,9 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { } } -void ModelBlender::setBlendedVertices(const QPointer& model, int blendNumber, +void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const QWeakPointer& geometry, const QVector& vertices, const QVector& normals) { - - if (!model.isNull()) { + if (model) { model->setBlendedVertices(blendNumber, geometry, vertices, normals); } _pendingBlenders--; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 53ed82f418..4e51dc4f33 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -384,7 +384,7 @@ protected: RigPointer _rig; }; -Q_DECLARE_METATYPE(QPointer) +Q_DECLARE_METATYPE(ModelPointer) Q_DECLARE_METATYPE(QWeakPointer) /// Handle management of pending models that need blending @@ -398,7 +398,7 @@ public: void noteRequiresBlend(ModelPointer model); public slots: - void setBlendedVertices(const QPointer& model, int blendNumber, const QWeakPointer& geometry, + void setBlendedVertices(ModelPointer model, int blendNumber, const QWeakPointer& geometry, const QVector& vertices, const QVector& normals); private: From 9c11474dd78785eb8811b1084847534c480acbcf Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Mar 2016 15:39:03 -0700 Subject: [PATCH 2/5] Expose qApp->updateHeartbeat --- interface/src/Application.cpp | 24 ++++++++++++------------ interface/src/Application.h | 4 ++++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e88ea28dc..65a8f83871 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -239,11 +239,7 @@ class DeadlockWatchdogThread : public QThread { public: static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; -#ifdef DEBUG - static const unsigned long MAX_HEARTBEAT_AGE_USECS = 600 * USECS_PER_SECOND; -#else static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND; -#endif // Set the heartbeat on launch DeadlockWatchdogThread() { @@ -511,8 +507,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : auto nodeList = DependencyManager::get(); // Set up a watchdog thread to intentionally crash the application on deadlocks - auto deadlockWatchdog = new DeadlockWatchdogThread(); - deadlockWatchdog->start(); + _deadlockWatchdogThread = new DeadlockWatchdogThread(); + _deadlockWatchdogThread->start(); qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); @@ -586,7 +582,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : ResourceManager::init(); // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); // Setup MessagesClient auto messagesClient = DependencyManager::get(); @@ -734,7 +730,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : initializeGL(); _offscreenContext->makeCurrent(); // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); // Tell our entity edit sender about our known jurisdictions _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); @@ -746,7 +742,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _overlays.init(); // do this before scripts load // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit())); @@ -900,11 +896,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // do this as late as possible so that all required subsystems are initialized scriptEngines->loadScripts(); // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); loadSettings(); // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings); @@ -1019,7 +1015,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : }); // Make sure we don't time out during slow operations at startup - deadlockWatchdog->updateHeartbeat(); + updateHeartbeat(); connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); @@ -1060,6 +1056,10 @@ void Application::showCursor(const QCursor& cursor) { _cursorNeedsChanging = true; } +void Application::updateHeartbeat() { + static_cast(_deadlockWatchdogThread)->updateHeartbeat(); +} + void Application::aboutToQuit() { emit beforeAboutToQuit(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4c12164a5f..3b906a7d17 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -271,6 +271,8 @@ public slots: void reloadResourceCaches(); + void updateHeartbeat(); + void crashApplication(); void deadlockApplication(); @@ -505,6 +507,8 @@ private: mutable QMutex _changeCursorLock { QMutex::Recursive }; QCursor _desiredCursor{ Qt::BlankCursor }; bool _cursorNeedsChanging { false }; + + QThread* _deadlockWatchdogThread; }; #endif // hifi_Application_h From 745438148a760b10260d832dcfbeb99f5851c112 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 22 Mar 2016 17:17:36 -0700 Subject: [PATCH 3/5] Reset deadlock watch before qml load --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 563c590874..4cfd2527ea 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -426,7 +426,11 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { } QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function f) { - _qmlComponent->loadUrl(qmlSource); + // Synchronous loading may take a while; restart the deadlock timer + QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); + + _qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous); + if (_qmlComponent->isLoading()) { connect(_qmlComponent, &QQmlComponent::statusChanged, this, [this, f](QQmlComponent::Status){ From 2fdb92e8cded5675ad64c64db4f218b9728f03ed Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 22 Mar 2016 22:19:10 -0700 Subject: [PATCH 4/5] Move oglplus dependency from sourceforge to s3 --- cmake/externals/oglplus/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/oglplus/CMakeLists.txt b/cmake/externals/oglplus/CMakeLists.txt index 43730129a0..089ee5bb95 100644 --- a/cmake/externals/oglplus/CMakeLists.txt +++ b/cmake/externals/oglplus/CMakeLists.txt @@ -4,7 +4,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://iweb.dl.sourceforge.net/project/oglplus/oglplus-0.63.x/oglplus-0.63.0.zip + URL http://hifi-public.s3.amazonaws.com/dependencies/oglplus-0.63.0.zip URL_MD5 de984ab245b185b45c87415c0e052135 CONFIGURE_COMMAND "" BUILD_COMMAND "" From 252a49eea4ea92c88d1baf4d021a840bd246e0e7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 22 Mar 2016 20:21:36 -0700 Subject: [PATCH 5/5] Add a tracker and logging of memory allocated by the GPU library --- libraries/gpu/src/gpu/Resource.cpp | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index 1788f6ece5..197263f392 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -10,11 +10,74 @@ // #include "Resource.h" +#include + +#include +#include #include using namespace gpu; +class AllocationDebugger { +public: + void operator+=(size_t size) { + _allocatedMemory += size; + maybeReport(); + } + + void operator-=(size_t size) { + _allocatedMemory -= size; + maybeReport(); + } + +private: + QString formatSize(size_t size) { + float num = size; + QStringList list; + list << "KB" << "MB" << "GB" << "TB"; + + QStringListIterator i(list); + QString unit("bytes"); + + while (num >= K && i.hasNext()) { + unit = i.next(); + num /= K; + } + return QString().setNum(num, 'f', 2) + " " + unit; + } + + void maybeReport() { + auto now = usecTimestampNow(); + if (now - _lastReportTime < MAX_REPORT_FREQUENCY) { + return; + } + size_t current = _allocatedMemory; + size_t last = _lastReportedMemory; + size_t delta = (current > last) ? (current - last) : (last - current); + if (delta > MIN_REPORT_DELTA) { + _lastReportTime = now; + _lastReportedMemory = current; + qDebug() << "Total allocation " << formatSize(current); + } + } + + std::atomic _allocatedMemory; + std::atomic _lastReportedMemory; + std::atomic _lastReportTime; + + static const float K; + // Report changes of 5 megabytes + static const size_t MIN_REPORT_DELTA = 1024 * 1024 * 5; + // Report changes no more frequently than every 15 seconds + static const uint64_t MAX_REPORT_FREQUENCY = USECS_PER_SECOND * 15; +}; + +const float AllocationDebugger::K = 1024.0f; + +static AllocationDebugger allocationDebugger; + Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) { + allocationDebugger += size; if ( !dataAllocated ) { qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer."; return NOT_ALLOCATED; @@ -38,6 +101,7 @@ Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) } void Resource::Sysmem::deallocateMemory(Byte* dataAllocated, Size size) { + allocationDebugger -= size; if (dataAllocated) { delete[] dataAllocated; }