diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -28,6 +28,7 @@ bench/merkle_root.cpp \ bench/mempool_eviction.cpp \ bench/rpc_mempool.cpp \ + bench/util_time.cpp \ bench/base58.cpp \ bench/lockedpool.cpp \ bench/prevector.cpp diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt --- a/src/bench/CMakeLists.txt +++ b/src/bench/CMakeLists.txt @@ -52,6 +52,7 @@ prevector.cpp rollingbloom.cpp rpc_mempool.cpp + util_time.cpp # Add the generated headers to trigger the conversion command ${BENCH_DATA_GENERATED_HEADERS} diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp new file mode 100644 --- /dev/null +++ b/src/bench/util_time.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +static void BenchTimeDeprecated(benchmark::State &state) { + while (state.KeepRunning()) { + (void)GetTime(); + } +} + +static void BenchTimeMock(benchmark::State &state) { + SetMockTime(111); + while (state.KeepRunning()) { + (void)GetTime(); + } + SetMockTime(0); +} + +static void BenchTimeMillis(benchmark::State &state) { + while (state.KeepRunning()) { + (void)GetTime(); + } +} + +static void BenchTimeMillisSys(benchmark::State &state) { + while (state.KeepRunning()) { + (void)GetTimeMillis(); + } +} + +BENCHMARK(BenchTimeDeprecated, 100000000); +BENCHMARK(BenchTimeMillis, 6000000); +BENCHMARK(BenchTimeMillisSys, 6000000); +BENCHMARK(BenchTimeMock, 300000000); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -926,6 +926,27 @@ BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0); } +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}) { + MilliSleep(num_sleep); + BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter + BOOST_CHECK_EQUAL(111, GetTime().count()); + BOOST_CHECK_EQUAL(111000, GetTime().count()); + BOOST_CHECK_EQUAL(111000000, + GetTime().count()); + } + + SetMockTime(0); + // Check that system time changes after a sleep + const auto ms_0 = GetTime(); + const auto us_0 = GetTime(); + MilliSleep(1); + BOOST_CHECK(ms_0 < GetTime()); + BOOST_CHECK(us_0 < GetTime()); +} + BOOST_AUTO_TEST_CASE(test_IsDigit) { BOOST_CHECK_EQUAL(IsDigit('0'), true); BOOST_CHECK_EQUAL(IsDigit('1'), true); diff --git a/src/util/time.h b/src/util/time.h --- a/src/util/time.h +++ b/src/util/time.h @@ -1,35 +1,41 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTIL_TIME_H #define BITCOIN_UTIL_TIME_H +#include #include #include /** - * GetTimeMicros() and GetTimeMillis() both return the system time, but in - * different units. GetTime() returns the system time in seconds, but also - * supports mocktime, where the time can be specified by the user, eg for - * testing (eg with the setmocktime rpc, or -mocktime argument). - * - * TODO: Rework these functions to be type-safe (so that we don't inadvertently - * compare numbers with different units, or compare a mocktime to system time). + * DEPRECATED + * Use either GetSystemTimeInSeconds (not mockable) or GetTime (mockable) */ - int64_t GetTime(); + +/** Returns the system time (not mockable) */ int64_t GetTimeMillis(); +/** Returns the system time (not mockable) */ int64_t GetTimeMicros(); +/** Returns the system time (not mockable) */ // Like GetTime(), but not mockable int64_t GetSystemTimeInSeconds(); + +/** For testing. Set e.g. with the setmocktime rpc, or -mocktime argument */ void SetMockTime(int64_t nMockTimeIn); +/** For testing */ int64_t GetMockTime(); + void MilliSleep(int64_t n); +/** Return system time (or mocked time, if set) */ +template T GetTime(); + /** - * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date,Time} + * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date} * helper functions if possible. */ std::string FormatISO8601DateTime(int64_t nTime); diff --git a/src/util/time.cpp b/src/util/time.cpp --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,6 +31,18 @@ return now; } +template T GetTime() { + const std::chrono::seconds mocktime{ + nMockTime.load(std::memory_order_relaxed)}; + + return std::chrono::duration_cast( + mocktime.count() ? mocktime + : std::chrono::microseconds{GetTimeMicros()}); +} +template std::chrono::seconds GetTime(); +template std::chrono::milliseconds GetTime(); +template std::chrono::microseconds GetTime(); + void SetMockTime(int64_t nMockTimeIn) { nMockTime.store(nMockTimeIn, std::memory_order_relaxed); }