From 51bf5259dcadcb8861cc7ff53880cf9b6d2c3b4c Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 30 Jul 2021 08:46:21 +0700 Subject: [PATCH 1/4] optimize chrono:steady_clock::now() Co-authored-by: Bruce Dawson --- stl/inc/chrono | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 1a01e1b28d7..5bda9f43a0e 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -710,9 +710,18 @@ namespace chrono { // It assumes that _Freq * period::den does not overflow, which is currently true for nano period. // It is not realistic for _Ctr to accumulate to large values from zero with this assumption, // but the initial value of _Ctr could be large. - const long long _Whole = (_Ctr / _Freq) * period::den; - const long long _Part = (_Ctr % _Freq) * period::den / _Freq; - return time_point(duration(_Whole + _Part)); + // 10 MHz is a very common QPC frequency on modern PCs. Optimizing for + // this specific frequency can double the performance of this function by + // avoiding the expensive frequency conversion path. + if (_Freq == 10000000) { + static_assert(period::den % 10000000 == 0, "It should never fail."); + constexpr long long _Multiplier = period::den / 10000000; + return time_point(duration(_Ctr * _Multiplier)); + } else { + const long long _Whole = (_Ctr / _Freq) * period::den; + const long long _Part = (_Ctr % _Freq) * period::den / _Freq; + return time_point(duration(_Whole + _Part)); + } } }; From 87a8d6933b431bd301b0d796728fb25994ccf6a7 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 30 Jul 2021 12:21:00 +0700 Subject: [PATCH 2/4] use `static` for `_Freq` Co-authored-by: Bruce Dawson --- stl/inc/chrono | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 5bda9f43a0e..74d515464d2 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -702,8 +702,8 @@ namespace chrono { static constexpr bool is_steady = true; _NODISCARD static time_point now() noexcept { // get current time - const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot - const long long _Ctr = _Query_perf_counter(); + static const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot + const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); // Instead of just having "(_Ctr * period::den) / _Freq", // the algorithm below prevents overflow when _Ctr is sufficiently large. From 8e1daf43a853b870094f807085e486db1f2e78c0 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 30 Jul 2021 12:41:02 +0700 Subject: [PATCH 3/4] Revert "use `static` for `_Freq`" This reverts commit 87a8d6933b431bd301b0d796728fb25994ccf6a7. --- stl/inc/chrono | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 74d515464d2..5bda9f43a0e 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -702,8 +702,8 @@ namespace chrono { static constexpr bool is_steady = true; _NODISCARD static time_point now() noexcept { // get current time - static const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot - const long long _Ctr = _Query_perf_counter(); + const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot + const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); // Instead of just having "(_Ctr * period::den) / _Freq", // the algorithm below prevents overflow when _Ctr is sufficiently large. From 5bed6163ecb1aca8a889bea59586b7cef1a73c07 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Fri, 30 Jul 2021 19:21:05 +0700 Subject: [PATCH 4/4] Addressing PR reviews Co-authored-by: Alex Guteniev --- stl/inc/chrono | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index 5bda9f43a0e..a7cd925b47d 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -705,19 +705,20 @@ namespace chrono { const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); - // Instead of just having "(_Ctr * period::den) / _Freq", - // the algorithm below prevents overflow when _Ctr is sufficiently large. - // It assumes that _Freq * period::den does not overflow, which is currently true for nano period. - // It is not realistic for _Ctr to accumulate to large values from zero with this assumption, - // but the initial value of _Ctr could be large. // 10 MHz is a very common QPC frequency on modern PCs. Optimizing for // this specific frequency can double the performance of this function by // avoiding the expensive frequency conversion path. - if (_Freq == 10000000) { - static_assert(period::den % 10000000 == 0, "It should never fail."); - constexpr long long _Multiplier = period::den / 10000000; + constexpr long long _TenMHz = 10'000'000; + if (_Freq == _TenMHz) { + static_assert(period::den % _TenMHz == 0, "It should never fail."); + constexpr long long _Multiplier = period::den / _TenMHz; return time_point(duration(_Ctr * _Multiplier)); } else { + // Instead of just having "(_Ctr * period::den) / _Freq", + // the algorithm below prevents overflow when _Ctr is sufficiently large. + // It assumes that _Freq * period::den does not overflow, which is currently true for nano period. + // It is not realistic for _Ctr to accumulate to large values from zero with this assumption, + // but the initial value of _Ctr could be large. const long long _Whole = (_Ctr / _Freq) * period::den; const long long _Part = (_Ctr % _Freq) * period::den / _Freq; return time_point(duration(_Whole + _Part));