25
25
#include " src/core/lib/iomgr/combiner.h"
26
26
#include " src/core/lib/profiling/timers.h"
27
27
28
+ #define GRPC_START_TIME_UPDATE_INTERVAL 10000
29
+ extern " C" grpc_tracer_flag grpc_timer_check_trace;
30
+
28
31
bool grpc_exec_ctx_ready_to_finish (grpc_exec_ctx* exec_ctx) {
29
32
if ((exec_ctx->flags & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0 ) {
30
33
if (exec_ctx->check_ready_to_finish (exec_ctx,
@@ -104,23 +107,49 @@ static void exec_ctx_sched(grpc_exec_ctx* exec_ctx, grpc_closure* closure,
104
107
grpc_closure_list_append (&exec_ctx->closure_list , closure, error);
105
108
}
106
109
107
- static gpr_timespec
110
+ /* This time pair is not entirely thread-safe as store/load of tv_sec and
111
+ * tv_nsec are performed separately. However g_start_time do not need to have
112
+ * sub-second precision, so it is ok if the value of tv_nsec is off in this
113
+ * case. */
114
+ typedef struct time_atm_pair {
115
+ gpr_atm tv_sec;
116
+ gpr_atm tv_nsec;
117
+ } time_atm_pair;
118
+
119
+ static time_atm_pair
108
120
g_start_time[GPR_TIMESPAN + 1 ]; // assumes GPR_TIMESPAN is the
109
121
// last enum value in
110
122
// gpr_clock_type
123
+ static grpc_millis g_last_start_time_update;
124
+
125
+ static gpr_timespec timespec_from_time_atm_pair (const time_atm_pair* src,
126
+ gpr_clock_type clock_type) {
127
+ gpr_timespec time ;
128
+ time .tv_nsec = (int32_t )gpr_atm_no_barrier_load (&src->tv_nsec );
129
+ time .tv_sec = (int64_t )gpr_atm_no_barrier_load (&src->tv_sec );
130
+ time .clock_type = clock_type;
131
+ return time ;
132
+ }
133
+
134
+ static void time_atm_pair_store (time_atm_pair* dst, const gpr_timespec src) {
135
+ gpr_atm_no_barrier_store (&dst->tv_sec , src.tv_sec );
136
+ gpr_atm_no_barrier_store (&dst->tv_nsec , src.tv_nsec );
137
+ }
111
138
112
139
void grpc_exec_ctx_global_init (void ) {
113
140
for (int i = 0 ; i < GPR_TIMESPAN; i++) {
114
- g_start_time[i] = gpr_now ((gpr_clock_type)i);
141
+ time_atm_pair_store (& g_start_time[i], gpr_now ((gpr_clock_type)i) );
115
142
}
116
143
// allows uniform treatment in conversion functions
117
- g_start_time[GPR_TIMESPAN] = gpr_time_0 (GPR_TIMESPAN);
144
+ time_atm_pair_store (& g_start_time[GPR_TIMESPAN], gpr_time_0 (GPR_TIMESPAN) );
118
145
}
119
146
120
147
void grpc_exec_ctx_global_shutdown (void ) {}
121
148
122
149
static gpr_atm timespec_to_atm_round_down (gpr_timespec ts) {
123
- ts = gpr_time_sub (ts, g_start_time[ts.clock_type ]);
150
+ gpr_timespec start_time =
151
+ timespec_from_time_atm_pair (&g_start_time[ts.clock_type ], ts.clock_type );
152
+ ts = gpr_time_sub (ts, start_time);
124
153
double x =
125
154
GPR_MS_PER_SEC * (double )ts.tv_sec + (double )ts.tv_nsec / GPR_NS_PER_MS;
126
155
if (x < 0 ) return 0 ;
@@ -129,7 +158,9 @@ static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
129
158
}
130
159
131
160
static gpr_atm timespec_to_atm_round_up (gpr_timespec ts) {
132
- ts = gpr_time_sub (ts, g_start_time[ts.clock_type ]);
161
+ gpr_timespec start_time =
162
+ timespec_from_time_atm_pair (&g_start_time[ts.clock_type ], ts.clock_type );
163
+ ts = gpr_time_sub (ts, start_time);
133
164
double x = GPR_MS_PER_SEC * (double )ts.tv_sec +
134
165
(double )ts.tv_nsec / GPR_NS_PER_MS +
135
166
(double )(GPR_NS_PER_SEC - 1 ) / (double )GPR_NS_PER_SEC;
@@ -164,8 +195,9 @@ gpr_timespec grpc_millis_to_timespec(grpc_millis millis,
164
195
if (clock_type == GPR_TIMESPAN) {
165
196
return gpr_time_from_millis (millis, GPR_TIMESPAN);
166
197
}
167
- return gpr_time_add (g_start_time[clock_type],
168
- gpr_time_from_millis (millis, GPR_TIMESPAN));
198
+ gpr_timespec start_time =
199
+ timespec_from_time_atm_pair (&g_start_time[clock_type], clock_type);
200
+ return gpr_time_add (start_time, gpr_time_from_millis (millis, GPR_TIMESPAN));
169
201
}
170
202
171
203
grpc_millis grpc_timespec_to_millis_round_down (gpr_timespec ts) {
@@ -176,6 +208,30 @@ grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec ts) {
176
208
return timespec_to_atm_round_up (ts);
177
209
}
178
210
211
+ void grpc_exec_ctx_maybe_update_start_time (grpc_exec_ctx* exec_ctx) {
212
+ grpc_millis now = grpc_exec_ctx_now (exec_ctx);
213
+ grpc_millis last_start_time_update =
214
+ gpr_atm_no_barrier_load (&g_last_start_time_update);
215
+
216
+ if (now > last_start_time_update &&
217
+ now - last_start_time_update > GRPC_START_TIME_UPDATE_INTERVAL) {
218
+ /* Get the current system time and subtract \a now from it, where \a now is
219
+ * the relative time from grpc_init() from monotonic clock. This calibrates
220
+ * the time when grpc_exec_ctx_global_init was called based on current
221
+ * system clock. */
222
+ gpr_atm_no_barrier_store (&g_last_start_time_update, now);
223
+ gpr_timespec real_now = gpr_now (GPR_CLOCK_REALTIME);
224
+ gpr_timespec real_start_time =
225
+ gpr_time_sub (real_now, gpr_time_from_millis (now, GPR_TIMESPAN));
226
+ time_atm_pair_store (&g_start_time[GPR_CLOCK_REALTIME], real_start_time);
227
+
228
+ if (GRPC_TRACER_ON (grpc_timer_check_trace)) {
229
+ gpr_log (GPR_DEBUG, " Update realtime clock start time: %" PRId64 " s %dns" ,
230
+ real_start_time.tv_sec , real_start_time.tv_nsec );
231
+ }
232
+ }
233
+ }
234
+
179
235
static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
180
236
exec_ctx_run, exec_ctx_sched, " exec_ctx" };
181
237
static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable};
0 commit comments