aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}