time_precise.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
21 #if GPR_LINUX
22 #include <fcntl.h>
23 #include <unistd.h>
24 #endif
25 
26 #include <algorithm>
27 
29 #include <grpc/support/log.h>
30 #include <grpc/support/time.h>
31 
33 
34 #ifndef GPR_CYCLE_COUNTER_CUSTOM
35 #if GPR_CYCLE_COUNTER_RDTSC_32 || GPR_CYCLE_COUNTER_RDTSC_64
36 #if GPR_LINUX
37 static bool read_freq_from_kernel(double* freq) {
38  // Google production kernel export the frequency for us in kHz.
39  int fd = open("/sys/devices/system/cpu/cpu0/tsc_freq_khz", O_RDONLY);
40  if (fd == -1) {
41  return false;
42  }
43  char line[1024] = {};
44  char* err;
45  bool ret = false;
46  int len = read(fd, line, sizeof(line) - 1);
47  if (len > 0) {
48  const long val = strtol(line, &err, 10);
49  if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
50  *freq = val * 1e3; // Value is kHz.
51  ret = true;
52  }
53  }
54  close(fd);
55  return ret;
56 }
57 #endif /* GPR_LINUX */
58 
59 static double cycles_per_second = 0;
60 static gpr_cycle_counter start_cycle;
61 
62 static bool is_fake_clock() {
64  int64_t sum = 0;
65  for (int i = 0; i < 8; ++i) {
68  sum += delta.tv_sec * GPR_NS_PER_SEC + delta.tv_nsec;
69  }
70  // If the clock doesn't move even a nano after 8 tries, it's a fake one.
71  return sum == 0;
72 }
73 
74 void gpr_precise_clock_init(void) {
75  gpr_log(GPR_DEBUG, "Calibrating timers");
76 
77 #if GPR_LINUX
78  if (read_freq_from_kernel(&cycles_per_second)) {
79  start_cycle = gpr_get_cycle_counter();
80  return;
81  }
82 #endif /* GPR_LINUX */
83 
84  if (is_fake_clock()) {
85  cycles_per_second = 1;
86  start_cycle = 0;
87  return;
88  }
89  // Start from a loop of 1ms, and gradually increase the loop duration
90  // until we either converge or we have passed 255ms (1ms+2ms+...+128ms).
91  int64_t measurement_ns = GPR_NS_PER_MS;
92  double last_freq = -1;
93  bool converged = false;
94  for (int i = 0; i < 8 && !converged; ++i, measurement_ns *= 2) {
95  start_cycle = gpr_get_cycle_counter();
96  int64_t loop_ns;
98  do {
99  // TODO(soheil): Maybe sleep instead of busy polling.
102  loop_ns = delta.tv_sec * GPR_NS_PER_SEC + delta.tv_nsec;
103  } while (loop_ns < measurement_ns);
104  gpr_cycle_counter end_cycle = gpr_get_cycle_counter();
105  // Frequency should be in Hz.
106  const double freq =
107  static_cast<double>(end_cycle - start_cycle) / loop_ns * GPR_NS_PER_SEC;
108  converged =
109  last_freq != -1 && (freq * 0.99 < last_freq && last_freq < freq * 1.01);
110  last_freq = freq;
111  }
112  cycles_per_second = last_freq;
113  gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second);
114 }
115 
116 gpr_timespec gpr_cycle_counter_to_time(gpr_cycle_counter cycles) {
117  const double secs =
118  static_cast<double>(cycles - start_cycle) / cycles_per_second;
119  gpr_timespec ts;
120  ts.tv_sec = static_cast<int64_t>(secs);
121  ts.tv_nsec = static_cast<int32_t>(GPR_NS_PER_SEC *
122  (secs - static_cast<double>(ts.tv_sec)));
123  ts.clock_type = GPR_CLOCK_PRECISE;
124  return ts;
125 }
126 
127 gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b) {
128  const double secs = static_cast<double>(a - b) / cycles_per_second;
129  gpr_timespec ts;
130  ts.tv_sec = static_cast<int64_t>(secs);
131  ts.tv_nsec = static_cast<int32_t>(GPR_NS_PER_SEC *
132  (secs - static_cast<double>(ts.tv_sec)));
133  ts.clock_type = GPR_TIMESPAN;
134  return ts;
135 }
136 
138  int64_t counter = gpr_get_cycle_counter();
140 }
141 #elif GPR_CYCLE_COUNTER_FALLBACK
142 void gpr_precise_clock_init(void) {}
143 
144 gpr_cycle_counter gpr_get_cycle_counter() {
146  return gpr_timespec_to_micros(ts);
147 }
148 
149 gpr_timespec gpr_cycle_counter_to_time(gpr_cycle_counter cycles) {
150  gpr_timespec ts;
151  ts.tv_sec = static_cast<int64_t>(cycles / GPR_US_PER_SEC);
152  ts.tv_nsec = static_cast<int64_t>((cycles - ts.tv_sec * GPR_US_PER_SEC) *
153  GPR_NS_PER_US);
155  return ts;
156 }
157 
159  *clk = gpr_now(GPR_CLOCK_REALTIME);
161 }
162 
163 gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b) {
166 }
167 #endif /* GPR_CYCLE_COUNTER_FALLBACK */
168 #endif /* !GPR_CYCLE_COUNTER_CUSTOM */
gpr_timespec::tv_nsec
int32_t tv_nsec
Definition: gpr_types.h:52
gpr_timespec_to_micros
GPRAPI double gpr_timespec_to_micros(gpr_timespec t)
Definition: src/core/lib/gpr/time.cc:237
GPR_TIMESPAN
@ GPR_TIMESPAN
Definition: gpr_types.h:45
gpr_timespec::tv_sec
int64_t tv_sec
Definition: gpr_types.h:51
now
static double now(void)
Definition: test/core/fling/client.cc:130
log.h
grpc::testing::sum
double sum(const T &container, F functor)
Definition: test/cpp/qps/stats.h:30
error_ref_leak.err
err
Definition: error_ref_leak.py:35
gpr_cycle_counter_to_time
gpr_timespec gpr_cycle_counter_to_time(gpr_cycle_counter cycles)
GPR_US_PER_SEC
#define GPR_US_PER_SEC
Definition: include/grpc/support/time.h:40
gpr_precise_clock_now
void gpr_precise_clock_now(gpr_timespec *clk)
time.h
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
GPR_NS_PER_SEC
#define GPR_NS_PER_SEC
Definition: include/grpc/support/time.h:41
start
static uint64_t start
Definition: benchmark-pound.c:74
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
gpr_time_sub
GPRAPI gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:168
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
counter
static int counter
Definition: abseil-cpp/absl/flags/reflection_test.cc:131
close
#define close
Definition: test-fs.c:48
GPR_CLOCK_MONOTONIC
@ GPR_CLOCK_MONOTONIC
Definition: gpr_types.h:36
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
GPR_NS_PER_US
#define GPR_NS_PER_US
Definition: include/grpc/support/time.h:43
gpr_now
GPRAPI gpr_timespec gpr_now(gpr_clock_type clock)
gpr_types.h
GPR_NS_PER_MS
#define GPR_NS_PER_MS
Definition: include/grpc/support/time.h:42
gpr_timespec::clock_type
gpr_clock_type clock_type
Definition: gpr_types.h:55
GPR_CLOCK_PRECISE
@ GPR_CLOCK_PRECISE
Definition: gpr_types.h:42
read
int read(izstream &zs, T *x, Items items)
Definition: bloaty/third_party/zlib/contrib/iostream2/zstream.h:115
gpr_cycle_counter_sub
gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b)
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
regen-readme.line
line
Definition: regen-readme.py:30
open
#define open
Definition: test-fs.c:46
GPR_DEBUG
#define GPR_DEBUG
Definition: include/grpc/impl/codegen/log.h:55
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
gpr_timespec
Definition: gpr_types.h:50
GPR_CLOCK_REALTIME
@ GPR_CLOCK_REALTIME
Definition: gpr_types.h:39
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
gpr_precise_clock_init
void gpr_precise_clock_init(void)
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
time_precise.h
port_platform.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:37