mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
Merge bitcoin/bitcoin#24921: Add time helpers for std::chrono::steady_clock and FastRandomContext::rand_uniform_delay
fa4fb8d98b
random: Add FastRandomContext::rand_uniform_delay (MarcoFalke)faa5c62967
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: ACKfa4fb8d98b
Tree-SHA512: 2c37174468fe84b1cdf2a032f458706df44b99a5f99062417bb42078b6f69e2f1738d20c21cd9386ca5a35f3bc0583e547ba40168c66f6aa42f700ba35dd95d4
This commit is contained in:
commit
fb7c12c26f
4 changed files with 42 additions and 4 deletions
11
src/random.h
11
src/random.h
|
@ -223,6 +223,17 @@ public:
|
||||||
/** Generate a random boolean. */
|
/** Generate a random boolean. */
|
||||||
bool randbool() noexcept { return randbits(1); }
|
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
|
// Compatibility with the C++11 UniformRandomBitGenerator concept
|
||||||
typedef uint64_t result_type;
|
typedef uint64_t result_type;
|
||||||
static constexpr uint64_t min() { return 0; }
|
static constexpr uint64_t min() { return 0; }
|
||||||
|
|
|
@ -31,6 +31,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
|
||||||
BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
|
BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
|
||||||
BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374);
|
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.rand32(), ctx2.rand32());
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
||||||
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
|
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
|
||||||
|
|
|
@ -1488,8 +1488,8 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime)
|
||||||
{
|
{
|
||||||
SetMockTime(111);
|
SetMockTime(111);
|
||||||
// Check that mock time does not change after a sleep
|
// Check that mock time does not change after a sleep
|
||||||
for (const auto& num_sleep : {0, 1}) {
|
for (const auto& num_sleep : {0ms, 1ms}) {
|
||||||
UninterruptibleSleep(std::chrono::milliseconds{num_sleep});
|
UninterruptibleSleep(num_sleep);
|
||||||
BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
|
BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
|
||||||
BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
|
BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
|
||||||
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
|
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
|
||||||
|
@ -1497,10 +1497,14 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMockTime(0);
|
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 ms_0 = GetTime<std::chrono::milliseconds>();
|
||||||
const auto us_0 = GetTime<std::chrono::microseconds>();
|
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(ms_0 < GetTime<std::chrono::milliseconds>());
|
||||||
BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
|
BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
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);
|
void UninterruptibleSleep(const std::chrono::microseconds& n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,6 +71,15 @@ std::chrono::seconds GetMockTime();
|
||||||
/** Return system time (or mocked time, if set) */
|
/** Return system time (or mocked time, if set) */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetTime();
|
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}
|
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}
|
||||||
|
|
Loading…
Add table
Reference in a new issue