FD.io VPP  v16.06
Vector Packet Processing
timing_wheel.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vppinfra/bitmap.h>
16 #include <vppinfra/hash.h>
17 #include <vppinfra/pool.h>
18 #include <vppinfra/timing_wheel.h>
19 
20 void
21 timing_wheel_init (timing_wheel_t * w, u64 current_cpu_time, f64 cpu_clocks_per_second)
22 {
23  if (w->max_sched_time <= w->min_sched_time)
24  {
25  w->min_sched_time = 1e-6;
26  w->max_sched_time = 1e-3;
27  }
28 
29  w->cpu_clocks_per_second = cpu_clocks_per_second;
36 
37  w->current_time_index = current_cpu_time >> w->log2_clocks_per_bin;
38 
39  if (w->n_wheel_elt_time_bits <= 0 ||
40  w->n_wheel_elt_time_bits >= STRUCT_BITS_OF (timing_wheel_elt_t, cpu_time_relative_to_base))
41  w->n_wheel_elt_time_bits = STRUCT_BITS_OF (timing_wheel_elt_t, cpu_time_relative_to_base) - 1;
42 
43  w->cpu_time_base = current_cpu_time;
46 }
47 
49 get_level_and_relative_time (timing_wheel_t * w, u64 cpu_time, uword * rtime_result)
50 {
51  u64 dt, rtime;
52  uword level_index;
53 
54  dt = (cpu_time >> w->log2_clocks_per_bin);
55 
56  /* Time should always move forward. */
57  ASSERT (dt >= w->current_time_index);
58 
59  dt -= w->current_time_index;
60 
61  /* Find level and offset within level. Level i has bins of size 2^((i+1)*M) */
62  rtime = dt;
63  for (level_index = 0; (rtime >> w->log2_bins_per_wheel) != 0; level_index++)
64  rtime = (rtime >> w->log2_bins_per_wheel) - 1;
65 
66  /* Return offset within level and level index. */
67  ASSERT (rtime < w->bins_per_wheel);
68  *rtime_result = rtime;
69  return level_index;
70 }
71 
74 { return (ti >> (level_index * w->log2_bins_per_wheel)) & w->bins_per_wheel_mask; }
75 
76 /* Find current time on this level. */
79 { return time_index_to_wheel_index (w, level_index, w->current_time_index); }
80 
81 /* Circular wheel indexing. */
84 { return x & w->bins_per_wheel_mask; }
85 
88 {
89  uword t = current_time_wheel_index (w, level_index);
90  return wheel_add (w, t + rtime);
91 }
92 
93 static clib_error_t *
94 validate_level (timing_wheel_t * w, uword level_index, uword * n_elts)
95 {
96  timing_wheel_level_t * level;
98  uword wi;
99  clib_error_t * error = 0;
100 
101 #define _(x) \
102  do { \
103  error = CLIB_ERROR_ASSERT (x); \
104  ASSERT (! error); \
105  if (error) return error; \
106  } while (0)
107 
108  level = vec_elt_at_index (w->levels, level_index);
109  for (wi = 0; wi < vec_len (level->elts); wi++)
110  {
111  /* Validate occupancy bitmap. */
112  _ (clib_bitmap_get_no_check (level->occupancy_bitmap, wi) == (vec_len (level->elts[wi]) > 0));
113 
114  *n_elts += vec_len (level->elts[wi]);
115 
116  vec_foreach (e, level->elts[wi])
117  {
118  /* Validate time bin and level. */
119  u64 e_time;
120  uword e_ti, e_li, e_wi;
121 
122  e_time = e->cpu_time_relative_to_base + w->cpu_time_base;
123  e_li = get_level_and_relative_time (w, e_time, &e_ti);
124  e_wi = rtime_to_wheel_index (w, level_index, e_ti);
125 
126  if (e_li == level_index - 1)
127  /* If this element was scheduled on the previous level
128  it must be wrapped. */
129  _ (e_ti + current_time_wheel_index (w, level_index - 1)
130  >= w->bins_per_wheel);
131  else
132  {
133  _ (e_li == level_index);
134  if (e_li == 0)
135  _ (e_wi == wi);
136  else
137  _ (e_wi == wi || e_wi + 1 == wi || e_wi - 1 == wi);
138  }
139  }
140  }
141 
142 #undef _
143 
144  return error;
145 }
146 
148 {
149  uword l;
150  clib_error_t * error = 0;
151  uword n_elts;
152 
153  if (! w->validate)
154  return;
155 
156  n_elts = pool_elts (w->overflow_pool);
157  for (l = 0; l < vec_len (w->levels); l++)
158  {
159  error = validate_level (w, l, &n_elts);
160  if (error)
161  clib_error_report (error);
162  }
163 }
164 
165 always_inline void
167 {
168  /* Poison free elements so we never use them by mistake. */
169  if (CLIB_DEBUG > 0)
170  memset (ev, ~0, vec_len (ev) * sizeof (ev[0]));
171  _vec_len (ev) = 0;
172  vec_add1 (w->free_elt_vectors, ev);
173 }
174 
175 static timing_wheel_elt_t *
177  uword level_index,
178  uword rtime)
179 {
180  timing_wheel_level_t * level;
181  timing_wheel_elt_t * e;
182  uword wheel_index;
183 
184  /* Circular buffer. */
185  vec_validate (w->levels, level_index);
186  level = vec_elt_at_index (w->levels, level_index);
187 
188  if (PREDICT_FALSE (! level->elts))
189  {
190  uword max = w->bins_per_wheel - 1;
192  vec_validate (level->elts, max);
193  }
194 
195  wheel_index = rtime_to_wheel_index (w, level_index, rtime);
196 
197  level->occupancy_bitmap = clib_bitmap_ori (level->occupancy_bitmap, wheel_index);
198 
199  /* Allocate an elt vector from free list if there is one. */
200  if (! level->elts[wheel_index] && vec_len (w->free_elt_vectors))
201  level->elts[wheel_index] = vec_pop (w->free_elt_vectors);
202 
203  /* Add element to vector for this time bin. */
204  vec_add2 (level->elts[wheel_index], e, 1);
205 
206  return e;
207 }
208 
209 /* Insert user data on wheel at given CPU time stamp. */
210 static void timing_wheel_insert_helper (timing_wheel_t * w, u64 insert_cpu_time, u32 user_data)
211 {
212  timing_wheel_elt_t * e;
213  u64 dt;
214  uword rtime, level_index;
215 
216  level_index = get_level_and_relative_time (w, insert_cpu_time, &rtime);
217 
218  dt = insert_cpu_time - w->cpu_time_base;
219  if (PREDICT_TRUE (0 == (dt >> BITS (e->cpu_time_relative_to_base))))
220  {
221  e = insert_helper (w, level_index, rtime);
222  e->user_data = user_data;
224  }
225  else
226  {
227  /* Time too far in the future: add to overflow vector. */
229  pool_get (w->overflow_pool, oe);
230  oe->user_data = user_data;
231  oe->cpu_time = insert_cpu_time;
232  }
233 }
234 
237 {
238  return (hash_elts (w->deleted_user_data_hash) > 0
239  && hash_get (w->deleted_user_data_hash, user_data));
240 }
241 
242 static timing_wheel_elt_t *
244 {
245  uword found_match;
246  timing_wheel_elt_t * e, * new_elts;
247 
248  /* Quickly scan to see if there are any elements to delete
249  in this bucket. */
250  found_match = 0;
251  vec_foreach (e, elts)
252  {
253  found_match = e->user_data == user_data;
254  if (found_match)
255  break;
256  }
257  if (! found_match)
258  return elts;
259 
260  /* Re-scan to build vector of new elts with matching user_data deleted. */
261  new_elts = 0;
262  vec_foreach (e, elts)
263  {
264  if (e->user_data != user_data)
265  vec_add1 (new_elts, e[0]);
266  }
267 
268  vec_free (elts);
269  return new_elts;
270 }
271 
272 /* Insert user data on wheel at given CPU time stamp. */
273 void timing_wheel_insert (timing_wheel_t * w, u64 insert_cpu_time, u32 user_data)
274 {
275  /* Remove previously deleted elements. */
276  if (elt_is_deleted (w, user_data))
277  {
279  uword wi;
280 
281  /* Delete elts with given user data so that stale events don't expire. */
282  vec_foreach (l, w->levels)
283  {
285  l->elts[wi] = delete_user_data (l->elts[wi], user_data);
286  if (vec_len (l->elts[wi]) == 0)
287  l->occupancy_bitmap = clib_bitmap_andnoti (l->occupancy_bitmap, wi);
288  }));
289  }
290 
291  {
293  pool_foreach (oe, w->overflow_pool, ({
294  if (oe->user_data == user_data)
295  pool_put (w->overflow_pool, oe);
296  }));
297  }
298 
299  hash_unset (w->deleted_user_data_hash, user_data);
300  }
301 
302  timing_wheel_insert_helper (w, insert_cpu_time, user_data);
303 }
304 
306 {
307  if (! w->deleted_user_data_hash)
308  w->deleted_user_data_hash = hash_create (/* capacity */ 0, /* value bytes */ 0);
309 
310  hash_set1 (w->deleted_user_data_hash, user_data);
311 }
312 
313 /* Returns time of next expiring element. */
315 {
317  timing_wheel_elt_t * e;
318  uword li, wi, wi0;
319  u32 min_dt;
320  u64 min_t;
321  uword wrapped = 0;
322 
323  min_dt = ~0;
324  min_t = ~0ULL;
325  vec_foreach (l, w->levels)
326  {
327  if (! l->occupancy_bitmap)
328  continue;
329 
330  li = l - w->levels;
331  wi0 = wi = current_time_wheel_index (w, li);
332  wrapped = 0;
333  while (1)
334  {
336  {
337  vec_foreach (e, l->elts[wi])
338  min_dt = clib_min (min_dt, e->cpu_time_relative_to_base);
339 
340  if (wrapped && li + 1 < vec_len (w->levels))
341  {
342  uword wi1 = current_time_wheel_index (w, li + 1);
343  if (l[1].occupancy_bitmap && clib_bitmap_get_no_check (l[1].occupancy_bitmap, wi1))
344  {
345  vec_foreach (e, l[1].elts[wi1]) {
346  min_dt = clib_min (min_dt, e->cpu_time_relative_to_base);
347  }
348  }
349  }
350 
351  min_t = w->cpu_time_base + min_dt;
352  goto done;
353  }
354 
355  wi = wheel_add (w, wi + 1);
356  if (wi == wi0)
357  break;
358 
359  wrapped = wi != wi + 1;
360  }
361  }
362 
363  {
365 
366  if (min_dt != ~0)
367  min_t = w->cpu_time_base + min_dt;
368 
369  pool_foreach (oe, w->overflow_pool,
370  ({ min_t = clib_min (min_t, oe->cpu_time); }));
371 
372  done:
373  return min_t;
374  }
375 }
376 
377 static inline void
379 {
382 }
383 
386 { return w->cpu_time_base + e->cpu_time_relative_to_base; }
387 
388 always_inline void
390  u64 current_cpu_time)
391 {
392  if (CLIB_DEBUG > 0)
393  {
394  u64 e_time = elt_cpu_time (w, e);
395 
396  /* Verify that element is actually expired. */
397  ASSERT ((e_time >> w->log2_clocks_per_bin)
398  <= (current_cpu_time >> w->log2_clocks_per_bin));
399  }
400 }
401 
402 static u32 *
404  uword level_index,
405  uword wheel_index,
406  u64 advance_cpu_time,
407  u32 * expired_user_data)
408 {
409  timing_wheel_level_t * level = vec_elt_at_index (w->levels, level_index);
410  timing_wheel_elt_t * e;
411  u32 * x;
412  uword i, j, e_len;
413 
414  e = vec_elt (level->elts, wheel_index);
415  e_len = vec_len (e);
416 
417  vec_add2 (expired_user_data, x, e_len);
418  for (i = j = 0; i < e_len; i++)
419  {
420  validate_expired_elt (w, &e[i], advance_cpu_time);
421  x[j] = e[i].user_data;
422 
423  /* Only advance if elt is not to be deleted. */
424  j += ! elt_is_deleted (w, e[i].user_data);
425  }
426 
427  /* Adjust for deleted elts. */
428  if (j < e_len)
429  _vec_len (expired_user_data) -= e_len - j;
430 
431  free_elt_vector (w, e);
432 
433  level->elts[wheel_index] = 0;
434  clib_bitmap_set_no_check (level->occupancy_bitmap, wheel_index, 0);
435 
436  return expired_user_data;
437 }
438 
439 /* Called rarely. 32 bit times should only overflow every 4 seconds or so on a fast machine. */
440 static void
441 advance_cpu_time_base (timing_wheel_t * w, u32 * expired_user_data)
442 {
444  timing_wheel_elt_t * e;
445  u64 delta;
446 
448  delta = ((u64) 1 << w->n_wheel_elt_time_bits);
449  w->cpu_time_base += delta;
451 
452  vec_foreach (l, w->levels)
453  {
454  uword wi;
456  vec_foreach (e, l->elts[wi])
457  {
458  /* This should always be true since otherwise we would have already expired
459  this element. */
460  ASSERT (e->cpu_time_relative_to_base >= delta);
461  e->cpu_time_relative_to_base -= delta;
462  }
463  }));
464  }
465 
466  /* See which overflow elements fit now. */
467  {
469  pool_foreach (oe, w->overflow_pool, ({
470  /* It fits now into 32 bits. */
471  if (0 == ((oe->cpu_time - w->cpu_time_base) >> BITS (e->cpu_time_relative_to_base)))
472  {
473  u64 ti = oe->cpu_time >> w->log2_clocks_per_bin;
474  if (ti < w->current_time_index)
475  {
476  /* This can happen when timing wheel is not advanced for a long time
477  (for example when at a gdb breakpoint for a while). */
478  if (! elt_is_deleted (w, oe->user_data))
479  vec_add1 (expired_user_data, oe->user_data);
480  }
481  else
482  timing_wheel_insert_helper (w, oe->cpu_time, oe->user_data);
483  pool_put (w->overflow_pool, oe);
484  }
485  }));
486  }
487 }
488 
489 static u32 *
491  uword level_index,
492  u64 advance_cpu_time,
493  uword from_wheel_index,
494  uword to_wheel_index,
495  u32 * expired_user_data)
496 {
497  timing_wheel_level_t * level;
499  u64 advance_time_index = advance_cpu_time >> w->log2_clocks_per_bin;
500 
501  vec_validate (w->stats.refills, level_index);
502  w->stats.refills[level_index] += 1;
503 
504  if (level_index + 1 >= vec_len (w->levels))
505  goto done;
506 
507  level = vec_elt_at_index (w->levels, level_index + 1);
508  if (! level->occupancy_bitmap)
509  goto done;
510 
511  while (1)
512  {
513  timing_wheel_elt_t * e, * es;
514 
515  if (clib_bitmap_get_no_check (level->occupancy_bitmap, from_wheel_index))
516  {
517  es = level->elts[from_wheel_index];
518  level->elts[from_wheel_index] = 0;
519  clib_bitmap_set_no_check (level->occupancy_bitmap, from_wheel_index, 0);
520 
521  vec_foreach (e, es)
522  {
523  u64 e_time = elt_cpu_time (w, e);
524  u64 ti = e_time >> w->log2_clocks_per_bin;
525  if (ti <= advance_time_index)
526  {
527  validate_expired_elt (w, e, advance_cpu_time);
528  if (! elt_is_deleted (w, e->user_data))
529  vec_add1 (expired_user_data, e->user_data);
530  }
531  else
532  vec_add1 (to_insert, e[0]);
533  }
534  free_elt_vector (w, es);
535  }
536 
537  if (from_wheel_index == to_wheel_index)
538  break;
539 
540  from_wheel_index = wheel_add (w, from_wheel_index + 1);
541  }
542 
544  done:
545  w->unexpired_elts_pending_insert = to_insert;
546  return expired_user_data;
547 }
548 
549 /* Advance wheel and return any expired user data in vector. */
550 u32 *
551 timing_wheel_advance (timing_wheel_t * w, u64 advance_cpu_time, u32 * expired_user_data,
552  u64 * next_expiring_element_cpu_time)
553 {
554  timing_wheel_level_t * level;
555  uword level_index, advance_rtime, advance_level_index, advance_wheel_index;
556  uword n_expired_user_data_before;
557  u64 current_time_index, advance_time_index;
558 
559  n_expired_user_data_before = vec_len (expired_user_data);
560 
561  /* Re-fill lower levels when time wraps. */
562  current_time_index = w->current_time_index;
563  advance_time_index = advance_cpu_time >> w->log2_clocks_per_bin;
564 
565  {
566  u64 current_ti, advance_ti;
567 
568  current_ti = current_time_index >> w->log2_bins_per_wheel;
569  advance_ti = advance_time_index >> w->log2_bins_per_wheel;
570 
571  if (PREDICT_FALSE (current_ti != advance_ti))
572  {
574  _vec_len (w->unexpired_elts_pending_insert) = 0;
575 
576  level_index = 0;
577  while (current_ti != advance_ti)
578  {
579  uword c, a;
580  c = current_ti & (w->bins_per_wheel - 1);
581  a = advance_ti & (w->bins_per_wheel - 1);
582  if (c != a)
583  expired_user_data = refill_level (w,
584  level_index,
585  advance_cpu_time,
586  c, a,
587  expired_user_data);
588  current_ti >>= w->log2_bins_per_wheel;
589  advance_ti >>= w->log2_bins_per_wheel;
590  level_index++;
591  }
592  }
593  }
594 
595  advance_level_index = get_level_and_relative_time (w, advance_cpu_time, &advance_rtime);
596  advance_wheel_index = rtime_to_wheel_index (w, advance_level_index, advance_rtime);
597 
598  /* Empty all occupied bins for entire levels that we advance past. */
599  for (level_index = 0; level_index < advance_level_index; level_index++)
600  {
601  uword wi;
602 
603  if (level_index >= vec_len (w->levels))
604  break;
605 
606  level = vec_elt_at_index (w->levels, level_index);
607  clib_bitmap_foreach (wi, level->occupancy_bitmap, ({
608  expired_user_data = expire_bin (w, level_index, wi, advance_cpu_time,
609  expired_user_data);
610  }));
611  }
612 
613  if (PREDICT_TRUE (level_index < vec_len (w->levels)))
614  {
615  uword wi;
616  level = vec_elt_at_index (w->levels, level_index);
617  wi = current_time_wheel_index (w, level_index);
618  if (level->occupancy_bitmap)
619  while (1)
620  {
622  expired_user_data = expire_bin (w, advance_level_index, wi, advance_cpu_time,
623  expired_user_data);
624 
625  if (wi == advance_wheel_index)
626  break;
627 
628  wi = wheel_add (w, wi + 1);
629  }
630  }
631 
632  /* Advance current time index. */
633  w->current_time_index = advance_time_index;
634 
636  {
637  timing_wheel_elt_t * e;
639  insert_elt (w, e);
640  _vec_len (w->unexpired_elts_pending_insert) = 0;
641  }
642 
643  /* Don't advance until necessary. */
644  while (PREDICT_FALSE (advance_time_index >= w->time_index_next_cpu_time_base_update))
645  advance_cpu_time_base (w, expired_user_data);
646 
647  if (next_expiring_element_cpu_time)
648  {
649  u64 min_t;
650 
651  /* Anything expired? If so we need to recompute next expiring elt time. */
652  if (vec_len (expired_user_data) == n_expired_user_data_before
653  && w->cached_min_cpu_time_on_wheel != 0ULL)
654  min_t = w->cached_min_cpu_time_on_wheel;
655  else
656  {
658  w->cached_min_cpu_time_on_wheel = min_t;
659  }
660 
661  *next_expiring_element_cpu_time = min_t;
662  }
663 
664  return expired_user_data;
665 }
666 
667 u8 * format_timing_wheel (u8 * s, va_list * va)
668 {
669  timing_wheel_t * w = va_arg (*va, timing_wheel_t *);
670  int verbose = va_arg (*va, int);
671  uword indent = format_get_indent (s);
672 
673  s = format (s, "level 0: %.4e - %.4e secs, 2^%d - 2^%d clocks",
677 
678  if (verbose)
679  {
680  int l;
681 
682  s = format (s, "\n%Utime base advances %Ld, every %.4e secs",
683  format_white_space, indent + 2,
686 
687  for (l = 0; l < vec_len (w->levels); l++)
688  s = format (s, "\n%Ulevel %d: refills %Ld",
689  format_white_space, indent + 2,
690  l, l < vec_len (w->stats.refills) ? w->stats.refills[l] : (u64) 0);
691  }
692 
693  return s;
694 }
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
timing_wheel_overflow_elt_t * overflow_pool
Definition: timing_wheel.h:80
void timing_wheel_validate(timing_wheel_t *w)
Definition: timing_wheel.c:147
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define clib_min(x, y)
Definition: clib.h:295
static void advance_cpu_time_base(timing_wheel_t *w, u32 *expired_user_data)
Definition: timing_wheel.c:441
always_inline void validate_expired_elt(timing_wheel_t *w, timing_wheel_elt_t *e, u64 current_cpu_time)
Definition: timing_wheel.c:389
#define hash_unset(h, key)
Definition: hash.h:243
a
Definition: bitmap.h:393
#define PREDICT_TRUE(x)
Definition: clib.h:98
#define STRUCT_BITS_OF(t, f)
Definition: clib.h:65
void timing_wheel_init(timing_wheel_t *w, u64 current_cpu_time, f64 cpu_clocks_per_second)
Definition: timing_wheel.c:21
u64 timing_wheel_next_expiring_elt_time(timing_wheel_t *w)
Definition: timing_wheel.c:314
u64 cached_min_cpu_time_on_wheel
Definition: timing_wheel.h:108
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
always_inline uword max_log2(uword x)
Definition: clib.h:216
always_inline uword time_index_to_wheel_index(timing_wheel_t *w, uword level_index, u64 ti)
Definition: timing_wheel.c:73
#define clib_error_report(e)
Definition: error.h:126
void timing_wheel_insert(timing_wheel_t *w, u64 insert_cpu_time, u32 user_data)
Definition: timing_wheel.c:273
#define pool_get(P, E)
Definition: pool.h:186
#define vec_pop(V)
Returns last element of a vector and decrements its length.
Definition: vec.h:574
u64 current_time_index
Definition: timing_wheel.h:95
always_inline void free_elt_vector(timing_wheel_t *w, timing_wheel_elt_t *ev)
Definition: timing_wheel.c:166
static timing_wheel_elt_t * delete_user_data(timing_wheel_elt_t *elts, u32 user_data)
Definition: timing_wheel.c:243
#define clib_bitmap_validate(v, n_bits)
Definition: bitmap.h:91
static timing_wheel_elt_t * insert_helper(timing_wheel_t *w, uword level_index, uword rtime)
Definition: timing_wheel.c:176
#define pool_foreach(VAR, POOL, BODY)
Definition: pool.h:328
#define always_inline
Definition: clib.h:84
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:107
always_inline uword wheel_add(timing_wheel_t *w, word x)
Definition: timing_wheel.c:83
timing_wheel_stats_t stats
Definition: timing_wheel.h:112
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
f64 cpu_clocks_per_second
Definition: timing_wheel.h:110
always_inline uword pool_elts(void *v)
Definition: pool.h:97
unsigned long u64
Definition: types.h:89
static u32 * expire_bin(timing_wheel_t *w, uword level_index, uword wheel_index, u64 advance_cpu_time, u32 *expired_user_data)
Definition: timing_wheel.c:403
#define hash_get(h, key)
Definition: hash.h:231
#define clib_bitmap_foreach(i, ai, body)
Definition: bitmap.h:308
always_inline uword clib_bitmap_set_no_check(uword *a, uword i, uword new_value)
Definition: bitmap.h:112
timing_wheel_elt_t ** free_elt_vectors
Definition: timing_wheel.h:83
always_inline uword get_level_and_relative_time(timing_wheel_t *w, u64 cpu_time, uword *rtime_result)
Definition: timing_wheel.c:49
u8 * format_timing_wheel(u8 *s, va_list *va)
Definition: timing_wheel.c:667
#define PREDICT_FALSE(x)
Definition: clib.h:97
static void timing_wheel_insert_helper(timing_wheel_t *w, u64 insert_cpu_time, u32 user_data)
Definition: timing_wheel.c:210
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
u32 * timing_wheel_advance(timing_wheel_t *w, u64 advance_cpu_time, u32 *expired_user_data, u64 *next_expiring_element_cpu_time)
Definition: timing_wheel.c:551
void timing_wheel_delete(timing_wheel_t *w, u32 user_data)
Definition: timing_wheel.c:305
always_inline uword hash_elts(void *v)
Definition: hash.h:111
always_inline u64 elt_cpu_time(timing_wheel_t *w, timing_wheel_elt_t *e)
Definition: timing_wheel.c:385
timing_wheel_elt_t ** elts
Definition: timing_wheel.h:46
#define hash_set1(h, key)
Definition: hash.h:240
timing_wheel_elt_t * unexpired_elts_pending_insert
Definition: timing_wheel.h:85
#define hash_create(elts, value_bytes)
Definition: hash.h:615
uword * deleted_user_data_hash
Definition: timing_wheel.h:88
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u64 time_index_next_cpu_time_base_update
Definition: timing_wheel.h:105
always_inline uword elt_is_deleted(timing_wheel_t *w, u32 user_data)
Definition: timing_wheel.c:236
timing_wheel_level_t * levels
Definition: timing_wheel.h:78
always_inline uword format_get_indent(u8 *s)
Definition: format.h:72
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
always_inline uword current_time_wheel_index(timing_wheel_t *w, uword level_index)
Definition: timing_wheel.c:78
always_inline uword clib_bitmap_get_no_check(uword *ai, uword i)
Definition: bitmap.h:170
always_inline uword rtime_to_wheel_index(timing_wheel_t *w, uword level_index, uword rtime)
Definition: timing_wheel.c:87
i64 word
Definition: types.h:111
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
u8 n_wheel_elt_time_bits
Definition: timing_wheel.h:70
u32 bins_per_wheel_mask
Definition: timing_wheel.h:76
static u32 * refill_level(timing_wheel_t *w, uword level_index, u64 advance_cpu_time, uword from_wheel_index, uword to_wheel_index, u32 *expired_user_data)
Definition: timing_wheel.c:490
#define vec_foreach(var, vec)
Vector iterator.
static void insert_elt(timing_wheel_t *w, timing_wheel_elt_t *e)
Definition: timing_wheel.c:378
u8 log2_clocks_per_wheel
Definition: timing_wheel.h:66
#define BITS(x)
Definition: clib.h:58
static clib_error_t * validate_level(timing_wheel_t *w, uword level_index, uword *n_elts)
Definition: timing_wheel.c:94