Agora  1.2.0
Agora project
timer.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <vector>
5 
7 static inline size_t rdtsc() {
8  uint64_t rax;
9  uint64_t rdx;
10  asm volatile("rdtsc" : "=a"(rax), "=d"(rdx));
11  return static_cast<size_t>((rdx << 32) | rax);
12 }
13 
15 static const auto& dpath_rdtsc = rdtsc;
16 
17 static void nano_sleep(size_t ns, double freq_ghz) {
18  size_t start = rdtsc();
19  size_t end = start;
20  size_t upp = static_cast<size_t>(freq_ghz * ns);
21  while (end - start < upp) end = rdtsc();
22 }
23 
24 static double measure_rdtsc_freq() {
25  struct timespec start, end;
26  clock_gettime(CLOCK_REALTIME, &start);
27  uint64_t rdtsc_start = rdtsc();
28 
29  // Do not change this loop! The hardcoded value below depends on this loop
30  // and prevents it from being optimized out.
31  uint64_t sum = 5;
32  for (uint64_t i = 0; i < 1000000; i++) {
33  sum += i + (sum + i) * (i % sum);
34  }
35 
36  if (sum != 13580802877818827968ull) {
37  throw std::runtime_error("measure_rdtsc_freq is incorrect");
38  }
39 
40  clock_gettime(CLOCK_REALTIME, &end);
41  uint64_t clock_ns =
42  static_cast<uint64_t>(end.tv_sec - start.tv_sec) * 1000000000 +
43  static_cast<uint64_t>(end.tv_nsec - start.tv_nsec);
44  uint64_t rdtsc_cycles = rdtsc() - rdtsc_start;
45 
46  double _freq_ghz = rdtsc_cycles * 1.0 / clock_ns;
47  return _freq_ghz;
48 }
49 
51 static double to_sec(size_t cycles, double freq_ghz) {
52  return (cycles / (freq_ghz * 1000000000));
53 }
54 
56 static double to_msec(size_t cycles, double freq_ghz) {
57  return (cycles / (freq_ghz * 1000000));
58 }
59 
61 static double to_usec(size_t cycles, double freq_ghz) {
62  return (cycles / (freq_ghz * 1000));
63 }
64 
65 static size_t us_to_cycles(double us, double freq_ghz) {
66  return static_cast<size_t>(us * 1000 * freq_ghz);
67 }
68 
69 static size_t ns_to_cycles(double ns, double freq_ghz) {
70  return static_cast<size_t>(ns * freq_ghz);
71 }
72 
74 static double to_nsec(size_t cycles, double freq_ghz) {
75  return (cycles / freq_ghz);
76 }
77 
79 static double sec_since(const struct timespec& t0) {
80  struct timespec t1;
81  clock_gettime(CLOCK_REALTIME, &t1);
82  return (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1000000000.0;
83 }
84 
86 static double ns_since(const struct timespec& t0) {
87  struct timespec t1;
88  clock_gettime(CLOCK_REALTIME, &t1);
89  return (t1.tv_sec - t0.tv_sec) * 1000000000.0 + (t1.tv_nsec - t0.tv_nsec);
90 }
91 
93 class TscTimer {
94  public:
95  size_t start_tsc = 0;
96  double freq_ghz;
97  std::vector<double> ms_duration_vec;
98 
99  TscTimer(size_t n_timestamps, double freq_ghz) : freq_ghz(freq_ghz) {
100  ms_duration_vec.reserve(n_timestamps);
101  }
102 
103  inline void start() { start_tsc = rdtsc(); }
104  inline void stop() {
106  }
107 
108  void reset() { ms_duration_vec.clear(); }
109 
110  double stddev_msec() {
111  if (ms_duration_vec.empty()) return 0;
112  double sum_ms =
113  std::accumulate(ms_duration_vec.begin(), ms_duration_vec.end(), 0.0);
114  double mean_ms = sum_ms * 1.0 / ms_duration_vec.size();
115  double sq_sum =
116  std::inner_product(ms_duration_vec.begin(), ms_duration_vec.end(),
117  ms_duration_vec.begin(), 0.0);
118  double var_ms = sq_sum / ms_duration_vec.size() - (mean_ms * mean_ms);
119  if (var_ms < 0) return 0.0; // This can happen when variance ~ 0
120 
121  return std::sqrt(var_ms);
122  }
123 
124  double avg_msec() {
125  if (ms_duration_vec.empty()) return 0;
126  double sum_ms =
127  std::accumulate(ms_duration_vec.begin(), ms_duration_vec.end(), 0.0);
128  return sum_ms * 1.0 / ms_duration_vec.size();
129  }
130 };
sqrt
2 sqrt()
freq_ghz
double freq_ghz
Definition: bench.cc:10
TscTimer::ms_duration_vec
std::vector< double > ms_duration_vec
Definition: timer.h:114
TscTimer::stddev_msec
double stddev_msec()
Definition: timer.h:110
TscTimer::avg_msec
double avg_msec()
Definition: timer.h:124
sec_since
static double sec_since(const struct timespec &t0)
Return seconds elapsed since timestamp t0.
Definition: timer.h:79
TscTimer::start
void start()
Definition: timer.h:103
TscTimer::start_tsc
size_t start_tsc
Definition: timer.h:112
us_to_cycles
static size_t us_to_cycles(double us, double freq_ghz)
Definition: timer.h:65
TscTimer::stop
void stop()
Definition: timer.h:104
to_usec
static double to_usec(size_t cycles, double freq_ghz)
Convert cycles measured by rdtsc with frequence freq_ghz to usec.
Definition: timer.h:61
rdtsc
static size_t rdtsc()
Return the TSC.
Definition: timer.h:7
to_nsec
static double to_nsec(size_t cycles, double freq_ghz)
Convert cycles measured by rdtsc with frequence freq_ghz to nsec.
Definition: timer.h:74
i
for i
Definition: generate_data.m:107
dpath_rdtsc
static const auto & dpath_rdtsc
An alias for rdtsc() to distinguish calls on the critical path.
Definition: timer.h:15
start
end start
Definition: inspect_agora_results.m:95
TscTimer::TscTimer
TscTimer(size_t n_timestamps, double freq_ghz)
Definition: timer.h:99
TscTimer::freq_ghz
double freq_ghz
Definition: timer.h:113
to_msec
static double to_msec(size_t cycles, double freq_ghz)
Convert cycles measured by rdtsc with frequence freq_ghz to msec.
Definition: timer.h:56
ns_to_cycles
static size_t ns_to_cycles(double ns, double freq_ghz)
Definition: timer.h:69
measure_rdtsc_freq
static double measure_rdtsc_freq()
Definition: timer.h:24
TscTimer::reset
void reset()
Definition: timer.h:108
nano_sleep
static void nano_sleep(size_t ns, double freq_ghz)
Definition: timer.h:17
TscTimer
Simple time that uses RDTSC.
Definition: timer.h:110
ns_since
static double ns_since(const struct timespec &t0)
Return nanoseconds elapsed since timestamp t0.
Definition: timer.h:86
to_sec
static double to_sec(size_t cycles, double freq_ghz)
Convert cycles measured by rdtsc with frequence freq_ghz to seconds.
Definition: timer.h:51
nlohmann::json_v3_11_1NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON::detail2::end
end_tag end(T &&...)