From faa5c62967174f1dd66e8a4ba61ab29c867cf450 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 19 Apr 2022 13:13:21 +0200 Subject: [PATCH 1/2] Add time helpers for std::chrono::steady_clock --- src/test/util_tests.cpp | 12 ++++++++---- src/util/time.h | 13 +++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 3b2aca58878..9dcfe009b35 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1488,8 +1488,8 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime) { SetMockTime(111); // Check that mock time does not change after a sleep - for (const auto& num_sleep : {0, 1}) { - UninterruptibleSleep(std::chrono::milliseconds{num_sleep}); + for (const auto& num_sleep : {0ms, 1ms}) { + UninterruptibleSleep(num_sleep); BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter BOOST_CHECK_EQUAL(111, GetTime().count()); BOOST_CHECK_EQUAL(111000, GetTime().count()); @@ -1497,10 +1497,14 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime) } SetMockTime(0); - // Check that system time changes after a sleep + // Check that steady time and system time changes after a sleep + const auto steady_ms_0 = Now(); + const auto steady_0 = std::chrono::steady_clock::now(); const auto ms_0 = GetTime(); const auto us_0 = GetTime(); - UninterruptibleSleep(std::chrono::milliseconds{1}); + UninterruptibleSleep(1ms); + BOOST_CHECK(steady_ms_0 < Now()); + BOOST_CHECK(steady_0 + 1ms <= std::chrono::steady_clock::now()); BOOST_CHECK(ms_0 < GetTime()); BOOST_CHECK(us_0 < GetTime()); } diff --git a/src/util/time.h b/src/util/time.h index 9d92b237250..041b8aa6a1f 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -14,6 +14,10 @@ using namespace std::chrono_literals; +using SteadySeconds = std::chrono::time_point; +using SteadyMilliseconds = std::chrono::time_point; +using SteadyMicroseconds = std::chrono::time_point; + void UninterruptibleSleep(const std::chrono::microseconds& n); /** @@ -67,6 +71,15 @@ std::chrono::seconds GetMockTime(); /** Return system time (or mocked time, if set) */ template T GetTime(); +/** + * Return the current time point cast to the given precicion. Only use this + * when an exact precicion is needed, otherwise use T::clock::now() directly. + */ +template +T Now() +{ + return std::chrono::time_point_cast(T::clock::now()); +} /** * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date} From fa4fb8d98b7e8e5ea2db35bf239fa7f248da5d8e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 8 Apr 2022 12:56:25 +0200 Subject: [PATCH 2/2] random: Add FastRandomContext::rand_uniform_delay --- src/random.h | 11 +++++++++++ src/test/random_tests.cpp | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/random.h b/src/random.h index 285158b1c3c..4679a2b40c5 100644 --- a/src/random.h +++ b/src/random.h @@ -223,6 +223,17 @@ public: /** Generate a random boolean. */ bool randbool() noexcept { return randbits(1); } + /** Return the time point advanced by a uniform random duration. */ + template + Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) + { + using Dur = typename Tp::duration; + Dur dur{range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} : + range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} : + /* interval [0..0] */ Dur{0}}; + return time + dur; + } + // Compatibility with the C++11 UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() { return 0; } diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 978a7bee4dc..a3daefa599b 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -31,6 +31,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654); BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374); } + { + constexpr SteadySeconds time_point{1s}; + FastRandomContext ctx{true}; + BOOST_CHECK_EQUAL(7, ctx.rand_uniform_delay(time_point, 9s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(-6, ctx.rand_uniform_delay(time_point, -9s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(1, ctx.rand_uniform_delay(time_point, 0s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(1467825113502396065, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(-970181367944767837, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count()); + BOOST_CHECK_EQUAL(24761, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count()); + } BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32()); BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());