0
0
Fork 0
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:
    ACK fa4fb8d98b

Tree-SHA512: 2c37174468fe84b1cdf2a032f458706df44b99a5f99062417bb42078b6f69e2f1738d20c21cd9386ca5a35f3bc0583e547ba40168c66f6aa42f700ba35dd95d4
This commit is contained in:
MacroFake 2022-05-10 07:56:01 +02:00
commit fb7c12c26f
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
4 changed files with 42 additions and 4 deletions

View file

@ -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; }

View file

@ -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());

View file

@ -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>());
} }

View file

@ -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}