Skip to content

Commit fb7c12c

Browse files
author
MacroFake
committed
Merge bitcoin/bitcoin#24921: Add time helpers for std::chrono::steady_clock and FastRandomContext::rand_uniform_delay
fa4fb8d random: Add FastRandomContext::rand_uniform_delay (MarcoFalke) faa5c62 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 fa4fb8d Tree-SHA512: 2c37174468fe84b1cdf2a032f458706df44b99a5f99062417bb42078b6f69e2f1738d20c21cd9386ca5a35f3bc0583e547ba40168c66f6aa42f700ba35dd95d4
2 parents 967654d + fa4fb8d commit fb7c12c

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

src/random.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,17 @@ class FastRandomContext
223223
/** Generate a random boolean. */
224224
bool randbool() noexcept { return randbits(1); }
225225

226+
/** Return the time point advanced by a uniform random duration. */
227+
template <typename Tp>
228+
Tp rand_uniform_delay(const Tp& time, typename Tp::duration range)
229+
{
230+
using Dur = typename Tp::duration;
231+
Dur dur{range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
232+
range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
233+
/* interval [0..0] */ Dur{0}};
234+
return time + dur;
235+
}
236+
226237
// Compatibility with the C++11 UniformRandomBitGenerator concept
227238
typedef uint64_t result_type;
228239
static constexpr uint64_t min() { return 0; }

src/test/random_tests.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
3131
BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
3232
BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374);
3333
}
34+
{
35+
constexpr SteadySeconds time_point{1s};
36+
FastRandomContext ctx{true};
37+
BOOST_CHECK_EQUAL(7, ctx.rand_uniform_delay(time_point, 9s).time_since_epoch().count());
38+
BOOST_CHECK_EQUAL(-6, ctx.rand_uniform_delay(time_point, -9s).time_since_epoch().count());
39+
BOOST_CHECK_EQUAL(1, ctx.rand_uniform_delay(time_point, 0s).time_since_epoch().count());
40+
BOOST_CHECK_EQUAL(1467825113502396065, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count());
41+
BOOST_CHECK_EQUAL(-970181367944767837, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count());
42+
BOOST_CHECK_EQUAL(24761, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count());
43+
}
3444
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
3545
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
3646
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());

src/test/util_tests.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,19 +1488,23 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime)
14881488
{
14891489
SetMockTime(111);
14901490
// Check that mock time does not change after a sleep
1491-
for (const auto& num_sleep : {0, 1}) {
1492-
UninterruptibleSleep(std::chrono::milliseconds{num_sleep});
1491+
for (const auto& num_sleep : {0ms, 1ms}) {
1492+
UninterruptibleSleep(num_sleep);
14931493
BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
14941494
BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
14951495
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
14961496
BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
14971497
}
14981498

14991499
SetMockTime(0);
1500-
// Check that system time changes after a sleep
1500+
// Check that steady time and system time changes after a sleep
1501+
const auto steady_ms_0 = Now<SteadyMilliseconds>();
1502+
const auto steady_0 = std::chrono::steady_clock::now();
15011503
const auto ms_0 = GetTime<std::chrono::milliseconds>();
15021504
const auto us_0 = GetTime<std::chrono::microseconds>();
1503-
UninterruptibleSleep(std::chrono::milliseconds{1});
1505+
UninterruptibleSleep(1ms);
1506+
BOOST_CHECK(steady_ms_0 < Now<SteadyMilliseconds>());
1507+
BOOST_CHECK(steady_0 + 1ms <= std::chrono::steady_clock::now());
15041508
BOOST_CHECK(ms_0 < GetTime<std::chrono::milliseconds>());
15051509
BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
15061510
}

src/util/time.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
using namespace std::chrono_literals;
1616

17+
using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>;
18+
using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>;
19+
using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
20+
1721
void UninterruptibleSleep(const std::chrono::microseconds& n);
1822

1923
/**
@@ -67,6 +71,15 @@ std::chrono::seconds GetMockTime();
6771
/** Return system time (or mocked time, if set) */
6872
template <typename T>
6973
T GetTime();
74+
/**
75+
* Return the current time point cast to the given precicion. Only use this
76+
* when an exact precicion is needed, otherwise use T::clock::now() directly.
77+
*/
78+
template <typename T>
79+
T Now()
80+
{
81+
return std::chrono::time_point_cast<typename T::duration>(T::clock::now());
82+
}
7083

7184
/**
7285
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}

0 commit comments

Comments
 (0)