UV timer hack (#2042)

This commit is contained in:
Tim Sylvester
2024-01-22 10:53:41 -08:00
committed by GitHub
parent 5c304614d6
commit ec9afb5256
2 changed files with 31 additions and 16 deletions

View File

@@ -1,11 +1,12 @@
#include <mbgl/util/timer.hpp>
#include <stdexcept>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <uv.h>
#include <stdexcept>
namespace mbgl {
namespace util {
@@ -28,6 +29,14 @@ public:
void start(uint64_t timeout, uint64_t repeat, std::function<void()>&& cb_) {
cb = std::move(cb_);
// Update the event loop’s concept of “now”.
// This resolves test failures on some systems, where only the following sequence of tests fails:
// Thread.InvokeBeforeChildStarts:Thread.DeleteBeforeChildStarts:Timer.Basic
// This implies that "you have callbacks that block the event loop for ... on the order of a millisecond
// or more," so this may be masking some unexpected interaction between successive `RunLoop` instances.
uv_update_time(reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle()));
if (uv_timer_start(timer, timerCallback, timeout, repeat) != 0) {
throw std::runtime_error("Failed to start timer.");
}

View File

@@ -1,37 +1,43 @@
#include <mbgl/test/util.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/timer.hpp>
#include <mbgl/util/monotonic_timer.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/timer.hpp>
#include <memory>
#include <optional>
using namespace mbgl::util;
TEST(Timer, TEST_REQUIRES_ACCURATE_TIMING(Basic)) {
RunLoop loop;
Timer timer;
const auto interval = mbgl::Milliseconds(300);
const auto expectedTotalTime = interval;
auto callback = [&loop] {
const auto first = MonotonicTimer::now();
const auto elapsed = [=] {
return std::chrono::duration_cast<mbgl::Milliseconds>(MonotonicTimer::now() - first);
};
std::optional<mbgl::Milliseconds> callbackTime;
auto callback = [&] {
callbackTime = elapsed();
loop.stop();
};
auto interval = mbgl::Milliseconds(300);
auto expectedTotalTime = interval;
auto first = mbgl::Clock::now();
timer.start(interval, mbgl::Duration::zero(), callback);
Timer timer;
timer.start(interval, mbgl::Duration::zero(), std::move(callback));
loop.run();
auto totalTime = std::chrono::duration_cast<mbgl::Milliseconds>(mbgl::Clock::now() - first);
const auto totalTime = elapsed();
// These are not high precision timers. Especially libuv uses
// cached time from the beginning of of the main loop iteration
// and it is very prone to fire earlier, which is, odd.
EXPECT_GE(totalTime, expectedTotalTime * 0.8);
EXPECT_LE(totalTime, expectedTotalTime * 1.2);
SCOPED_TRACE("Timer callback: " + (callbackTime ? toString(callbackTime->count()) : "(never)"));
EXPECT_GE(totalTime.count(), (expectedTotalTime * 0.99).count());
EXPECT_LE(totalTime.count(), (expectedTotalTime * 1.10).count());
}
TEST(Timer, TEST_REQUIRES_ACCURATE_TIMING(Repeat)) {