17
17
#include < chrono>
18
18
#include < cstdint>
19
19
#include < cstdio>
20
+ #include < vector>
20
21
21
22
QUILL_BEGIN_NAMESPACE
22
23
@@ -52,13 +53,19 @@ class RdtscClock
52
53
// Convert rdtsc to wall time.
53
54
// 1. Get real time and rdtsc current count
54
55
// 2. Calculate how many rdtsc ticks can occur in one
55
- // calculate _ticks_per_ns as the median over a number of observations.
56
+ // calculate _ticks_per_ns as the median over a number of observations
57
+ // we use always odd number of trials for easy median calc
56
58
constexpr std::chrono::milliseconds spin_duration = std::chrono::milliseconds{10 };
59
+ constexpr size_t max_trials = 15 ;
60
+ constexpr size_t min_trials = 3 ;
61
+ constexpr double convergence_threshold = 0.01 ; // 1% threshold
57
62
58
- constexpr int trials = 13 ;
59
- std::array< double , trials> rates = {{ 0 }} ;
63
+ std::vector< double > rates ;
64
+ rates. reserve (max_trials) ;
60
65
61
- for (size_t i = 0 ; i < trials; ++i)
66
+ double previous_median = 0.0 ;
67
+
68
+ for (size_t i = 0 ; i < max_trials; ++i)
62
69
{
63
70
auto const beg_ts = detail::get_timestamp<std::chrono::steady_clock>();
64
71
uint64_t const beg_tsc = rdtsc ();
@@ -70,14 +77,31 @@ class RdtscClock
70
77
auto const end_ts = detail::get_timestamp<std::chrono::steady_clock>();
71
78
end_tsc = rdtsc ();
72
79
elapsed_ns = end_ts - beg_ts;
73
- } while (elapsed_ns < spin_duration); // busy spin for 10ms
80
+ } while (elapsed_ns < spin_duration);
81
+
82
+ rates.push_back (static_cast <double >(end_tsc - beg_tsc) / static_cast <double >(elapsed_ns.count ()));
83
+
84
+ // Check for convergence after minimum trials and only on an odd count of trials.
85
+ if (((i + 1 ) >= min_trials) && (((i + 1 ) % 2 ) != 0 ))
86
+ {
87
+ std::nth_element (rates.begin (), rates.begin () + static_cast <ptrdiff_t >((i + 1 ) / 2 ), rates.end ());
88
+ double current_median = rates[(i + 1 ) / 2 ];
89
+
90
+ // If we've converged, break early
91
+ if (std::abs (current_median - previous_median) / current_median < convergence_threshold)
92
+ {
93
+ break ;
94
+ }
74
95
75
- rates[i] = static_cast <double >(end_tsc - beg_tsc) / static_cast <double >(elapsed_ns.count ());
96
+ previous_median = current_median;
97
+ }
76
98
}
77
99
78
- std::nth_element (rates.begin (), rates.begin () + trials / 2 , rates.end ());
100
+ // Calculate final median.
101
+ std::nth_element (rates.begin (), rates.begin () + static_cast <ptrdiff_t >(rates.size () / 2 ),
102
+ rates.end ());
79
103
80
- double const ticks_per_ns = rates[trials / 2 ];
104
+ double const ticks_per_ns = rates[rates. size () / 2 ];
81
105
_ns_per_tick = 1 / ticks_per_ns;
82
106
}
83
107
0 commit comments