timer_generic.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 #include <inttypes.h>
22 
23 #include <string>
24 
25 #include "absl/strings/str_cat.h"
26 
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/cpu.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/sync.h>
31 
34 #include "src/core/lib/gpr/tls.h"
42 
43 #define INVALID_HEAP_INDEX 0xffffffffu
44 
45 #define ADD_DEADLINE_SCALE 0.33
46 #define MIN_QUEUE_WINDOW_DURATION 0.01
47 #define MAX_QUEUE_WINDOW_DURATION 1.0
48 
50 grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
51 
52 /* A "timer shard". Contains a 'heap' and a 'list' of timers. All timers with
53  * deadlines earlier than 'queue_deadline_cap' are maintained in the heap and
54  * others are maintained in the list (unordered). This helps to keep the number
55  * of elements in the heap low.
56  *
57  * The 'queue_deadline_cap' gets recomputed periodically based on the timer
58  * stats maintained in 'stats' and the relevant timers are then moved from the
59  * 'list' to 'heap'.
60  */
61 struct timer_shard {
64  /* All and only timers with deadlines < this will be in the heap. */
66  /* The deadline of the next timer due in this shard. */
68  /* Index of this timer_shard in the g_shard_queue. */
70  /* This holds all timers with deadlines < queue_deadline_cap. Timers in this
71  list have the top bit of their deadline set to 0. */
73  /* This holds timers whose deadline is >= queue_deadline_cap. */
75 };
76 static size_t g_num_shards;
77 
78 /* Array of timer shards. Whenever a timer (grpc_timer *) is added, its address
79  * is hashed to select the timer shard to add the timer to */
81 
82 /* Maintains a sorted list of timer shards (sorted by their min_deadline, i.e
83  * the deadline of the next timer in each shard).
84  * Access to this is protected by g_shared_mutables.mu */
86 
87 #ifndef NDEBUG
88 
89 /* == DEBUG ONLY: hash table for duplicate timer detection == */
90 
91 #define NUM_HASH_BUCKETS 1009 /* Prime number close to 1000 */
92 
93 static gpr_mu g_hash_mu[NUM_HASH_BUCKETS]; /* One mutex per bucket */
94 static grpc_timer* g_timer_ht[NUM_HASH_BUCKETS] = {nullptr};
95 
96 static void init_timer_ht() {
97  for (int i = 0; i < NUM_HASH_BUCKETS; i++) {
99  }
100 }
101 
102 static void destroy_timer_ht() {
103  for (int i = 0; i < NUM_HASH_BUCKETS; i++) {
105  }
106 }
107 
108 static bool is_in_ht(grpc_timer* t) {
110 
112  grpc_timer* p = g_timer_ht[i];
113  while (p != nullptr && p != t) {
114  p = p->hash_table_next;
115  }
117 
118  return (p == t);
119 }
120 
121 static void add_to_ht(grpc_timer* t) {
122  GPR_ASSERT(!t->hash_table_next);
124 
126  grpc_timer* p = g_timer_ht[i];
127  while (p != nullptr && p != t) {
128  p = p->hash_table_next;
129  }
130 
131  if (p == t) {
132  grpc_closure* c = t->closure;
134  "** Duplicate timer (%p) being added. Closure: (%p), created at: "
135  "(%s:%d), scheduled at: (%s:%d) **",
136  t, c, c->file_created, c->line_created, c->file_initiated,
137  c->line_initiated);
138  abort();
139  }
140 
141  /* Timer not present in the bucket. Insert at head of the list */
142  t->hash_table_next = g_timer_ht[i];
143  g_timer_ht[i] = t;
145 }
146 
147 static void remove_from_ht(grpc_timer* t) {
149  bool removed = false;
150 
152  if (g_timer_ht[i] == t) {
154  removed = true;
155  } else if (g_timer_ht[i] != nullptr) {
156  grpc_timer* p = g_timer_ht[i];
157  while (p->hash_table_next != nullptr && p->hash_table_next != t) {
158  p = p->hash_table_next;
159  }
160 
161  if (p->hash_table_next == t) {
162  p->hash_table_next = t->hash_table_next;
163  removed = true;
164  }
165  }
167 
168  if (!removed) {
169  grpc_closure* c = t->closure;
171  "** Removing timer (%p) that is not added to hash table. Closure "
172  "(%p), created at: (%s:%d), scheduled at: (%s:%d) **",
173  t, c, c->file_created, c->line_created, c->file_initiated,
174  c->line_initiated);
175  abort();
176  }
177 
178  t->hash_table_next = nullptr;
179 }
180 
181 /* If a timer is added to a timer shard (either heap or a list), it must
182  * be pending. A timer is added to hash table only-if it is added to the
183  * timer shard.
184  * Therefore, if timer->pending is false, it cannot be in hash table */
186  if (!t->pending && is_in_ht(t)) {
187  grpc_closure* c = t->closure;
189  "** gpr_timer_cancel() called on a non-pending timer (%p) which "
190  "is in the hash table. Closure: (%p), created at: (%s:%d), "
191  "scheduled at: (%s:%d) **",
192  t, c, c->file_created, c->line_created, c->file_initiated,
193  c->line_initiated);
194  abort();
195  }
196 }
197 
198 #define INIT_TIMER_HASH_TABLE() init_timer_ht()
199 #define DESTROY_TIMER_HASH_TABLE() destroy_timer_ht()
200 #define ADD_TO_HASH_TABLE(t) add_to_ht((t))
201 #define REMOVE_FROM_HASH_TABLE(t) remove_from_ht((t))
202 #define VALIDATE_NON_PENDING_TIMER(t) validate_non_pending_timer((t))
203 
204 #else
205 
206 #define INIT_TIMER_HASH_TABLE()
207 #define DESTROY_TIMER_HASH_TABLE()
208 #define ADD_TO_HASH_TABLE(t)
209 #define REMOVE_FROM_HASH_TABLE(t)
210 #define VALIDATE_NON_PENDING_TIMER(t)
211 
212 #endif
213 
214 /* Thread local variable that stores the deadline of the next timer the thread
215  * has last-seen. This is an optimization to prevent the thread from checking
216  * shared_mutables.min_timer (which requires acquiring shared_mutables.mu lock,
217  * an expensive operation) */
218 static GPR_THREAD_LOCAL(int64_t) g_last_seen_min_timer;
219 
221  /* The deadline of the next timer due across all timer shards */
223  /* Allow only one run_some_expired_timers at once */
226  /* Protects g_shard_queue (and the shared_mutables struct itself) */
229 
231 
235 
237  return grpc_timer_heap_is_empty(&shard->heap)
240  grpc_timer_heap_top(&shard->heap)->deadline);
241 }
242 
243 static void timer_list_init() {
244  uint32_t i;
245 
247  g_shards =
248  static_cast<timer_shard*>(gpr_zalloc(g_num_shards * sizeof(*g_shards)));
249  g_shard_queue = static_cast<timer_shard**>(
251 
256 
257  g_last_seen_min_timer = 0;
258 
259  for (i = 0; i < g_num_shards; i++) {
260  timer_shard* shard = &g_shards[i];
261  gpr_mu_init(&shard->mu);
263  0.5);
265  shard->shard_queue_index = i;
266  grpc_timer_heap_init(&shard->heap);
267  shard->list.next = shard->list.prev = &shard->list;
268  shard->min_deadline = compute_min_deadline(shard);
269  g_shard_queue[i] = shard;
270  }
271 
273 }
274 
275 static void timer_list_shutdown() {
276  size_t i;
279  GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown"));
280  for (i = 0; i < g_num_shards; i++) {
281  timer_shard* shard = &g_shards[i];
282  gpr_mu_destroy(&shard->mu);
283  grpc_timer_heap_destroy(&shard->heap);
284  }
289 
291 }
292 
293 /* returns true if the first element in the list */
294 static void list_join(grpc_timer* head, grpc_timer* timer) {
295  timer->next = head;
296  timer->prev = head->prev;
297  timer->next->prev = timer->prev->next = timer;
298 }
299 
300 static void list_remove(grpc_timer* timer) {
301  timer->next->prev = timer->prev;
302  timer->prev->next = timer->next;
303 }
304 
305 static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) {
306  timer_shard* temp;
307  temp = g_shard_queue[first_shard_queue_index];
308  g_shard_queue[first_shard_queue_index] =
309  g_shard_queue[first_shard_queue_index + 1];
310  g_shard_queue[first_shard_queue_index + 1] = temp;
311  g_shard_queue[first_shard_queue_index]->shard_queue_index =
312  first_shard_queue_index;
313  g_shard_queue[first_shard_queue_index + 1]->shard_queue_index =
314  first_shard_queue_index + 1;
315 }
316 
317 static void note_deadline_change(timer_shard* shard) {
318  while (shard->shard_queue_index > 0 &&
319  shard->min_deadline <
322  }
323  while (shard->shard_queue_index < g_num_shards - 1 &&
324  shard->min_deadline >
327  }
328 }
329 
330 void grpc_timer_init_unset(grpc_timer* timer) { timer->pending = false; }
331 
334  int is_first_timer = 0;
336  timer->closure = closure;
337  timer->deadline = deadline.milliseconds_after_process_epoch();
338 
339 #ifndef NDEBUG
340  timer->hash_table_next = nullptr;
341 #endif
342 
344  gpr_log(GPR_INFO, "TIMER %p: SET %" PRId64 " now %" PRId64 " call %p[%p]",
347  closure, closure->cb);
348  }
349 
351  timer->pending = false;
353  DEBUG_LOCATION, timer->closure,
355  "Attempt to create timer before initialization"));
356  return;
357  }
358 
359  gpr_mu_lock(&shard->mu);
360  timer->pending = true;
362  if (deadline <= now) {
363  timer->pending = false;
365  gpr_mu_unlock(&shard->mu);
366  /* early out */
367  return;
368  }
369 
371  (deadline - now).millis() / 1000.0);
372 
374 
375  if (deadline < shard->queue_deadline_cap) {
376  is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
377  } else {
378  timer->heap_index = INVALID_HEAP_INDEX;
379  list_join(&shard->list, timer);
380  }
383  " .. add to shard %d with queue_deadline_cap=%" PRId64
384  " => is_first_timer=%s",
385  static_cast<int>(shard - g_shards),
387  is_first_timer ? "true" : "false");
388  }
389  gpr_mu_unlock(&shard->mu);
390 
391  /* Deadline may have decreased, we need to adjust the main queue. Note
392  that there is a potential racy unlocked region here. There could be a
393  reordering of multiple grpc_timer_init calls, at this point, but the < test
394  below should ensure that we err on the side of caution. There could
395  also be a race with grpc_timer_check, which might beat us to the lock. In
396  that case, it is possible that the timer that we added will have already
397  run by the time we hold the lock, but that too is a safe error.
398  Finally, it's possible that the grpc_timer_check that intervened failed to
399  trigger the new timer because the min_deadline hadn't yet been reduced.
400  In that case, the timer will simply have to wait for the next
401  grpc_timer_check. */
402  if (is_first_timer) {
405  gpr_log(GPR_INFO, " .. old shard min_deadline=%" PRId64,
407  }
408  if (deadline < shard->min_deadline) {
409  grpc_core::Timestamp old_min_deadline = g_shard_queue[0]->min_deadline;
410  shard->min_deadline = deadline;
411  note_deadline_change(shard);
412  if (shard->shard_queue_index == 0 && deadline < old_min_deadline) {
413 #if GPR_ARCH_64
414  // TODO(sreek): Using c-style cast here. static_cast<> gives an error
415  // (on mac platforms complaining that gpr_atm* is (long *) while
416  // (&g_shared_mutables.min_timer) is a (long long *). The cast should be
417  // safe since we know that both are pointer types and 64-bit wide.
420 #else
421  // On 32-bit systems, gpr_atm_no_barrier_store does not work on 64-bit
422  // types (like grpc_core::Timestamp). So all reads and writes to
423  // g_shared_mutables.min_timer varialbe under g_shared_mutables.mu
424  g_shared_mutables.min_timer = deadline;
425 #endif
427  }
428  }
430  }
431 }
432 
433 static void timer_consume_kick(void) {
434  /* Force re-evaluation of last seen min */
435  g_last_seen_min_timer = 0;
436 }
437 
440  /* must have already been cancelled, also the shard mutex is invalid */
441  return;
442  }
443 
445  gpr_mu_lock(&shard->mu);
447  gpr_log(GPR_INFO, "TIMER %p: CANCEL pending=%s", timer,
448  timer->pending ? "true" : "false");
449  }
450 
451  if (timer->pending) {
453 
456  timer->pending = false;
457  if (timer->heap_index == INVALID_HEAP_INDEX) {
459  } else {
461  }
462  } else {
464  }
465  gpr_mu_unlock(&shard->mu);
466 }
467 
468 /* Rebalances the timer shard by computing a new 'queue_deadline_cap' and moving
469  all relevant timers in shard->list (i.e timers with deadlines earlier than
470  'queue_deadline_cap') into into shard->heap.
471  Returns 'true' if shard->heap has at least ONE element
472  REQUIRES: shard->mu locked */
474  /* Compute the new queue window width and bound by the limits: */
475  double computed_deadline_delta =
478  double deadline_delta =
479  grpc_core::Clamp(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION,
481  grpc_timer *timer, *next;
482 
483  /* Compute the new cap and put all timers under it into the queue: */
484  shard->queue_deadline_cap =
485  std::max(now, shard->queue_deadline_cap) +
487 
489  gpr_log(GPR_INFO, " .. shard[%d]->queue_deadline_cap --> %" PRId64,
490  static_cast<int>(shard - g_shards),
492  }
493  for (timer = shard->list.next; timer != &shard->list; timer = next) {
494  next = timer->next;
495  auto timer_deadline =
497  timer->deadline);
498 
499  if (timer_deadline < shard->queue_deadline_cap) {
501  gpr_log(GPR_INFO, " .. add timer with deadline %" PRId64 " to heap",
502  timer_deadline.milliseconds_after_process_epoch());
503  }
505  grpc_timer_heap_add(&shard->heap, timer);
506  }
507  }
508  return !grpc_timer_heap_is_empty(&shard->heap);
509 }
510 
511 /* This pops the next non-cancelled timer with deadline <= now from the
512  queue, or returns NULL if there isn't one.
513  REQUIRES: shard->mu locked */
515  grpc_timer* timer;
516  for (;;) {
518  gpr_log(GPR_INFO, " .. shard[%d]: heap_empty=%s",
519  static_cast<int>(shard - g_shards),
520  grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false");
521  }
522  if (grpc_timer_heap_is_empty(&shard->heap)) {
523  if (now < shard->queue_deadline_cap) return nullptr;
524  if (!refill_heap(shard, now)) return nullptr;
525  }
526  timer = grpc_timer_heap_top(&shard->heap);
527  auto timer_deadline =
529  timer->deadline);
532  " .. check top timer deadline=%" PRId64 " now=%" PRId64,
533  timer_deadline.milliseconds_after_process_epoch(),
534  now.milliseconds_after_process_epoch());
535  }
536  if (timer_deadline > now) return nullptr;
538  gpr_log(GPR_INFO, "TIMER %p: FIRE %" PRId64 "ms late", timer,
539  (now - timer_deadline).millis());
540  }
541  timer->pending = false;
542  grpc_timer_heap_pop(&shard->heap);
543  return timer;
544  }
545 }
546 
547 /* REQUIRES: shard->mu unlocked */
549  grpc_core::Timestamp* new_min_deadline,
551  size_t n = 0;
552  grpc_timer* timer;
553  gpr_mu_lock(&shard->mu);
554  while ((timer = pop_one(shard, now))) {
558  n++;
559  }
560  *new_min_deadline = compute_min_deadline(shard);
561  gpr_mu_unlock(&shard->mu);
563  gpr_log(GPR_INFO, " .. shard[%d] popped %" PRIdPTR,
564  static_cast<int>(shard - g_shards), n);
565  }
566  return n;
567 }
568 
573 
574 #if GPR_ARCH_64
575  // TODO(sreek): Using c-style cast here. static_cast<> gives an error (on
576  // mac platforms complaining that gpr_atm* is (long *) while
577  // (&g_shared_mutables.min_timer) is a (long long *). The cast should be
578  // safe since we know that both are pointer types and 64-bit wide
582 #else
583  // On 32-bit systems, gpr_atm_no_barrier_load does not work on 64-bit types
584  // (like grpc_core::Timestamp). So all reads and writes to
585  // g_shared_mutables.min_timer are done under g_shared_mutables.mu
589 #endif
590  g_last_seen_min_timer = min_timer.milliseconds_after_process_epoch();
591 
592  if (now < min_timer) {
593  if (next != nullptr) *next = std::min(*next, min_timer);
595  }
596 
600 
602  gpr_log(
603  GPR_INFO, " .. shard[%d]->min_deadline = %" PRId64,
604  static_cast<int>(g_shard_queue[0] - g_shards),
605  g_shard_queue[0]->min_deadline.milliseconds_after_process_epoch());
606  }
607 
608  while (g_shard_queue[0]->min_deadline < now ||
610  g_shard_queue[0]->min_deadline == now)) {
611  grpc_core::Timestamp new_min_deadline;
612 
613  /* For efficiency, we pop as many available timers as we can from the
614  shard. This may violate perfect timer deadline ordering, but that
615  shouldn't be a big deal because we don't make ordering guarantees. */
616  if (pop_timers(g_shard_queue[0], now, &new_min_deadline, error) > 0) {
618  }
619 
621  gpr_log(
622  GPR_INFO,
623  " .. result --> %d"
624  ", shard[%d]->min_deadline %" PRId64 " --> %" PRId64
625  ", now=%" PRId64,
626  result, static_cast<int>(g_shard_queue[0] - g_shards),
627  g_shard_queue[0]->min_deadline.milliseconds_after_process_epoch(),
628  new_min_deadline.milliseconds_after_process_epoch(),
629  now.milliseconds_after_process_epoch());
630  }
631 
632  /* An grpc_timer_init() on the shard could intervene here, adding a new
633  timer that is earlier than new_min_deadline. However,
634  grpc_timer_init() will block on the mutex before it can call
635  set_min_deadline, so this one will complete first and then the Addtimer
636  will reduce the min_deadline (perhaps unnecessarily). */
637  g_shard_queue[0]->min_deadline = new_min_deadline;
639  }
640 
641  if (next) {
642  *next = std::min(*next, g_shard_queue[0]->min_deadline);
643  }
644 
645 #if GPR_ARCH_64
646  // TODO(sreek): Using c-style cast here. static_cast<> gives an error (on
647  // mac platforms complaining that gpr_atm* is (long *) while
648  // (&g_shared_mutables.min_timer) is a (long long *). The cast should be
649  // safe since we know that both are pointer types and 64-bit wide
653 #else
654  // On 32-bit systems, gpr_atm_no_barrier_store does not work on 64-bit
655  // types (like grpc_core::Timestamp). So all reads and writes to
656  // g_shared_mutables.min_timer are done under g_shared_mutables.mu
658 #endif
661  }
662 
664 
665  return result;
666 }
667 
669  // prelude
671 
672  /* fetch from a thread-local first: this avoids contention on a globally
673  mutable cacheline in the common case */
676  g_last_seen_min_timer);
677 
678  if (now < min_timer) {
679  if (next != nullptr) {
680  *next = std::min(*next, min_timer);
681  }
683  gpr_log(GPR_INFO, "TIMER CHECK SKIP: now=%" PRId64 " min_timer=%" PRId64,
684  now.milliseconds_after_process_epoch(),
686  }
688  }
689 
690  grpc_error_handle shutdown_error =
693  : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
694 
695  // tracing
697  std::string next_str;
698  if (next == nullptr) {
699  next_str = "NULL";
700  } else {
701  next_str = absl::StrCat(next->milliseconds_after_process_epoch());
702  }
703 #if GPR_ARCH_64
704  gpr_log(
705  GPR_INFO,
706  "TIMER CHECK BEGIN: now=%" PRId64 " next=%s tls_min=%" PRId64
707  " glob_min=%" PRId64,
708  now.milliseconds_after_process_epoch(), next_str.c_str(),
713 #else
714  gpr_log(GPR_INFO, "TIMER CHECK BEGIN: now=%" PRId64 " next=%s min=%" PRId64,
715  now.milliseconds_after_process_epoch(), next_str.c_str(),
717 #endif
718  }
719  // actual code
721  run_some_expired_timers(now, next, shutdown_error);
722  // tracing
724  std::string next_str;
725  if (next == nullptr) {
726  next_str = "NULL";
727  } else {
728  next_str = absl::StrCat(next->milliseconds_after_process_epoch());
729  }
730  gpr_log(GPR_INFO, "TIMER CHECK END: r=%d; next=%s", r, next_str.c_str());
731  }
732  return r;
733 }
734 
trace.h
gpr_cpu_num_cores
GPRAPI unsigned gpr_cpu_num_cores(void)
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
GPR_SPINLOCK_INITIALIZER
#define GPR_SPINLOCK_INITIALIZER
Definition: src/core/lib/gpr/spinlock.h:35
gpr_mu_unlock
GPRAPI void gpr_mu_unlock(gpr_mu *mu)
timer_shard
Definition: timer_generic.cc:61
fix_build_deps.temp
temp
Definition: fix_build_deps.py:488
grpc_timer::next
struct grpc_timer * next
Definition: iomgr/timer.h:38
now
static double now(void)
Definition: test/core/fling/client.cc:130
gpr_atm_no_barrier_load
#define gpr_atm_no_barrier_load(p)
Definition: impl/codegen/atm_gcc_atomic.h:53
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
gpr_atm_no_barrier_store
#define gpr_atm_no_barrier_store(p, value)
Definition: impl/codegen/atm_gcc_atomic.h:56
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc_core::Duration::FromSecondsAsDouble
static Duration FromSecondsAsDouble(double seconds)
Definition: src/core/lib/gprpp/time.h:279
compute_min_deadline
static grpc_core::Timestamp compute_min_deadline(timer_shard *shard)
Definition: timer_generic.cc:236
gpr_spinlock
Definition: src/core/lib/gpr/spinlock.h:29
grpc_timer_heap_remove
void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer)
Definition: iomgr/timer_heap.cc:110
shared_mutables
Definition: timer_generic.cc:220
timer_heap.h
list_remove
static void list_remove(grpc_timer *timer)
Definition: timer_generic.cc:300
GRPC_TIMERS_NOT_CHECKED
@ GRPC_TIMERS_NOT_CHECKED
Definition: iomgr/timer.h:56
g_num_shards
static size_t g_num_shards
Definition: timer_generic.cc:76
grpc_timer_vtable
Definition: iomgr/timer.h:61
REMOVE_FROM_HASH_TABLE
#define REMOVE_FROM_HASH_TABLE(t)
Definition: timer_generic.cc:201
grpc_time_averaged_stats_init
void grpc_time_averaged_stats_init(grpc_time_averaged_stats *stats, double init_avg, double regress_weight, double persistence_factor)
Definition: iomgr/time_averaged_stats.cc:23
grpc_core::Timestamp
Definition: src/core/lib/gprpp/time.h:62
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
useful.h
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
INVALID_HEAP_INDEX
#define INVALID_HEAP_INDEX
Definition: timer_generic.cc:43
init_timer_ht
static void init_timer_ht()
Definition: timer_generic.cc:96
pop_timers
static size_t pop_timers(timer_shard *shard, grpc_core::Timestamp now, grpc_core::Timestamp *new_min_deadline, grpc_error_handle error)
Definition: timer_generic.cc:548
timer_shard::list
grpc_timer list
Definition: timer_generic.cc:74
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
g_shard_queue
static timer_shard ** g_shard_queue
Definition: timer_generic.cc:85
timer_consume_kick
static void timer_consume_kick(void)
Definition: timer_generic.cc:433
validate_non_pending_timer
static void validate_non_pending_timer(grpc_timer *t)
Definition: timer_generic.cc:185
timer_init
static void timer_init(grpc_timer *timer, grpc_core::Timestamp deadline, grpc_closure *closure)
Definition: timer_generic.cc:332
remove_from_ht
static void remove_from_ht(grpc_timer *t)
Definition: timer_generic.cc:147
timer_shard::mu
gpr_mu mu
Definition: timer_generic.cc:62
GPR_CACHELINE_SIZE
#define GPR_CACHELINE_SIZE
Definition: impl/codegen/port_platform.h:542
xds_manager.p
p
Definition: xds_manager.py:60
GRPC_ERROR_CANCELLED
#define GRPC_ERROR_CANCELLED
Definition: error.h:238
GPR_THREAD_LOCAL
static GPR_THREAD_LOCAL(int64_t) g_last_seen_min_timer
grpc_timer
Definition: iomgr/timer.h:33
grpc_time_averaged_stats
Definition: iomgr/time_averaged_stats.h:27
GRPC_TRACE_FLAG_ENABLED
#define GRPC_TRACE_FLAG_ENABLED(f)
Definition: debug/trace.h:114
grpc_timer_init_unset
void grpc_timer_init_unset(grpc_timer *timer)
Definition: timer_generic.cc:330
ADD_TO_HASH_TABLE
#define ADD_TO_HASH_TABLE(t)
Definition: timer_generic.cc:200
add_to_ht
static void add_to_ht(grpc_timer *t)
Definition: timer_generic.cc:121
gpr_zalloc
GPRAPI void * gpr_zalloc(size_t size)
Definition: alloc.cc:40
GRPC_TIMERS_FIRED
@ GRPC_TIMERS_FIRED
Definition: iomgr/timer.h:58
grpc_timer_heap_destroy
void grpc_timer_heap_destroy(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:95
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
gpr_mu_destroy
GPRAPI void gpr_mu_destroy(gpr_mu *mu)
timer_cancel
static void timer_cancel(grpc_timer *timer)
Definition: timer_generic.cc:438
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
timer_check
static grpc_timer_check_result timer_check(grpc_core::Timestamp *next)
Definition: timer_generic.cc:668
c
void c(T a)
Definition: miscompile_with_no_unique_address_test.cc:40
grpc_timer_heap_add
bool grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer)
Definition: iomgr/timer_heap.cc:97
timer_shard::shard_queue_index
uint32_t shard_queue_index
Definition: timer_generic.cc:69
shared_mutables::min_timer
grpc_core::Timestamp min_timer
Definition: timer_generic.cc:222
ADD_DEADLINE_SCALE
#define ADD_DEADLINE_SCALE
Definition: timer_generic.cc:45
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
grpc_timer::deadline
int64_t deadline
Definition: iomgr/timer.h:34
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
grpc_time_averaged_stats_add_sample
void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats *stats, double value)
Definition: iomgr/time_averaged_stats.cc:35
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
grpc_timer::prev
struct grpc_timer * prev
Definition: iomgr/timer.h:39
MAX_QUEUE_WINDOW_DURATION
#define MAX_QUEUE_WINDOW_DURATION
Definition: timer_generic.cc:47
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
gpr_mu_init
GPRAPI void gpr_mu_init(gpr_mu *mu)
DESTROY_TIMER_HASH_TABLE
#define DESTROY_TIMER_HASH_TABLE()
Definition: timer_generic.cc:199
closure
grpc_closure closure
Definition: src/core/lib/surface/server.cc:466
grpc_core::Timestamp::milliseconds_after_process_epoch
uint64_t milliseconds_after_process_epoch() const
Definition: src/core/lib/gprpp/time.h:109
grpc_timer_check_trace
grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check")
grpc_kick_poller
void grpc_kick_poller(void)
Definition: iomgr/timer_manager.cc:354
grpc_time_averaged_stats_update_average
double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats *stats)
Definition: iomgr/time_averaged_stats.cc:41
min_timer
grpc_core::Timestamp min_timer
Definition: timer_generic.cc:220
shared_mutables::initialized
bool initialized
Definition: timer_generic.cc:225
cpu.h
gpr_spinlock_unlock
#define gpr_spinlock_unlock(lock)
Definition: src/core/lib/gpr/spinlock.h:41
grpc_timer_heap_init
void grpc_timer_heap_init(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:91
time.h
gpr_mu_lock
GPRAPI void gpr_mu_lock(gpr_mu *mu)
grpc_core::HashPointer
constexpr size_t HashPointer(T *p, size_t range)
Definition: useful.h:102
GPR_ALIGN_STRUCT
struct shared_mutables GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE)
shared_mutables::checker_mu
gpr_spinlock checker_mu
Definition: timer_generic.cc:224
g_timer_ht
static grpc_timer * g_timer_ht[NUM_HASH_BUCKETS]
Definition: timer_generic.cc:94
grpc_core::Duration::Epsilon
static constexpr Duration Epsilon()
Definition: src/core/lib/gprpp/time.h:133
GRPC_TIMERS_CHECKED_AND_EMPTY
@ GRPC_TIMERS_CHECKED_AND_EMPTY
Definition: iomgr/timer.h:57
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
min
#define min(a, b)
Definition: qsort.h:83
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
INIT_TIMER_HASH_TABLE
#define INIT_TIMER_HASH_TABLE()
Definition: timer_generic.cc:198
grpc_timer_heap_is_empty
bool grpc_timer_heap_is_empty(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:124
g_shared_mutables
static struct shared_mutables g_shared_mutables
Definition: timer_generic.cc:230
VALIDATE_NON_PENDING_TIMER
#define VALIDATE_NON_PENDING_TIMER(t)
Definition: timer_generic.cc:202
timer_list_init
static void timer_list_init()
Definition: timer_generic.cc:243
timer_shard::min_deadline
grpc_core::Timestamp min_deadline
Definition: timer_generic.cc:67
GRPC_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch
static constexpr Timestamp FromMillisecondsAfterProcessEpoch(int64_t millis)
Definition: src/core/lib/gprpp/time.h:73
grpc_core::TraceFlag
Definition: debug/trace.h:63
gpr_spinlock_trylock
#define gpr_spinlock_trylock(lock)
Definition: src/core/lib/gpr/spinlock.h:40
gpr_atm
intptr_t gpr_atm
Definition: impl/codegen/atm_gcc_atomic.h:32
time_averaged_stats.h
NUM_HASH_BUCKETS
#define NUM_HASH_BUCKETS
Definition: timer_generic.cc:91
swap_adjacent_shards_in_queue
static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index)
Definition: timer_generic.cc:305
grpc_timer_heap_pop
void grpc_timer_heap_pop(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:132
grpc_core::Clamp
T Clamp(T val, T min, T max)
Definition: useful.h:31
GRPC_ERROR_REF
#define GRPC_ERROR_REF(err)
Definition: error.h:261
grpc_timer_heap_top
grpc_timer * grpc_timer_heap_top(grpc_timer_heap *heap)
Definition: iomgr/timer_heap.cc:128
g_hash_mu
static gpr_mu g_hash_mu[NUM_HASH_BUCKETS]
Definition: timer_generic.cc:93
gpr_mu
pthread_mutex_t gpr_mu
Definition: impl/codegen/sync_posix.h:47
grpc_timer_trace
grpc_core::TraceFlag grpc_timer_trace(false, "timer")
port.h
grpc_timer::hash_table_next
struct grpc_timer * hash_table_next
Definition: iomgr/timer.h:42
grpc_timer_check_result
grpc_timer_check_result
Definition: iomgr/timer.h:55
alloc.h
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
fix_build_deps.r
r
Definition: fix_build_deps.py:491
grpc_timer_heap
Definition: iomgr/timer_heap.h:26
is_in_ht
static bool is_in_ht(grpc_timer *t)
Definition: timer_generic.cc:108
destroy_timer_ht
static void destroy_timer_ht()
Definition: timer_generic.cc:102
list_join
static void list_join(grpc_timer *head, grpc_timer *timer)
Definition: timer_generic.cc:294
run_some_expired_timers
static grpc_timer_check_result run_some_expired_timers(grpc_core::Timestamp now, grpc_core::Timestamp *next, grpc_error_handle error)
Definition: timer_generic.cc:569
pop_one
static grpc_timer * pop_one(timer_shard *shard, grpc_core::Timestamp now)
Definition: timer_generic.cc:514
exec_ctx.h
grpc_generic_timer_vtable
grpc_timer_vtable grpc_generic_timer_vtable
Definition: timer_generic.cc:735
closure
Definition: proxy.cc:59
tls.h
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
grpc_core::ExecCtx::Run
static void Run(const DebugLocation &location, grpc_closure *closure, grpc_error_handle error)
Definition: exec_ctx.cc:98
timer.h
timer_list_shutdown
static void timer_list_shutdown()
Definition: timer_generic.cc:275
MIN_QUEUE_WINDOW_DURATION
#define MIN_QUEUE_WINDOW_DURATION
Definition: timer_generic.cc:46
spinlock.h
timer_shard::queue_deadline_cap
grpc_core::Timestamp queue_deadline_cap
Definition: timer_generic.cc:65
note_deadline_change
static void note_deadline_change(timer_shard *shard)
Definition: timer_generic.cc:317
grpc_core::Timestamp::InfFuture
static constexpr Timestamp InfFuture()
Definition: src/core/lib/gprpp/time.h:79
grpc_core::ExecCtx::Now
Timestamp Now()
Definition: exec_ctx.cc:90
grpc_error
Definition: error_internal.h:42
timer_shard::stats
grpc_time_averaged_stats stats
Definition: timer_generic.cc:63
timer_shard::heap
grpc_timer_heap heap
Definition: timer_generic.cc:72
sync.h
grpc_closure
Definition: closure.h:56
refill_heap
static bool refill_heap(timer_shard *shard, grpc_core::Timestamp now)
Definition: timer_generic.cc:473
grpc_core::ExecCtx::Get
static ExecCtx * Get()
Definition: exec_ctx.h:205
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
g_shards
static timer_shard * g_shards
Definition: timer_generic.cc:80
timer
static uv_timer_t timer
Definition: test-callback-stack.c:34
port_platform.h
shared_mutables::mu
gpr_mu mu
Definition: timer_generic.cc:227


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