mirror of
https://github.com/mitch030504/AstroQuest-Frame.git
synced 2026-10-17 22:01:15 +02:00
84 lines
3.0 KiB
C++
84 lines
3.0 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#include "common/precise_timer_scheduler.h"
|
|
#include "core/vr/mirror_limiter.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <condition_variable>
|
|
#include <iostream>
|
|
using namespace std::chrono_literals;
|
|
int main() {
|
|
using Clock = Common::PreciseTimerScheduler::Clock;
|
|
Common::PreciseTimerScheduler scheduler;
|
|
assert(scheduler.Available());
|
|
std::mutex mutex;
|
|
std::condition_variable cv;
|
|
std::vector<int> order;
|
|
auto record = [&](int n) {
|
|
std::scoped_lock lock{mutex};
|
|
order.push_back(n);
|
|
cv.notify_one();
|
|
};
|
|
auto start = Clock::now();
|
|
// An earlier timer inserted while the worker sleeps must interrupt the old
|
|
// deadline.
|
|
scheduler.Add(start + 60ms, [&] { record(2); });
|
|
std::this_thread::sleep_for(2ms);
|
|
scheduler.Add(start + 10ms, [&] {
|
|
record(1);
|
|
// Scheduling inside a callback must not deadlock the queue.
|
|
scheduler.Add(start + 25ms, [&] { record(3); });
|
|
});
|
|
{
|
|
std::unique_lock lock{mutex};
|
|
assert(cv.wait_for(lock, 2s, [&] { return order.size() == 3; }));
|
|
}
|
|
assert((order == std::vector<int>{1, 3, 2}));
|
|
std::vector<double> lateness;
|
|
for (int i = 0; i < 100; ++i) {
|
|
bool fired = false;
|
|
const auto deadline = Clock::now() + 3ms;
|
|
scheduler.Add(deadline, [&] {
|
|
std::scoped_lock lock{mutex};
|
|
lateness.push_back(
|
|
std::chrono::duration<double, std::micro>(Clock::now() - deadline)
|
|
.count());
|
|
fired = true;
|
|
cv.notify_one();
|
|
});
|
|
std::unique_lock lock{mutex};
|
|
assert(cv.wait_for(lock, 1s, [&] { return fired; }));
|
|
assert(lateness.back() >= 0);
|
|
}
|
|
std::sort(lateness.begin(), lateness.end());
|
|
std::cout << "3-ms timer lateness (us): median=" << lateness[50]
|
|
<< " p95=" << lateness[95] << " max=" << lateness.back() << '\n';
|
|
// Destruction cancels pending deadlines and joins the worker promptly.
|
|
bool unexpected = false;
|
|
start = Clock::now();
|
|
{
|
|
Common::PreciseTimerScheduler temporary;
|
|
temporary.Add(Clock::now() + 1h, [&] { unexpected = true; });
|
|
}
|
|
assert(!unexpected && Clock::now() - start < 1s);
|
|
for (int source_rate : {60, 72, 90, 120, 144}) {
|
|
Core::Vr::MirrorLimiter limiter;
|
|
int count = 0;
|
|
for (int i = 0; i < source_rate * 10; ++i) {
|
|
const auto now = Clock::time_point{} + 1s +
|
|
std::chrono::nanoseconds{1000000000LL * i / source_rate};
|
|
count += limiter.Due(now, true, 60);
|
|
}
|
|
assert(count >= 598 && count <= 601);
|
|
std::cout << source_rate << " Hz source: " << count
|
|
<< " mirror updates / 10 seconds\n";
|
|
}
|
|
Core::Vr::MirrorLimiter limiter;
|
|
assert(!limiter.Due(Clock::now(), true, 0));
|
|
assert(limiter.Due(Clock::now(), false, 0));
|
|
assert(limiter.Due(Clock::now(), true, 60));
|
|
assert(limiter.Due(Clock::now() + 10s, true, 60));
|
|
assert(!limiter.Due(Clock::now() + 10s, true, 60));
|
|
std::cout << "Timer ordering/reentrant scheduling/shutdown and mirror "
|
|
"cap/fallback: passed\n";
|
|
}
|