mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-31 09:52:15 +02:00
Merge pull request #13896 from AndrewMeadows/workload-feedback
Filter timings used in feedback logic for workload region sizes
This commit is contained in:
commit
a7fd35747d
5 changed files with 73 additions and 30 deletions
|
@ -5820,15 +5820,13 @@ void Application::update(float deltaTime) {
|
||||||
auto t5 = std::chrono::high_resolution_clock::now();
|
auto t5 = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
workload::Timings timings(6);
|
workload::Timings timings(6);
|
||||||
timings[0] = (t4 - t0);
|
timings[0] = t1 - t0; // prePhysics entities
|
||||||
timings[1] = (t5 - t4);
|
timings[1] = t2 - t1; // prePhysics avatars
|
||||||
timings[2] = (t4 - t3);
|
timings[2] = t3 - t2; // stepPhysics
|
||||||
timings[3] = (t3 - t2);
|
timings[3] = t4 - t3; // postPhysics
|
||||||
timings[4] = (t2 - t1);
|
timings[4] = t5 - t4; // non-physical kinematics
|
||||||
timings[5] = (t1 - t0);
|
timings[5] = workload::Timing_ns((int32_t)(NSECS_PER_SECOND * deltaTime)); // game loop duration
|
||||||
|
|
||||||
_gameWorkload.updateSimulationTimings(timings);
|
_gameWorkload.updateSimulationTimings(timings);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -36,6 +36,7 @@ const float METERS_PER_MILLIMETER = 0.001f;
|
||||||
const float MILLIMETERS_PER_METER = 1000.0f;
|
const float MILLIMETERS_PER_METER = 1000.0f;
|
||||||
const quint64 NSECS_PER_USEC = 1000;
|
const quint64 NSECS_PER_USEC = 1000;
|
||||||
const quint64 NSECS_PER_MSEC = 1000000;
|
const quint64 NSECS_PER_MSEC = 1000000;
|
||||||
|
const quint64 NSECS_PER_SECOND = 1e9;
|
||||||
const quint64 USECS_PER_MSEC = 1000;
|
const quint64 USECS_PER_MSEC = 1000;
|
||||||
const quint64 MSECS_PER_SECOND = 1000;
|
const quint64 MSECS_PER_SECOND = 1000;
|
||||||
const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND;
|
const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND;
|
||||||
|
|
|
@ -70,7 +70,8 @@ private:
|
||||||
using SpacePointer = std::shared_ptr<Space>;
|
using SpacePointer = std::shared_ptr<Space>;
|
||||||
using Changes = std::vector<Space::Change>;
|
using Changes = std::vector<Space::Change>;
|
||||||
using IndexVectors = std::vector<IndexVector>;
|
using IndexVectors = std::vector<IndexVector>;
|
||||||
using Timings = std::vector<std::chrono::nanoseconds>;
|
using Timing_ns = std::chrono::nanoseconds;
|
||||||
|
using Timings = std::vector<Timing_ns>;
|
||||||
|
|
||||||
} // namespace workload
|
} // namespace workload
|
||||||
|
|
||||||
|
|
|
@ -102,9 +102,16 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const
|
||||||
|
|
||||||
// Export the ranges and timings for debuging
|
// Export the ranges and timings for debuging
|
||||||
if (inTimings.size()) {
|
if (inTimings.size()) {
|
||||||
_dataExport.timings[workload::Region::R1] = std::chrono::duration<float, std::milli>(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<float, std::milli>(inTimings[2] + inTimings[3]).count();
|
||||||
_dataExport.timings[workload::Region::R2] = _dataExport.timings[workload::Region::R1];
|
_dataExport.timings[workload::Region::R2] = _dataExport.timings[workload::Region::R1];
|
||||||
_dataExport.timings[workload::Region::R3] = std::chrono::duration<float, std::milli>(inTimings[1]).count();
|
_dataExport.timings[workload::Region::R3] = std::chrono::duration<float, std::milli>(inTimings[4]).count();
|
||||||
doExport = true;
|
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) {
|
glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack) {
|
||||||
// Regulate next value based on current moving toward the goal budget
|
// measure signal: average and noise
|
||||||
float error_ms = std::chrono::duration<float, std::milli>(_budget - measured).count();
|
const float FILTER_TIMESCALE = 0.5f * (float)NSECS_PER_SECOND;
|
||||||
float coef = glm::clamp(error_ms / std::chrono::duration<float, std::milli>(regulationDuration).count(), -1.0f, 1.0f);
|
float del = deltaTime.count() / FILTER_TIMESCALE;
|
||||||
return current * (1.0f + coef * (error_ms < 0.0f ? _relativeStepDown : _relativeStepUp));
|
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 offsetFromTarget = _budget.count() - _measuredTimeAverage;
|
||||||
|
if (fabsf(offsetFromTarget) < noise) {
|
||||||
|
// budget is within the noise --> do nothing
|
||||||
|
return currentFrontBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Regulator::clamp(const glm::vec2& backFront) const {
|
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) {
|
void ControlViews::regulateViews(workload::Views& outViews, const workload::Timings& timings) {
|
||||||
|
|
||||||
for (auto& outView : outViews) {
|
for (auto& outView : outViews) {
|
||||||
for (int32_t r = 0; r < workload::Region::NUM_VIEW_REGIONS; r++) {
|
for (int32_t r = 0; r < workload::Region::NUM_VIEW_REGIONS; r++) {
|
||||||
outView.regionBackFronts[r] = regionBackFronts[r];
|
outView.regionBackFronts[r] = regionBackFronts[r];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto loopDuration = std::chrono::nanoseconds{ std::chrono::milliseconds(16) };
|
// Note: for reference:
|
||||||
regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[0], regionBackFronts[workload::Region::R1]);
|
// timings[0] = prePhysics entities
|
||||||
regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[0], regionBackFronts[workload::Region::R2]);
|
// timings[1] = prePhysics avatars
|
||||||
regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[1], regionBackFronts[workload::Region::R3]);
|
// 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();
|
enforceRegionContainment();
|
||||||
for (auto& outView : outViews) {
|
for (auto& outView : outViews) {
|
||||||
|
|
|
@ -37,8 +37,8 @@ namespace workload {
|
||||||
{ 250.0f, 16000.0f }
|
{ 250.0f, 16000.0f }
|
||||||
};
|
};
|
||||||
|
|
||||||
const float RELATIVE_STEP_DOWN = 0.05f;
|
const float RELATIVE_STEP_DOWN = 0.11f;
|
||||||
const float RELATIVE_STEP_UP = 0.04f;
|
const float RELATIVE_STEP_UP = 0.09f;
|
||||||
|
|
||||||
class SetupViewsConfig : public Job::Config{
|
class SetupViewsConfig : public Job::Config{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -212,20 +212,31 @@ namespace workload {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Regulator {
|
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 _minRange{ MIN_VIEW_BACK_FRONTS[0] };
|
||||||
glm::vec2 _maxRange{ MAX_VIEW_BACK_FRONTS[0] };
|
glm::vec2 _maxRange{ MAX_VIEW_BACK_FRONTS[0] };
|
||||||
|
|
||||||
glm::vec2 _relativeStepDown{ RELATIVE_STEP_DOWN };
|
glm::vec2 _relativeStepDown{ RELATIVE_STEP_DOWN };
|
||||||
glm::vec2 _relativeStepUp{ RELATIVE_STEP_UP };
|
glm::vec2 _relativeStepUp{ RELATIVE_STEP_UP };
|
||||||
|
Timing_ns _budget{ std::chrono::milliseconds(2) };
|
||||||
|
float _measuredTimeAverage { 0.0f };
|
||||||
|
float _measuredTimeNoiseSquared { 0.0f };
|
||||||
|
|
||||||
Regulator() {}
|
Regulator() {}
|
||||||
Regulator(const Timing_ns& budget_ns, const glm::vec2& minRange, const glm::vec2& maxRange, const glm::vec2& relativeStepDown, const glm::vec2& relativeStepUp) :
|
Regulator(const Timing_ns& budget_ns,
|
||||||
_budget(budget_ns), _minRange(minRange), _maxRange(maxRange), _relativeStepDown(relativeStepDown), _relativeStepUp(relativeStepUp) {}
|
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;
|
glm::vec2 clamp(const glm::vec2& backFront) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue