-
Notifications
You must be signed in to change notification settings - Fork 37.7k
refactor: Simplify GetTime #24871
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Simplify GetTime #24871
The head ref may contain hidden characters: "2204-time-\u{1F5A4}"
Conversation
Concept ACK, GetTime should either use std::chrono or C time functions, not a mix for different types, that's really weird. |
@@ -129,6 +120,8 @@ int64_t GetTimeSeconds() | |||
return int64_t{GetSystemTime<std::chrono::seconds>().count()}; | |||
} | |||
|
|||
int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Why not using the same syntax/formatting as above in GetTimeSeconds
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the narrowing check is a bit overkill and probably doesn't make much sense. Mostly relevant isn't the maximum number of bits in the value, but the minimum, which is 35 bits according to https://en.cppreference.com/w/cpp/chrono/duration .
In either case the function is deprecated (see comment in the header file), and will likely be removed in the future anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strong Concept ACK
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
Concept ACK |
Code review, untested ACK 0000a63. By the way strictly speaking |
@martinus note that we have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code-review ACK 0000a63
I was first confused on why we don't have to std::chrono::duration_cast<T>
the mock time, but C++ seems to be nice enough to implicitly convert between duration types if there is no precision loss (e.g. in our case seconds -> milliseconds and seconds -> microseconds). Note though that on master explicit instantiation with something less precise than seconds works:
template std::chrono::minutes GetTime();
while on the PR branch it doesn't. OTOH the chance that we ever need less precision than seconds is close to zero, so I think it's fine.
Yes, the change was intentional. Given that we've never used |
@@ -80,11 +70,12 @@ template <typename T> | |||
T GetTime() | |||
{ | |||
const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)}; | |||
|
|||
return std::chrono::duration_cast<T>( | |||
const auto ret{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const T ret
?
Dropping the duration_cast
around mocktime
means you can't use GetTime<T>()
with T
set to minutes or hours or similar. Seems fine, just noting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think auto
is fine for now. This will also reduce the diff in commit 8299fd2, where the type is changed from T
to Clock::time_point::duration
.
0000a63 Simplify GetTime (MarcoFalke) Pull request description: The implementation of `GetTime` is confusing: * The value returned by `GetTime` is assumed to be equal to `GetTime<std::chrono::seconds>()`. Both are mockable and the only difference is return type, the value itself is equal. However, the implementation does not support this assumption. * On some systems, `time_t` might be a signed 32-bit integer (https://en.cppreference.com/w/c/chrono/time), thus breaking in the year 2038, whereas `GetTime<std::chrono::seconds>` does not. Also, `time_t` might be `-1` "on error", where "error" is unspecified. * `GetTime<std::chrono::seconds>` calls `GetTimeMicros`, which calls `GetSystemTime`, which calls `std::chrono::system_clock::now`, which doesn't have the above issues. See https://en.cppreference.com/w/cpp/chrono/system_clock/now * `GetTimeMicros` and the internal-only `GetSystemTime` will likely be renamed (to clarify they are the non-mockable non-monotonic system time) or removed in the future to be replaced by appropriate `std::chrono::time_point<Clock>` getters. Fix all issues by: * making `GetTime()` an alias for `GetTime<std::chrono::seconds>().count()`. * inlining the needed parts of `GetSystemTime` directly instead of needlessly increasing the function call stack with functions that are likely to be removed in the future. ACKs for top commit: martinus: Code review, untested ACK 0000a63. By the way strictly speaking `std::chrono::system_clock` is only guaranteed to be based on the unix epoch starting with C++20: https://en.cppreference.com/w/cpp/chrono/system_clock theStack: Code-review ACK 0000a63 Tree-SHA512: f751ba740e0da65537be800e9414dd02282d9f04c0b0fb986a36546f257d0b888d8688653cdda5d355ec832c0e09d866922d9161b1ccd33485c1c92c5d1e802f
…ion time could be off by one Summary: util/time.* uses multiple clocks depending on circumstances like if mock time is set or if templated GetTime<>() is called. This can result in unexpected behavior where registerProof() uses a different clock than when SetMockTime(GetTime()...) is called in unit tests. Example failure: https://build.bitcoinabc.org/viewLog.html?buildId=416835&buildTypeId=BitcoinABC_BitcoinAbcStaging&tab=buildLog&_focus=1325 This patch makes this specific unit test predictable by setting mock time before any proofs are registered. The root cause may be fixed with additional backports to util/time.* that make the clock selection more consistent (see backport [[bitcoin/bitcoin#24871 | core#24871]] and [[bitcoin/bitcoin#21110 | core#21110]]). Test Plan: ninja check-avalanche Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D11786
Summary: > The implementation of `GetTime` is confusing: > > * The value returned by `GetTime` is assumed to be equal to `GetTime<std::chrono::seconds>()`. Both are mockable and the only difference is return type, the value itself is equal. However, the implementation does not support this assumption. > > * On some systems, `time_t` might be a signed 32-bit integer (https://en.cppreference.com/w/c/chrono/time), thus breaking in the year 2038, whereas `GetTime<std::chrono::seconds>` does not. Also, `time_t` might be `-1` "on error", where "error" is unspecified. > > * `GetTime<std::chrono::seconds>` calls `GetTimeMicros`, which calls `GetSystemTime`, which calls `std::chrono::system_clock::now`, which doesn't have the above issues. See https://en.cppreference.com/w/cpp/chrono/system_clock/now > > * `GetTimeMicros` and the internal-only `GetSystemTime` will likely be renamed (to clarify they are the non-mockable non-monotonic system time) or removed in the future to be replaced by appropriate `std::chrono::time_point<Clock>` getters. > > > Fix all issues by: > > * making `GetTime()` an alias for `GetTime<std::chrono::seconds>().count()`. > > * inlining the needed parts of `GetSystemTime` directly instead of needlessly increasing the function call stack with functions that are likely to be removed in the future. This is a backport of [[bitcoin/bitcoin#24871 | core#24871]] Depends on D11790 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D11791
The implementation of
GetTime
is confusing:GetTime
is assumed to be equal toGetTime<std::chrono::seconds>()
. Both are mockable and the only difference is return type, the value itself is equal. However, the implementation does not support this assumption.time_t
might be a signed 32-bit integer (https://en.cppreference.com/w/c/chrono/time), thus breaking in the year 2038, whereasGetTime<std::chrono::seconds>
does not. Also,time_t
might be-1
"on error", where "error" is unspecified.GetTime<std::chrono::seconds>
callsGetTimeMicros
, which callsGetSystemTime
, which callsstd::chrono::system_clock::now
, which doesn't have the above issues. See https://en.cppreference.com/w/cpp/chrono/system_clock/nowGetTimeMicros
and the internal-onlyGetSystemTime
will likely be renamed (to clarify they are the non-mockable non-monotonic system time) or removed in the future to be replaced by appropriatestd::chrono::time_point<Clock>
getters.Fix all issues by:
GetTime()
an alias forGetTime<std::chrono::seconds>().count()
.GetSystemTime
directly instead of needlessly increasing the function call stack with functions that are likely to be removed in the future.