diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 35d00ba34a..9052f082dc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -37,8 +37,6 @@ #include #include -#include - #include #include diff --git a/interface/src/Application.h b/interface/src/Application.h index cab42d1e1c..a7aded006b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -297,6 +297,7 @@ public: void setAvatarOverrideUrl(const QUrl& url, bool save); QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; } bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } + void setCacheOverrideDir(const QString& dirName) { _cacheDir = dirName; } signals: void svoImportRequested(const QString& url); @@ -688,5 +689,7 @@ private: QUrl _avatarOverrideUrl; bool _saveAvatarOverrideUrl { false }; + + QString _cacheDir; }; #endif // hifi_Application_h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 83cac6d9bb..67e248506f 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "AddressManager.h" #include "Application.h" @@ -71,15 +72,17 @@ int main(int argc, const char* argv[]) { QCommandLineOption runServerOption("runServer", "Whether to run the server"); QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath"); QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run"); + QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache ", "dir"); parser.addOption(urlOption); parser.addOption(noUpdaterOption); parser.addOption(checkMinSpecOption); parser.addOption(runServerOption); parser.addOption(serverContentPathOption); + parser.addOption(overrideAppLocalDataPathOption); parser.addOption(allowMultipleInstancesOption); parser.parse(arguments); - + const QString& applicationName = getInterfaceSharedMemoryName(); bool instanceMightBeRunning = true; #ifdef Q_OS_WIN @@ -96,6 +99,19 @@ int main(int argc, const char* argv[]) { if (allowMultipleInstances) { instanceMightBeRunning = false; } + if (parser.isSet(overrideAppLocalDataPathOption)) { + // get dir to use for cache + QString cacheDir = parser.value(overrideAppLocalDataPathOption); + if (!cacheDir.isEmpty()) { + // tell everyone to use the right cache location + // + // this handles data8 and prepared + ResourceManager::setCacheDir(cacheDir); + + // this does the ktx_cache + PathUtils::getAppLocalDataPath(cacheDir); + } + } if (instanceMightBeRunning) { // Try to connect and send message to existing interface instance @@ -179,7 +195,7 @@ int main(int argc, const char* argv[]) { QString openvrDllPath = appPath + "/plugins/openvr.dll"; HMODULE openvrDll; CHECKMINSPECPROC checkMinSpecPtr; - if ((openvrDll = LoadLibrary(openvrDllPath.toLocal8Bit().data())) && + if ((openvrDll = LoadLibrary(openvrDllPath.toLocal8Bit().data())) && (checkMinSpecPtr = (CHECKMINSPECPROC)GetProcAddress(openvrDll, "CheckMinSpec"))) { if (!checkMinSpecPtr()) { return -1; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 3faa9981dc..e97660da4c 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -31,7 +31,7 @@ MessageID AssetClient::_currentID = 0; -AssetClient::AssetClient() { +AssetClient::AssetClient(const QString& cacheDir) : _cacheDir(cacheDir) { setCustomDeleter([](Dependency* dependency){ static_cast(dependency)->deleteLater(); }); @@ -55,14 +55,15 @@ void AssetClient::init() { // Setup disk cache if not already auto& networkAccessManager = NetworkAccessManager::getInstance(); if (!networkAccessManager.cache()) { - QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - cachePath = !cachePath.isEmpty() ? cachePath : "interfaceCache"; - + if (_cacheDir.isEmpty()) { + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + _cacheDir = !cachePath.isEmpty() ? cachePath : "interfaceCache"; + } QNetworkDiskCache* cache = new QNetworkDiskCache(); cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); - cache->setCacheDirectory(cachePath); + cache->setCacheDirectory(_cacheDir); networkAccessManager.setCache(cache); - qInfo() << "ResourceManager disk cache setup at" << cachePath + qInfo() << "ResourceManager disk cache setup at" << _cacheDir << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index cab4a4f5b0..2bc694f367 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -49,7 +49,7 @@ using ProgressCallback = std::function class AssetClient : public QObject, public Dependency { Q_OBJECT public: - AssetClient(); + AssetClient(const QString& cacheDir=""); Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path); Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest(); @@ -109,6 +109,8 @@ private: std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; + QString _cacheDir; + friend class AssetRequest; friend class AssetUpload; friend class MappingRequest; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index e2c1cf2431..e4357ca507 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -27,7 +27,7 @@ QThread ResourceManager::_thread; ResourceManager::PrefixMap ResourceManager::_prefixMap; QMutex ResourceManager::_prefixMapLock; - +QString ResourceManager::_cacheDir; void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) { QMutexLocker locker(&_prefixMapLock); @@ -78,7 +78,7 @@ QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) { void ResourceManager::init() { _thread.setObjectName("Resource Manager Thread"); - auto assetClient = DependencyManager::set(); + auto assetClient = DependencyManager::set(_cacheDir); assetClient->moveToThread(&_thread); QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init); @@ -164,3 +164,7 @@ bool ResourceManager::resourceExists(const QUrl& url) { return false; } +void ResourceManager::setCacheDir(const QString& cacheDir) { + // TODO: check for existence? + _cacheDir = cacheDir; +} diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index 41da892701..699573ddd6 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -40,6 +40,9 @@ public: // to return to the calling thread so that events can still be processed. static bool resourceExists(const QUrl& url); + // adjust where we persist the cache + static void setCacheDir(const QString& cacheDir); + private: static QThread _thread; @@ -47,6 +50,8 @@ private: static PrefixMap _prefixMap; static QMutex _prefixMapLock; + + static QString _cacheDir; }; #endif diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d9b41bb55d..48f8b07a4a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1067,24 +1067,21 @@ void ScriptEngine::run() { // on shutdown and stop... so we want to loop and sleep until we've spent our time in // purgatory, constantly checking to see if our script was asked to end bool processedEvents = false; - while (!_isFinished && clock::now() < sleepUntil) { - - { - PROFILE_RANGE(script, "processEvents-sleep"); - QCoreApplication::processEvents(); // before we sleep again, give events a chance to process + if (!_isFinished) { + PROFILE_RANGE(script, "processEvents-sleep"); + std::chrono::milliseconds sleepFor = + std::chrono::duration_cast(sleepUntil - clock::now()); + if (sleepFor > std::chrono::milliseconds(0)) { + QEventLoop loop; + QTimer timer; + timer.setSingleShot(true); + connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.start(sleepFor.count()); + loop.exec(); + } else { + QCoreApplication::processEvents(); } processedEvents = true; - - // If after processing events, we're past due, exit asap - if (clock::now() >= sleepUntil) { - break; - } - - // We only want to sleep a small amount so that any pending events (like timers or invokeMethod events) - // will be able to process quickly. - static const int SMALL_SLEEP_AMOUNT = 100; - auto smallSleepUntil = clock::now() + static_cast(SMALL_SLEEP_AMOUNT); - std::this_thread::sleep_until(smallSleepUntil); } PROFILE_RANGE(script, "ScriptMainLoop"); @@ -1309,6 +1306,7 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int // make sure the timer stops when the script does connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + CallbackData timerData = { function, currentEntityIdentifier, currentSandboxURL }; _timerFunctionMap.insert(newTimer, timerData); @@ -1392,6 +1390,15 @@ void ScriptEngine::print(const QString& message) { emit printedMessage(message, getFilename()); } + +void ScriptEngine::beginProfileRange(const QString& label) const { + PROFILE_SYNC_BEGIN(script, label.toStdString().c_str(), label.toStdString().c_str()); +} + +void ScriptEngine::endProfileRange(const QString& label) const { + PROFILE_SYNC_END(script, label.toStdString().c_str(), label.toStdString().c_str()); +} + // Script.require.resolve -- like resolvePath, but performs more validation and throws exceptions on invalid module identifiers (for consistency with Node.js) QString ScriptEngine::_requireResolve(const QString& moduleId, const QString& relativeTo) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 9da8603814..7c473a305b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -43,6 +43,7 @@ #include "Vec3.h" #include "ConsoleScriptingInterface.h" #include "SettingHandle.h" +#include "Profile.h" class QScriptEngineDebugger; @@ -182,6 +183,8 @@ public: Q_INVOKABLE void print(const QString& message); Q_INVOKABLE QUrl resolvePath(const QString& path) const; Q_INVOKABLE QUrl resourcesPath() const; + Q_INVOKABLE void beginProfileRange(const QString& label) const; + Q_INVOKABLE void endProfileRange(const QString& label) const; // Entity Script Related methods Q_INVOKABLE bool isEntityScriptRunning(const EntityItemID& entityID) { diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index 9bf9d7bdcf..1fe9e2f83d 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -34,7 +34,18 @@ QString PathUtils::getAppDataPath() { return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/"; } -QString PathUtils::getAppLocalDataPath() { +QString PathUtils::getAppLocalDataPath(const QString& overridePath /* = "" */) { + static QString overriddenPath = ""; + // set the overridden path if one was passed in + if (!overridePath.isEmpty()) { + overriddenPath = overridePath; + } + // return overridden path if set + if (!overriddenPath.isEmpty()) { + return overriddenPath; + } + + // otherwise return standard path return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/"; } diff --git a/libraries/shared/src/PathUtils.h b/libraries/shared/src/PathUtils.h index 14eb81dd9a..42dd09c8b0 100644 --- a/libraries/shared/src/PathUtils.h +++ b/libraries/shared/src/PathUtils.h @@ -28,7 +28,7 @@ public: static const QString& resourcesPath(); static QString getAppDataPath(); - static QString getAppLocalDataPath(); + static QString getAppLocalDataPath(const QString& overridePath = ""); static QString getAppDataFilePath(const QString& filename); static QString getAppLocalDataFilePath(const QString& filename); diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index ee09298deb..5de4e8f41a 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -46,6 +46,20 @@ private: const QLoggingCategory& _category; }; + +inline void syncBegin(const QLoggingCategory& category, const QString& name, const QString& id, const QVariantMap& args = QVariantMap(), const QVariantMap& extra = QVariantMap()) { + if (category.isDebugEnabled()) { + tracing::traceEvent(category, name, tracing::DurationBegin, id, args, extra); + } +} + + +inline void syncEnd(const QLoggingCategory& category, const QString& name, const QString& id, const QVariantMap& args = QVariantMap(), const QVariantMap& extra = QVariantMap()) { + if (category.isDebugEnabled()) { + tracing::traceEvent(category, name, tracing::DurationEnd, id, args, extra); + } +} + inline void asyncBegin(const QLoggingCategory& category, const QString& name, const QString& id, const QVariantMap& args = QVariantMap(), const QVariantMap& extra = QVariantMap()) { if (category.isDebugEnabled()) { tracing::traceEvent(category, name, tracing::AsyncNestableStart, id, args, extra); @@ -80,6 +94,8 @@ inline void metadata(const QString& metadataType, const QVariantMap& args) { #define PROFILE_RANGE_EX(category, name, argbColor, payload, ...) Duration profileRangeThis(trace_##category(), name, argbColor, (uint64_t)payload, ##__VA_ARGS__); #define PROFILE_RANGE_BEGIN(category, rangeId, name, argbColor) rangeId = Duration::beginRange(trace_##category(), name, argbColor) #define PROFILE_RANGE_END(category, rangeId) Duration::endRange(trace_##category(), rangeId) +#define PROFILE_SYNC_BEGIN(category, name, id, ...) syncBegin(trace_##category(), name, id, ##__VA_ARGS__); +#define PROFILE_SYNC_END(category, name, id, ...) syncEnd(trace_##category(), name, id, ##__VA_ARGS__); #define PROFILE_ASYNC_BEGIN(category, name, id, ...) asyncBegin(trace_##category(), name, id, ##__VA_ARGS__); #define PROFILE_ASYNC_END(category, name, id, ...) asyncEnd(trace_##category(), name, id, ##__VA_ARGS__); #define PROFILE_COUNTER_IF_CHANGED(category, name, type, value) { static type lastValue = 0; type newValue = value; if (newValue != lastValue) { counter(trace_##category(), name, { { name, newValue }}); lastValue = newValue; } }