• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 #include <grpc/support/port_platform.h>
20 
21 #if GPR_LINUX
22 #include <fcntl.h>
23 #include <unistd.h>
24 #endif
25 
26 #include <algorithm>
27 
28 #include <grpc/impl/codegen/gpr_types.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/time.h>
31 
32 #include "src/core/lib/gpr/time_precise.h"
33 
34 #ifndef GPR_CYCLE_COUNTER_CUSTOM
35 #if GPR_CYCLE_COUNTER_RDTSC_32 || GPR_CYCLE_COUNTER_RDTSC_64
36 #if GPR_LINUX
read_freq_from_kernel(double * freq)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 
is_fake_clock()62 static bool is_fake_clock() {
63   gpr_timespec start = gpr_now(GPR_CLOCK_MONOTONIC);
64   int64_t sum = 0;
65   for (int i = 0; i < 8; ++i) {
66     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
67     gpr_timespec delta = gpr_time_sub(now, start);
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 
gpr_precise_clock_init(void)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;
97     gpr_timespec start = gpr_now(GPR_CLOCK_MONOTONIC);
98     do {
99       // TODO(soheil): Maybe sleep instead of busy polling.
100       gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
101       gpr_timespec delta = gpr_time_sub(now, start);
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 
gpr_cycle_counter_to_time(gpr_cycle_counter cycles)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 
gpr_cycle_counter_sub(gpr_cycle_counter a,gpr_cycle_counter b)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 
gpr_precise_clock_now(gpr_timespec * clk)137 void gpr_precise_clock_now(gpr_timespec* clk) {
138   int64_t counter = gpr_get_cycle_counter();
139   *clk = gpr_cycle_counter_to_time(counter);
140 }
141 #elif GPR_CYCLE_COUNTER_FALLBACK
gpr_precise_clock_init(void)142 void gpr_precise_clock_init(void) {}
143 
gpr_get_cycle_counter()144 gpr_cycle_counter gpr_get_cycle_counter() {
145   gpr_timespec ts = gpr_now(GPR_CLOCK_REALTIME);
146   return gpr_timespec_to_micros(ts);
147 }
148 
gpr_cycle_counter_to_time(gpr_cycle_counter cycles)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);
154   ts.clock_type = GPR_CLOCK_PRECISE;
155   return ts;
156 }
157 
gpr_precise_clock_now(gpr_timespec * clk)158 void gpr_precise_clock_now(gpr_timespec* clk) {
159   *clk = gpr_now(GPR_CLOCK_REALTIME);
160   clk->clock_type = GPR_CLOCK_PRECISE;
161 }
162 
gpr_cycle_counter_sub(gpr_cycle_counter a,gpr_cycle_counter b)163 gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b) {
164   return gpr_time_sub(gpr_cycle_counter_to_time(a),
165                       gpr_cycle_counter_to_time(b));
166 }
167 #endif /* GPR_CYCLE_COUNTER_FALLBACK */
168 #endif /* !GPR_CYCLE_COUNTER_CUSTOM */
169