From f9d14e135149d977640f09308ec791cf6fb52b28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Aug 2018 11:17:11 -0700 Subject: [PATCH 1/3] filter time-cost drivers for region regulation --- interface/src/Application.cpp | 14 +++-- libraries/shared/src/NumericalConstants.h | 1 + libraries/workload/src/workload/Space.h | 3 +- libraries/workload/src/workload/ViewTask.cpp | 56 +++++++++++++++----- libraries/workload/src/workload/ViewTask.h | 29 ++++++---- 5 files changed, 73 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44bba6250b..0c25fd59a9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5795,15 +5795,13 @@ void Application::update(float deltaTime) { auto t5 = std::chrono::high_resolution_clock::now(); workload::Timings timings(6); - timings[0] = (t4 - t0); - timings[1] = (t5 - t4); - timings[2] = (t4 - t3); - timings[3] = (t3 - t2); - timings[4] = (t2 - t1); - timings[5] = (t1 - t0); - + timings[0] = t1 - t0; // prePhysics entities + timings[1] = t2 - t1; // prePhysics avatars + timings[2] = t3 - t2; // stepPhysics + timings[3] = t4 - t3; // postPhysics + timings[4] = t5 - t4; // non-physical kinematics + timings[5] = workload::Timing_ns((int32_t)(NSECS_PER_SECOND * deltaTime)); // game loop duration _gameWorkload.updateSimulationTimings(timings); - } } } else { diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index 4c24a73226..8377c48960 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -36,6 +36,7 @@ const float METERS_PER_MILLIMETER = 0.001f; const float MILLIMETERS_PER_METER = 1000.0f; const quint64 NSECS_PER_USEC = 1000; const quint64 NSECS_PER_MSEC = 1000000; +const quint64 NSECS_PER_SECOND = 1e9; const quint64 USECS_PER_MSEC = 1000; const quint64 MSECS_PER_SECOND = 1000; const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; diff --git a/libraries/workload/src/workload/Space.h b/libraries/workload/src/workload/Space.h index 310955f4c6..7dcb2217f7 100644 --- a/libraries/workload/src/workload/Space.h +++ b/libraries/workload/src/workload/Space.h @@ -70,7 +70,8 @@ private: using SpacePointer = std::shared_ptr; using Changes = std::vector; using IndexVectors = std::vector; -using Timings = std::vector; +using Timing_ns = std::chrono::nanoseconds; +using Timings = std::vector; } // namespace workload diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index 5d9953cdf4..b05a4c0c5f 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -102,9 +102,16 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const // Export the ranges and timings for debuging if (inTimings.size()) { - _dataExport.timings[workload::Region::R1] = std::chrono::duration(inTimings[0]).count(); + // NOTE for reference: + // inTimings[0] = prePhysics entities + // inTimings[1] = prePhysics avatars + // inTimings[2] = stepPhysics + // inTimings[3] = postPhysics + // inTimings[4] = non-physical kinematics + // inTimings[5] = game loop + _dataExport.timings[workload::Region::R1] = std::chrono::duration(inTimings[2] + inTimings[3]).count(); _dataExport.timings[workload::Region::R2] = _dataExport.timings[workload::Region::R1]; - _dataExport.timings[workload::Region::R3] = std::chrono::duration(inTimings[1]).count(); + _dataExport.timings[workload::Region::R3] = std::chrono::duration(inTimings[4]).count(); doExport = true; } @@ -115,11 +122,29 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const } } -glm::vec2 Regulator::run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current) { - // Regulate next value based on current moving toward the goal budget - float error_ms = std::chrono::duration(_budget - measured).count(); - float coef = glm::clamp(error_ms / std::chrono::duration(regulationDuration).count(), -1.0f, 1.0f); - return current * (1.0f + coef * (error_ms < 0.0f ? _relativeStepDown : _relativeStepUp)); +glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack) { + // measure signal: average and noise + const float FILTER_TIMESCALE = 0.5f * (float)NSECS_PER_SECOND; + float del = deltaTime.count() / FILTER_TIMESCALE; + if (del > 1.0f) { + del = 1.0f; // clamp for stability + } + _measuredTimeAverage = (1.0f - del) * _measuredTimeAverage + del * measuredTime.count(); + float diff = measuredTime.count() - _measuredTimeAverage; + _measuredTimeNoiseSquared = (1.0f - del) * _measuredTimeNoiseSquared + del * diff * diff; + float noise = sqrtf(_measuredTimeNoiseSquared); + + // check budget + float budgetDelta = _budget.count() - _measuredTimeAverage; + if (abs(budgetDelta) < noise) { + // budget is within the noise + return currentFrontBack; + } + + // clamp the step factor + del = budgetDelta < 0.0f ? -_relativeStepDown: _relativeStepUp; + + return currentFrontBack * (1.0f + del); } glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { @@ -128,17 +153,24 @@ glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { } void ControlViews::regulateViews(workload::Views& outViews, const workload::Timings& timings) { - for (auto& outView : outViews) { for (int32_t r = 0; r < workload::Region::NUM_VIEW_REGIONS; r++) { outView.regionBackFronts[r] = regionBackFronts[r]; } } - auto loopDuration = std::chrono::nanoseconds{ std::chrono::milliseconds(16) }; - regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[0], regionBackFronts[workload::Region::R1]); - regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[0], regionBackFronts[workload::Region::R2]); - regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[1], regionBackFronts[workload::Region::R3]); + // Note: for reference: + // timings[0] = prePhysics entities + // timings[1] = prePhysics avatars + // timings[2] = stepPhysics + // timings[3] = postPhysics + // timings[4] = non-physical kinematics + // timings[5] = game loop + + auto loopDuration = timings[5]; + regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R1]); + regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R2]); + regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[4], regionBackFronts[workload::Region::R3]); enforceRegionContainment(); for (auto& outView : outViews) { diff --git a/libraries/workload/src/workload/ViewTask.h b/libraries/workload/src/workload/ViewTask.h index 4fdd7e0f4c..7c1e4944f5 100644 --- a/libraries/workload/src/workload/ViewTask.h +++ b/libraries/workload/src/workload/ViewTask.h @@ -37,8 +37,8 @@ namespace workload { { 250.0f, 16000.0f } }; - const float RELATIVE_STEP_DOWN = 0.05f; - const float RELATIVE_STEP_UP = 0.04f; + const float RELATIVE_STEP_DOWN = 0.11f; + const float RELATIVE_STEP_UP = 0.09f; class SetupViewsConfig : public Job::Config{ Q_OBJECT @@ -212,20 +212,31 @@ namespace workload { }; struct Regulator { - using Timing_ns = std::chrono::nanoseconds; - Timing_ns _budget{ std::chrono::milliseconds(2) }; glm::vec2 _minRange{ MIN_VIEW_BACK_FRONTS[0] }; glm::vec2 _maxRange{ MAX_VIEW_BACK_FRONTS[0] }; - glm::vec2 _relativeStepDown{ RELATIVE_STEP_DOWN }; glm::vec2 _relativeStepUp{ RELATIVE_STEP_UP }; - + Timing_ns _budget{ std::chrono::milliseconds(2) }; + float _measuredTimeAverage { 0.0f }; + float _measuredTimeNoiseSquared { 0.0f }; Regulator() {} - Regulator(const Timing_ns& budget_ns, const glm::vec2& minRange, const glm::vec2& maxRange, const glm::vec2& relativeStepDown, const glm::vec2& relativeStepUp) : - _budget(budget_ns), _minRange(minRange), _maxRange(maxRange), _relativeStepDown(relativeStepDown), _relativeStepUp(relativeStepUp) {} + Regulator(const Timing_ns& budget_ns, + const glm::vec2& minRange, + const glm::vec2& maxRange, + const glm::vec2& relativeStepDown, + const glm::vec2& relativeStepUp) : + _minRange(minRange), + _maxRange(maxRange), + _relativeStepDown(relativeStepDown), + _relativeStepUp(relativeStepUp), + _budget(budget_ns), + _measuredTimeAverage(budget_ns.count()), + _measuredTimeNoiseSquared(0.0f) + {} - glm::vec2 run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current); + void setBudget(const Timing_ns& budget) { _budget = budget; } + glm::vec2 run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack); glm::vec2 clamp(const glm::vec2& backFront) const; }; From a134357489173f6c34d9d1a9ee51faf9ba30a0c8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Aug 2018 11:37:19 -0700 Subject: [PATCH 2/3] fix compile typo --- libraries/workload/src/workload/ViewTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index b05a4c0c5f..27b136d64e 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -142,9 +142,9 @@ glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTi } // clamp the step factor - del = budgetDelta < 0.0f ? -_relativeStepDown: _relativeStepUp; + glm::vec2 stepDelta = budgetDelta < 0.0f ? -_relativeStepDown : _relativeStepUp; - return currentFrontBack * (1.0f + del); + return currentFrontBack * (1.0f + stepDelta); } glm::vec2 Regulator::clamp(const glm::vec2& backFront) const { From 6c4862910e70fe0236b8ce9e4539a03c205fe802 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Aug 2018 10:13:35 -0700 Subject: [PATCH 3/3] smoother edges for workload region feedback response --- libraries/workload/src/workload/ViewTask.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/workload/src/workload/ViewTask.cpp b/libraries/workload/src/workload/ViewTask.cpp index 27b136d64e..9d0c693149 100644 --- a/libraries/workload/src/workload/ViewTask.cpp +++ b/libraries/workload/src/workload/ViewTask.cpp @@ -135,15 +135,15 @@ glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTi float noise = sqrtf(_measuredTimeNoiseSquared); // check budget - float budgetDelta = _budget.count() - _measuredTimeAverage; - if (abs(budgetDelta) < noise) { - // budget is within the noise + float offsetFromTarget = _budget.count() - _measuredTimeAverage; + if (fabsf(offsetFromTarget) < noise) { + // budget is within the noise --> do nothing return currentFrontBack; } - // clamp the step factor - glm::vec2 stepDelta = budgetDelta < 0.0f ? -_relativeStepDown : _relativeStepUp; - + // compute response + glm::vec2 stepDelta = offsetFromTarget < 0.0f ? -_relativeStepDown : _relativeStepUp; + stepDelta *= glm::min(1.0f, (fabsf(offsetFromTarget) - noise) / noise); // ease out of "do nothing" return currentFrontBack * (1.0f + stepDelta); }