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 #if GPR_CYCLE_COUNTER_RDTSC_32 || GPR_CYCLE_COUNTER_RDTSC_64
35 #if GPR_LINUX
read_freq_from_kernel(double * freq)36 static bool read_freq_from_kernel(double* freq) {
37 // Google production kernel export the frequency for us in kHz.
38 int fd = open("/sys/devices/system/cpu/cpu0/tsc_freq_khz", O_RDONLY);
39 if (fd == -1) {
40 return false;
41 }
42 char line[1024] = {};
43 char* err;
44 bool ret = false;
45 int len = read(fd, line, sizeof(line) - 1);
46 if (len > 0) {
47 const long val = strtol(line, &err, 10);
48 if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
49 *freq = val * 1e3; // Value is kHz.
50 ret = true;
51 }
52 }
53 close(fd);
54 return ret;
55 }
56 #endif /* GPR_LINUX */
57
58 static double cycles_per_second = 0;
59 static gpr_cycle_counter start_cycle;
60
is_fake_clock()61 static bool is_fake_clock() {
62 gpr_timespec start = gpr_now(GPR_CLOCK_MONOTONIC);
63 int64_t sum = 0;
64 for (int i = 0; i < 8; ++i) {
65 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
66 gpr_timespec delta = gpr_time_sub(now, start);
67 sum += delta.tv_sec * GPR_NS_PER_SEC + delta.tv_nsec;
68 }
69 // If the clock doesn't move even a nano after 8 tries, it's a fake one.
70 return sum == 0;
71 }
72
gpr_precise_clock_init(void)73 void gpr_precise_clock_init(void) {
74 gpr_log(GPR_DEBUG, "Calibrating timers");
75
76 #if GPR_LINUX
77 if (read_freq_from_kernel(&cycles_per_second)) {
78 start_cycle = gpr_get_cycle_counter();
79 return;
80 }
81 #endif /* GPR_LINUX */
82
83 if (is_fake_clock()) {
84 cycles_per_second = 1;
85 start_cycle = 0;
86 return;
87 }
88 // Start from a loop of 1ms, and gradually increase the loop duration
89 // until we either converge or we have passed 255ms (1ms+2ms+...+128ms).
90 int64_t measurement_ns = GPR_NS_PER_MS;
91 double last_freq = -1;
92 bool converged = false;
93 for (int i = 0; i < 8 && !converged; ++i, measurement_ns *= 2) {
94 start_cycle = gpr_get_cycle_counter();
95 int64_t loop_ns;
96 gpr_timespec start = gpr_now(GPR_CLOCK_MONOTONIC);
97 do {
98 // TODO(soheil): Maybe sleep instead of busy polling.
99 gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
100 gpr_timespec delta = gpr_time_sub(now, start);
101 loop_ns = delta.tv_sec * GPR_NS_PER_SEC + delta.tv_nsec;
102 } while (loop_ns < measurement_ns);
103 gpr_cycle_counter end_cycle = gpr_get_cycle_counter();
104 // Frequency should be in Hz.
105 const double freq =
106 static_cast<double>(end_cycle - start_cycle) / loop_ns * GPR_NS_PER_SEC;
107 converged =
108 last_freq != -1 && (freq * 0.99 < last_freq && last_freq < freq * 1.01);
109 last_freq = freq;
110 }
111 cycles_per_second = last_freq;
112 gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second);
113 }
114
gpr_cycle_counter_to_time(gpr_cycle_counter cycles)115 gpr_timespec gpr_cycle_counter_to_time(gpr_cycle_counter cycles) {
116 const double secs =
117 static_cast<double>(cycles - start_cycle) / cycles_per_second;
118 gpr_timespec ts;
119 ts.tv_sec = static_cast<int64_t>(secs);
120 ts.tv_nsec = static_cast<int32_t>(GPR_NS_PER_SEC *
121 (secs - static_cast<double>(ts.tv_sec)));
122 ts.clock_type = GPR_CLOCK_PRECISE;
123 return ts;
124 }
125
gpr_cycle_counter_sub(gpr_cycle_counter a,gpr_cycle_counter b)126 gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b) {
127 const double secs = static_cast<double>(a - b) / cycles_per_second;
128 gpr_timespec ts;
129 ts.tv_sec = static_cast<int64_t>(secs);
130 ts.tv_nsec = static_cast<int32_t>(GPR_NS_PER_SEC *
131 (secs - static_cast<double>(ts.tv_sec)));
132 ts.clock_type = GPR_TIMESPAN;
133 return ts;
134 }
135
gpr_precise_clock_now(gpr_timespec * clk)136 void gpr_precise_clock_now(gpr_timespec* clk) {
137 int64_t counter = gpr_get_cycle_counter();
138 *clk = gpr_cycle_counter_to_time(counter);
139 }
140 #elif GPR_CYCLE_COUNTER_FALLBACK
gpr_precise_clock_init(void)141 void gpr_precise_clock_init(void) {}
142
gpr_get_cycle_counter()143 gpr_cycle_counter gpr_get_cycle_counter() {
144 gpr_timespec ts = gpr_now(GPR_CLOCK_REALTIME);
145 return gpr_timespec_to_micros(ts);
146 }
147
gpr_cycle_counter_to_time(gpr_cycle_counter cycles)148 gpr_timespec gpr_cycle_counter_to_time(gpr_cycle_counter cycles) {
149 gpr_timespec ts;
150 ts.tv_sec = cycles / GPR_US_PER_SEC;
151 ts.tv_nsec = (cycles - ts.tv_sec * GPR_US_PER_SEC) * GPR_NS_PER_US;
152 ts.clock_type = GPR_CLOCK_PRECISE;
153 return ts;
154 }
155
gpr_precise_clock_now(gpr_timespec * clk)156 void gpr_precise_clock_now(gpr_timespec* clk) {
157 *clk = gpr_now(GPR_CLOCK_REALTIME);
158 clk->clock_type = GPR_CLOCK_PRECISE;
159 }
160
gpr_cycle_counter_sub(gpr_cycle_counter a,gpr_cycle_counter b)161 gpr_timespec gpr_cycle_counter_sub(gpr_cycle_counter a, gpr_cycle_counter b) {
162 return gpr_time_sub(gpr_cycle_counter_to_time(a),
163 gpr_cycle_counter_to_time(b));
164 }
165 #endif /* GPR_CYCLE_COUNTER_FALLBACK */
166