From 173d2a590c4bf265b441824754848590ffdd7480 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 6 May 2016 18:19:10 -0700 Subject: [PATCH] Use sleep_until for ScriptEngine --- assignment-client/src/Agent.cpp | 3 +- libraries/script-engine/src/ScriptEngine.cpp | 38 ++++++++++++++++---- libraries/script-engine/src/ScriptEngine.h | 4 +-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ef20dc82e2..f8f0f7904a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -386,8 +386,7 @@ void Agent::sendAvatarBillboardPacket() { void Agent::processAgentAvatarAndAudio(float deltaTime) { if (!_scriptEngine->isFinished() && _isAvatar) { auto scriptedAvatar = DependencyManager::get(); - const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * AudioConstants::SAMPLE_RATE) - / (1000 * 1000)) + 0.5); + const int SCRIPT_AUDIO_BUFFER_SAMPLES = AudioConstants::SAMPLE_RATE / SCRIPT_FPS + 0.5; const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); QByteArray avatarByteArray = scriptedAvatar->toByteArray(true, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6c7739c784..464b514fd5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include #include #include @@ -706,9 +709,15 @@ void ScriptEngine::run() { QScriptValue result = evaluate(_scriptContents, _fileNameString); - QElapsedTimer startTime; - startTime.start(); +#ifdef _WIN32 + // VS13 does not sleep_until unless it uses the system_clock, see: + // https://www.reddit.com/r/cpp_questions/comments/3o71ic/sleep_until_not_working_with_a_time_pointsteady/ + using clock = std::chrono::system_clock; +#else + using clock = std::chrono::high_resolution_clock; +#endif + clock::time_point startTime = clock::now(); int thisFrame = 0; auto nodeList = DependencyManager::get(); @@ -716,12 +725,29 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); + // TODO: Integrate this with signals/slots instead of this busy wait while (!_isFinished) { - int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec - if (usecToSleep > 0) { - usleep(usecToSleep); - } + // Throttle to SCRIPT_FPS + const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); + clock::time_point sleepTime(startTime + thisFrame++ * FRAME_DURATION); + std::this_thread::sleep_until(sleepTime); +#ifdef SCRIPT_DELAY_DEBUG + { + auto now = clock::now(); + uint64_t seconds = std::chrono::duration_cast(now - startTime).count(); + if (seconds > 0) { // avoid division by zero and time travel + uint64_t fps = thisFrame / seconds; + // Overreporting artificially reduces the reported rate + if (thisFrame % SCRIPT_FPS == 0) { + qCDebug(scriptengine) << + "Frame:" << thisFrame << + "Slept (us):" << std::chrono::duration_cast(now - sleepTime).count() << + "FPS:" << fps; + } + } + } +#endif if (_isFinished) { break; } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 175a3f1f1c..f050997235 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -39,9 +39,9 @@ #include "ScriptUUID.h" #include "Vec3.h" -const QString NO_SCRIPT(""); +static const QString NO_SCRIPT(""); -const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); +static const int SCRIPT_FPS = 60; class CallbackData { public: