aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMacroFake <falke.marco@gmail.com>2022-05-10 07:56:01 +0200
committerMacroFake <falke.marco@gmail.com>2022-05-10 07:56:06 +0200
commitfb7c12c26f57784c6db589939103237173adb533 (patch)
tree58f4950ee30353f4609c60d43e297d76c2630ce6
parent967654d0792f8ee44da3bd747b005071804da3d6 (diff)
parentfa4fb8d98b7e8e5ea2db35bf239fa7f248da5d8e (diff)
Merge bitcoin/bitcoin#24921: Add time helpers for std::chrono::steady_clock and FastRandomContext::rand_uniform_delay
fa4fb8d98b7e8e5ea2db35bf239fa7f248da5d8e random: Add FastRandomContext::rand_uniform_delay (MarcoFalke) faa5c62967174f1dd66e8a4ba61ab29c867cf450 Add time helpers for std::chrono::steady_clock (MarcoFalke) Pull request description: A steady clock can be used in the future for the scheduler, for example. A random uniform delay applied to a time point can be used in the future for time points passed to the scheduler, or delays in net processing. Currently they are unused outside of tests, but if they turn out unused in the future (unlikely), they can trivially be removed again. I am splitting them out, so that several branches/pulls can build on top of them without duplicating the commits. ACKs for top commit: ajtowns: ACK fa4fb8d98b7e8e5ea2db35bf239fa7f248da5d8e Tree-SHA512: 2c37174468fe84b1cdf2a032f458706df44b99a5f99062417bb42078b6f69e2f1738d20c21cd9386ca5a35f3bc0583e547ba40168c66f6aa42f700ba35dd95d4
-rw-r--r--src/random.h11
-rw-r--r--src/test/random_tests.cpp10
-rw-r--r--src/test/util_tests.cpp12
-rw-r--r--src/util/time.h13
4 files changed, 42 insertions, 4 deletions
diff --git a/src/random.h b/src/random.h
index 285158b1c3..4679a2b40c 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 <typename Tp>
+ 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 978a7bee4d..a3daefa599 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());
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3b2aca5887..9dcfe009b3 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<std::chrono::seconds>().count());
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().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<SteadyMilliseconds>();
+ const auto steady_0 = std::chrono::steady_clock::now();
const auto ms_0 = GetTime<std::chrono::milliseconds>();
const auto us_0 = GetTime<std::chrono::microseconds>();
- UninterruptibleSleep(std::chrono::milliseconds{1});
+ UninterruptibleSleep(1ms);
+ BOOST_CHECK(steady_ms_0 < Now<SteadyMilliseconds>());
+ BOOST_CHECK(steady_0 + 1ms <= std::chrono::steady_clock::now());
BOOST_CHECK(ms_0 < GetTime<std::chrono::milliseconds>());
BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
}
diff --git a/src/util/time.h b/src/util/time.h
index 9d92b23725..041b8aa6a1 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<std::chrono::steady_clock, std::chrono::seconds>;
+using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>;
+using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
+
void UninterruptibleSleep(const std::chrono::microseconds& n);
/**
@@ -67,6 +71,15 @@ std::chrono::seconds GetMockTime();
/** Return system time (or mocked time, if set) */
template <typename T>
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 <typename T>
+T Now()
+{
+ return std::chrono::time_point_cast<typename T::duration>(T::clock::now());
+}
/**
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}