blob: ec0baa07faddd6364686e2bbd974f214c17259ee [file] [log] [blame]
Dave Barach8e8f98c2017-02-03 11:58:53 -05001#include <vppinfra/time.h>
2#include <vppinfra/cache.h>
3#include <vppinfra/error.h>
4#include <vppinfra/tw_timer_2t_1w_2048sl.h>
5#include <vppinfra/tw_timer_16t_2w_512sl.h>
Dave Barach4af9ba12017-06-07 15:18:23 -04006#include <vppinfra/tw_timer_4t_3w_256sl.h>
7#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
Dave Barach8e8f98c2017-02-03 11:58:53 -05008
9typedef struct
10{
11 /** Handle returned from tw_start_timer */
12 u32 stop_timer_handle;
13
14 /** Test item should expire at this clock tick */
Dave Barach4af9ba12017-06-07 15:18:23 -040015 u64 expected_to_expire;
Dave Barach8e8f98c2017-02-03 11:58:53 -050016} tw_timer_test_elt_t;
17
18typedef struct
19{
20 /** Pool of test objects */
21 tw_timer_test_elt_t *test_elts;
22
23 /** The single-wheel */
24 tw_timer_wheel_2t_1w_2048sl_t single_wheel;
25
26 /** The double-wheel */
27 tw_timer_wheel_16t_2w_512sl_t double_wheel;
28
Dave Barach4af9ba12017-06-07 15:18:23 -040029 /* The triple wheel */
30 tw_timer_wheel_4t_3w_256sl_t triple_wheel;
31
32 /* The triple wheel with overflow vector */
33 tw_timer_wheel_1t_3w_1024sl_ov_t triple_ov_wheel;
34
Dave Barach8e8f98c2017-02-03 11:58:53 -050035 /** random number seed */
Dave Barach4af9ba12017-06-07 15:18:23 -040036 u64 seed;
Dave Barach8e8f98c2017-02-03 11:58:53 -050037
38 /** number of timers */
39 u32 ntimers;
40
41 /** number of "churn" iterations */
42 u32 niter;
43
44 /** number of clock ticks per churn iteration */
45 u32 ticks_per_iter;
46
47 /** cpu timer */
48 clib_time_t clib_time;
49} tw_timer_test_main_t;
50
51tw_timer_test_main_t tw_timer_test_main;
52
53static void
54run_single_wheel (tw_timer_wheel_2t_1w_2048sl_t * tw, u32 n_ticks)
55{
56 u32 i;
57 f64 now = tw->last_run_time + 1.01;
58
59 for (i = 0; i < n_ticks; i++)
60 {
61 tw_timer_expire_timers_2t_1w_2048sl (tw, now);
62 now += 1.01;
63 }
64}
65
66static void
67run_double_wheel (tw_timer_wheel_16t_2w_512sl_t * tw, u32 n_ticks)
68{
69 u32 i;
70 f64 now = tw->last_run_time + 1.01;
71
72 for (i = 0; i < n_ticks; i++)
73 {
74 tw_timer_expire_timers_16t_2w_512sl (tw, now);
75 now += 1.01;
76 }
77}
78
79static void
Dave Barach4af9ba12017-06-07 15:18:23 -040080run_triple_wheel (tw_timer_wheel_4t_3w_256sl_t * tw, u32 n_ticks)
81{
82 u32 i;
83 f64 now = tw->last_run_time + 1.01;
84
85 for (i = 0; i < n_ticks; i++)
86 {
87 tw_timer_expire_timers_4t_3w_256sl (tw, now);
88 now += 1.01;
89 }
90}
91
92static void
93run_triple_ov_wheel (tw_timer_wheel_1t_3w_1024sl_ov_t * tw, u32 n_ticks)
94{
95 u32 i;
96 f64 now = tw->last_run_time + 1.01;
97
98 for (i = 0; i < n_ticks; i++)
99 {
100 tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
101 now += 1.01;
102 }
103}
104
105static void
Dave Barach8e8f98c2017-02-03 11:58:53 -0500106expired_timer_single_callback (u32 * expired_timers)
107{
108 int i;
109 u32 pool_index, timer_id;
110 tw_timer_test_elt_t *e;
111 tw_timer_test_main_t *tm = &tw_timer_test_main;
112
113 for (i = 0; i < vec_len (expired_timers); i++)
114 {
115 pool_index = expired_timers[i] & 0x7FFFFFFF;
116 timer_id = expired_timers[i] >> 31;
117
118 ASSERT (timer_id == 1);
119
120 e = pool_elt_at_index (tm->test_elts, pool_index);
121
122 if (e->expected_to_expire != tm->single_wheel.current_tick)
123 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400124 fformat (stdout, "[%d] expired at %lld not %lld\n",
Dave Barach8e8f98c2017-02-03 11:58:53 -0500125 e - tm->test_elts, tm->single_wheel.current_tick,
126 e->expected_to_expire);
127 }
128 pool_put (tm->test_elts, e);
129 }
130}
131
132static void
133expired_timer_double_callback (u32 * expired_timers)
134{
135 int i;
136 u32 pool_index, timer_id;
137 tw_timer_test_elt_t *e;
138 tw_timer_test_main_t *tm = &tw_timer_test_main;
139
140 for (i = 0; i < vec_len (expired_timers); i++)
141 {
142 pool_index = expired_timers[i] & 0x0FFFFFFF;
143 timer_id = expired_timers[i] >> 28;
144
145 ASSERT (timer_id == 14);
146
147 e = pool_elt_at_index (tm->test_elts, pool_index);
148
149 if (e->expected_to_expire != tm->double_wheel.current_tick)
150 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400151 fformat (stdout, "[%d] expired at %lld not %lld\n",
Dave Barach8e8f98c2017-02-03 11:58:53 -0500152 e - tm->test_elts, tm->double_wheel.current_tick,
153 e->expected_to_expire);
154 }
155 pool_put (tm->test_elts, e);
156 }
157}
158
Dave Barach4af9ba12017-06-07 15:18:23 -0400159static void
160expired_timer_triple_callback (u32 * expired_timers)
161{
162 int i;
163 u32 pool_index, timer_id;
164 tw_timer_test_elt_t *e;
165 tw_timer_test_main_t *tm = &tw_timer_test_main;
166
167 for (i = 0; i < vec_len (expired_timers); i++)
168 {
169 pool_index = expired_timers[i] & 0x3FFFFFFF;
170 timer_id = expired_timers[i] >> 30;
171
172 ASSERT (timer_id == 3);
173
174 e = pool_elt_at_index (tm->test_elts, pool_index);
175
176 if (e->expected_to_expire != tm->triple_wheel.current_tick)
177 {
178 fformat (stdout, "[%d] expired at %lld not %lld\n",
179 e - tm->test_elts, tm->triple_wheel.current_tick,
180 e->expected_to_expire);
181 }
182 pool_put (tm->test_elts, e);
183 }
184}
185
186static void
187expired_timer_triple_ov_callback (u32 * expired_timers)
188{
189 int i;
190 u32 pool_index;
191 tw_timer_test_elt_t *e;
192 tw_timer_test_main_t *tm = &tw_timer_test_main;
193
194 for (i = 0; i < vec_len (expired_timers); i++)
195 {
196 pool_index = expired_timers[i];
197
198 e = pool_elt_at_index (tm->test_elts, pool_index);
199
200 if (e->expected_to_expire != tm->triple_ov_wheel.current_tick)
201 {
202 fformat (stdout, "[%d] expired at %lld not %lld\n",
203 e - tm->test_elts, tm->triple_ov_wheel.current_tick,
204 e->expected_to_expire);
205 }
206 pool_put (tm->test_elts, e);
207 }
208}
209
Dave Barach8e8f98c2017-02-03 11:58:53 -0500210static clib_error_t *
211test2_single (tw_timer_test_main_t * tm)
212{
213 u32 i, j;
214 tw_timer_test_elt_t *e;
215 u32 initial_wheel_offset;
Dave Barach4af9ba12017-06-07 15:18:23 -0400216 u64 expiration_time;
Dave Barach8e8f98c2017-02-03 11:58:53 -0500217 u32 max_expiration_time = 0;
218 u32 *deleted_indices = 0;
219 u32 adds = 0, deletes = 0;
220 f64 before, after;
221
222 clib_time_init (&tm->clib_time);
223
224 tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
225 expired_timer_single_callback,
Filip Tehlar816f4372017-04-26 16:09:06 +0200226 1.0 /* timer interval */ , ~0);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500227
228 /* Prime offset */
229 initial_wheel_offset = 757;
230
231 run_single_wheel (&tm->single_wheel, initial_wheel_offset);
232
Dave Barach4af9ba12017-06-07 15:18:23 -0400233 fformat (stdout, "initial wheel time %d, fast index %d\n",
234 tm->single_wheel.current_tick,
235 tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
236
237 initial_wheel_offset = tm->single_wheel.current_tick;
238
239 fformat (stdout,
240 "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
Dave Barach8e8f98c2017-02-03 11:58:53 -0500241 tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
242
243 before = clib_time_now (&tm->clib_time);
244
245 /* Prime the pump */
246 for (i = 0; i < tm->ntimers; i++)
247 {
248 pool_get (tm->test_elts, e);
249 memset (e, 0, sizeof (*e));
250
251 do
252 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400253 expiration_time = random_u64 (&tm->seed) & (2047);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500254 }
255 while (expiration_time == 0);
256
257 if (expiration_time > max_expiration_time)
258 max_expiration_time = expiration_time;
259
260 e->expected_to_expire = expiration_time + initial_wheel_offset;
261 e->stop_timer_handle =
262 tw_timer_start_2t_1w_2048sl (&tm->single_wheel, e - tm->test_elts,
263 1 /* timer id */ ,
264 expiration_time);
265 }
266
267 adds += i;
268
269 for (i = 0; i < tm->niter; i++)
270 {
271 run_single_wheel (&tm->single_wheel, tm->ticks_per_iter);
272
273 j = 0;
274 vec_reset_length (deleted_indices);
275 /* *INDENT-OFF* */
276 pool_foreach (e, tm->test_elts,
277 ({
278 tw_timer_stop_2t_1w_2048sl (&tm->single_wheel, e->stop_timer_handle);
279 vec_add1 (deleted_indices, e - tm->test_elts);
280 if (++j >= tm->ntimers / 4)
281 goto del_and_re_add;
282 }));
283 /* *INDENT-ON* */
284
285 del_and_re_add:
286 for (j = 0; j < vec_len (deleted_indices); j++)
Dave Barach4af9ba12017-06-07 15:18:23 -0400287 {
288 pool_put_index (tm->test_elts, deleted_indices[j]);
289 }
Dave Barach8e8f98c2017-02-03 11:58:53 -0500290
291 deletes += j;
292
293 for (j = 0; j < tm->ntimers / 4; j++)
294 {
295 pool_get (tm->test_elts, e);
296 memset (e, 0, sizeof (*e));
297
298 do
299 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400300 expiration_time = random_u64 (&tm->seed) & (2047);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500301 }
302 while (expiration_time == 0);
303
304 if (expiration_time > max_expiration_time)
305 max_expiration_time = expiration_time;
306
307 e->expected_to_expire =
308 expiration_time + tm->single_wheel.current_tick;
309 e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
310 (&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
311 expiration_time);
312 }
313 adds += j;
314 }
315
316 vec_free (deleted_indices);
317
318 run_single_wheel (&tm->single_wheel, max_expiration_time + 1);
319
320 after = clib_time_now (&tm->clib_time);
321
322 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
323 tm->single_wheel.current_tick);
324 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
325 (after - before),
326 ((f64) adds + (f64) deletes +
327 (f64) tm->single_wheel.current_tick) / (after - before));
328
329 if (pool_elts (tm->test_elts))
330 fformat (stdout, "Note: %d elements remain in pool\n",
331 pool_elts (tm->test_elts));
332
333 /* *INDENT-OFF* */
334 pool_foreach (e, tm->test_elts,
335 ({
336 fformat (stdout, "[%d] expected to expire %d\n",
337 e - tm->test_elts,
338 e->expected_to_expire);
339 }));
340 /* *INDENT-ON* */
341
342 pool_free (tm->test_elts);
343 tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
344 return 0;
345}
346
347static clib_error_t *
348test2_double (tw_timer_test_main_t * tm)
349{
350 u32 i, j;
351 tw_timer_test_elt_t *e;
352 u32 initial_wheel_offset;
353 u32 expiration_time;
354 u32 max_expiration_time = 0;
355 u32 *deleted_indices = 0;
356 u32 adds = 0, deletes = 0;
357 f64 before, after;
358
359 clib_time_init (&tm->clib_time);
360
361 tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
362 expired_timer_double_callback,
Filip Tehlar816f4372017-04-26 16:09:06 +0200363 1.0 /* timer interval */ , ~0);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500364
365 /* Prime offset */
Dave Barach4af9ba12017-06-07 15:18:23 -0400366 initial_wheel_offset = 7577;
Dave Barach8e8f98c2017-02-03 11:58:53 -0500367
368 run_double_wheel (&tm->double_wheel, initial_wheel_offset);
369
Dave Barach4af9ba12017-06-07 15:18:23 -0400370 fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
371 tm->double_wheel.current_tick,
372 tm->double_wheel.current_index[TW_TIMER_RING_FAST],
373 tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
374
375 initial_wheel_offset = tm->double_wheel.current_tick;
376
377 fformat (stdout,
378 "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
Dave Barach8e8f98c2017-02-03 11:58:53 -0500379 tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
380
381 before = clib_time_now (&tm->clib_time);
382
383 /* Prime the pump */
384 for (i = 0; i < tm->ntimers; i++)
385 {
386 pool_get (tm->test_elts, e);
387 memset (e, 0, sizeof (*e));
388
389 do
390 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400391 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500392 }
393 while (expiration_time == 0);
394
395 if (expiration_time > max_expiration_time)
396 max_expiration_time = expiration_time;
397
398 e->expected_to_expire = expiration_time + initial_wheel_offset;
Dave Barach4af9ba12017-06-07 15:18:23 -0400399
Dave Barach8e8f98c2017-02-03 11:58:53 -0500400 e->stop_timer_handle =
401 tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
402 14 /* timer id */ ,
403 expiration_time);
404 }
405
406 adds += i;
407
408 for (i = 0; i < tm->niter; i++)
409 {
410 run_double_wheel (&tm->double_wheel, tm->ticks_per_iter);
411
412 j = 0;
413 vec_reset_length (deleted_indices);
414 /* *INDENT-OFF* */
415 pool_foreach (e, tm->test_elts,
416 ({
417 tw_timer_stop_16t_2w_512sl (&tm->double_wheel, e->stop_timer_handle);
418 vec_add1 (deleted_indices, e - tm->test_elts);
419 if (++j >= tm->ntimers / 4)
420 goto del_and_re_add;
421 }));
422 /* *INDENT-ON* */
423
424 del_and_re_add:
425 for (j = 0; j < vec_len (deleted_indices); j++)
426 pool_put_index (tm->test_elts, deleted_indices[j]);
427
428 deletes += j;
429
430 for (j = 0; j < tm->ntimers / 4; j++)
431 {
432 pool_get (tm->test_elts, e);
433 memset (e, 0, sizeof (*e));
434
435 do
436 {
Dave Barach4af9ba12017-06-07 15:18:23 -0400437 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500438 }
439 while (expiration_time == 0);
440
441 if (expiration_time > max_expiration_time)
442 max_expiration_time = expiration_time;
443
444 e->expected_to_expire = expiration_time +
445 tm->double_wheel.current_tick;
Dave Barach4af9ba12017-06-07 15:18:23 -0400446
Dave Barach8e8f98c2017-02-03 11:58:53 -0500447 e->stop_timer_handle = tw_timer_start_16t_2w_512sl
448 (&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
449 expiration_time);
450 }
451 adds += j;
452 }
453
454 vec_free (deleted_indices);
455
456 run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
457
458 after = clib_time_now (&tm->clib_time);
459
460 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
461 tm->double_wheel.current_tick);
462 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
463 (after - before),
464 ((f64) adds + (f64) deletes +
465 (f64) tm->double_wheel.current_tick) / (after - before));
466
467 if (pool_elts (tm->test_elts))
468 fformat (stdout, "Note: %d elements remain in pool\n",
469 pool_elts (tm->test_elts));
470
471 /* *INDENT-OFF* */
472 pool_foreach (e, tm->test_elts,
473 ({
474 fformat (stdout, "[%d] expected to expire %d\n",
475 e - tm->test_elts,
476 e->expected_to_expire);
477 }));
478 /* *INDENT-ON* */
479
480 pool_free (tm->test_elts);
481 tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
482 return 0;
483}
484
485static clib_error_t *
Dave Barach4af9ba12017-06-07 15:18:23 -0400486test2_triple (tw_timer_test_main_t * tm)
487{
488 u32 i, j;
489 tw_timer_test_elt_t *e;
490 u32 initial_wheel_offset = 0;
491 u32 expiration_time;
492 u32 max_expiration_time = 0;
493 u32 *deleted_indices = 0;
494 u32 adds = 0, deletes = 0;
495 f64 before, after;
496
497 clib_time_init (&tm->clib_time);
498
499 tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
500 expired_timer_triple_callback,
501 1.0 /* timer interval */ , ~0);
502
503
504 /* Prime offset */
505 initial_wheel_offset = 75700;
506 run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
507
508 fformat (stdout,
509 "initial wheel time %d, fi %d si %d gi %d\n",
510 tm->triple_wheel.current_tick,
511 tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
512 tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
513 tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
514
515 initial_wheel_offset = tm->triple_wheel.current_tick;
516
517 fformat (stdout,
518 "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
519 tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
520
521 before = clib_time_now (&tm->clib_time);
522
523 /* Prime the pump */
524 for (i = 0; i < tm->ntimers; i++)
525 {
526 pool_get (tm->test_elts, e);
527 memset (e, 0, sizeof (*e));
528
529 do
530 {
531 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
532 }
533 while (expiration_time == 0);
534
535 if (expiration_time > max_expiration_time)
536 max_expiration_time = expiration_time;
537
538 e->expected_to_expire = expiration_time + initial_wheel_offset;
539
540 e->stop_timer_handle =
541 tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
542 3 /* timer id */ ,
543 expiration_time);
544 }
545
546 adds += i;
547
548 for (i = 0; i < tm->niter; i++)
549 {
550 run_triple_wheel (&tm->triple_wheel, tm->ticks_per_iter);
551
552 j = 0;
553 vec_reset_length (deleted_indices);
554 /* *INDENT-OFF* */
555 pool_foreach (e, tm->test_elts,
556 ({
557 tw_timer_stop_4t_3w_256sl (&tm->triple_wheel, e->stop_timer_handle);
558 vec_add1 (deleted_indices, e - tm->test_elts);
559 if (++j >= tm->ntimers / 4)
560 goto del_and_re_add;
561 }));
562 /* *INDENT-ON* */
563
564 del_and_re_add:
565 for (j = 0; j < vec_len (deleted_indices); j++)
566 pool_put_index (tm->test_elts, deleted_indices[j]);
567
568 deletes += j;
569
570 for (j = 0; j < tm->ntimers / 4; j++)
571 {
572 pool_get (tm->test_elts, e);
573 memset (e, 0, sizeof (*e));
574
575 do
576 {
577 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
578 }
579 while (expiration_time == 0);
580
581 if (expiration_time > max_expiration_time)
582 max_expiration_time = expiration_time;
583
584 e->expected_to_expire = expiration_time +
585 tm->triple_wheel.current_tick;
586
587 e->stop_timer_handle = tw_timer_start_4t_3w_256sl
588 (&tm->triple_wheel, e - tm->test_elts, 3 /* timer id */ ,
589 expiration_time);
590 }
591 adds += j;
592 }
593
594 vec_free (deleted_indices);
595
596 run_triple_wheel (&tm->triple_wheel, max_expiration_time + 1);
597
598 after = clib_time_now (&tm->clib_time);
599
600 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
601 tm->triple_wheel.current_tick);
602 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
603 (after - before),
604 ((f64) adds + (f64) deletes +
605 (f64) tm->triple_wheel.current_tick) / (after - before));
606
607 if (pool_elts (tm->test_elts))
608 fformat (stdout, "Note: %d elements remain in pool\n",
609 pool_elts (tm->test_elts));
610
611 /* *INDENT-OFF* */
612 pool_foreach (e, tm->test_elts,
613 ({
614 fformat (stdout, "[%d] expected to expire %d\n",
615 e - tm->test_elts,
616 e->expected_to_expire);
617 }));
618 /* *INDENT-ON* */
619
620 pool_free (tm->test_elts);
621 tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
622 return 0;
623}
624
625static clib_error_t *
626test2_triple_ov (tw_timer_test_main_t * tm)
627{
628 u32 i, j;
629 tw_timer_test_elt_t *e;
630 u32 initial_wheel_offset = 0;
631 u32 expiration_time;
632 u32 max_expiration_time = 0;
633 u32 *deleted_indices = 0;
634 u32 adds = 0, deletes = 0;
635 f64 before, after;
636
637 clib_time_init (&tm->clib_time);
638
639 tw_timer_wheel_init_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
640 expired_timer_triple_ov_callback,
641 1.0 /* timer interval */ , ~0);
642
643
644 /* Prime offset */
645 initial_wheel_offset = 75700;
646 run_triple_ov_wheel (&tm->triple_ov_wheel, initial_wheel_offset);
647
648 fformat (stdout,
649 "initial wheel time %d, fi %d si %d gi %d\n",
650 tm->triple_ov_wheel.current_tick,
651 tm->triple_ov_wheel.current_index[TW_TIMER_RING_FAST],
652 tm->triple_ov_wheel.current_index[TW_TIMER_RING_SLOW],
653 tm->triple_ov_wheel.current_index[TW_TIMER_RING_GLACIER]);
654
655 initial_wheel_offset = tm->triple_ov_wheel.current_tick;
656
657 fformat (stdout,
658 "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
659 tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
660
661 before = clib_time_now (&tm->clib_time);
662
663 /* Prime the pump */
664 for (i = 0; i < tm->ntimers; i++)
665 {
666 pool_get (tm->test_elts, e);
667 memset (e, 0, sizeof (*e));
668
669 do
670 {
671 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
672 }
673 while (expiration_time == 0);
674
675 if (expiration_time > max_expiration_time)
676 max_expiration_time = expiration_time;
677
678 e->expected_to_expire = expiration_time + initial_wheel_offset;
679
680 e->stop_timer_handle =
681 tw_timer_start_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
682 e - tm->test_elts, 0 /* timer id */ ,
683 expiration_time);
684 }
685
686 adds += i;
687
688 for (i = 0; i < tm->niter; i++)
689 {
690 run_triple_ov_wheel (&tm->triple_ov_wheel, tm->ticks_per_iter);
691
692 j = 0;
693 vec_reset_length (deleted_indices);
694 /* *INDENT-OFF* */
695 pool_foreach (e, tm->test_elts,
696 ({
697 tw_timer_stop_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
698 e->stop_timer_handle);
699 vec_add1 (deleted_indices, e - tm->test_elts);
700 if (++j >= tm->ntimers / 4)
701 goto del_and_re_add;
702 }));
703 /* *INDENT-ON* */
704
705 del_and_re_add:
706 for (j = 0; j < vec_len (deleted_indices); j++)
707 pool_put_index (tm->test_elts, deleted_indices[j]);
708
709 deletes += j;
710
711 for (j = 0; j < tm->ntimers / 4; j++)
712 {
713 pool_get (tm->test_elts, e);
714 memset (e, 0, sizeof (*e));
715
716 do
717 {
718 expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
719 }
720 while (expiration_time == 0);
721
722 if (expiration_time > max_expiration_time)
723 max_expiration_time = expiration_time;
724
725 e->expected_to_expire = expiration_time +
726 tm->triple_ov_wheel.current_tick;
727
728 e->stop_timer_handle = tw_timer_start_1t_3w_1024sl_ov
729 (&tm->triple_ov_wheel, e - tm->test_elts, 0 /* timer id */ ,
730 expiration_time);
731 }
732 adds += j;
733 }
734
735 vec_free (deleted_indices);
736
737 run_triple_ov_wheel (&tm->triple_ov_wheel, max_expiration_time + 1);
738
739 after = clib_time_now (&tm->clib_time);
740
741 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
742 tm->triple_ov_wheel.current_tick);
743 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
744 (after - before),
745 ((f64) adds + (f64) deletes +
746 (f64) tm->triple_ov_wheel.current_tick) / (after - before));
747
748 if (pool_elts (tm->test_elts))
749 fformat (stdout, "Note: %d elements remain in pool\n",
750 pool_elts (tm->test_elts));
751
752 /* *INDENT-OFF* */
753 pool_foreach (e, tm->test_elts,
754 ({
755 TWT (tw_timer) * t;
756
757 fformat (stdout, "[%d] expected to expire %d\n",
758 e - tm->test_elts,
759 e->expected_to_expire);
760 t = pool_elt_at_index (tm->triple_ov_wheel.timers, e->stop_timer_handle);
761 fformat (stdout, " expiration_time %lld\n", t->expiration_time);
762 }));
763 /* *INDENT-ON* */
764
765 pool_free (tm->test_elts);
766 tw_timer_wheel_free_1t_3w_1024sl_ov (&tm->triple_ov_wheel);
767 return 0;
768}
769
770static clib_error_t *
Dave Barach8e8f98c2017-02-03 11:58:53 -0500771test1_single (tw_timer_test_main_t * tm)
772{
773 u32 i;
774 tw_timer_test_elt_t *e;
775 u32 offset;
776
777 tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
778 expired_timer_single_callback,
Filip Tehlar816f4372017-04-26 16:09:06 +0200779 1.0 /* timer interval */ , ~0);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500780
781 /*
782 * Prime offset, to make sure that the wheel starts in a
783 * non-trivial position
784 */
785 offset = 123;
786
787 run_single_wheel (&tm->single_wheel, offset);
788
789 fformat (stdout, "initial wheel time %d, fast index %d\n",
790 tm->single_wheel.current_tick,
791 tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
792
Dave Barach4af9ba12017-06-07 15:18:23 -0400793 offset = tm->single_wheel.current_tick;
794
Dave Barach8e8f98c2017-02-03 11:58:53 -0500795 for (i = 0; i < tm->ntimers; i++)
796 {
797 u32 expected_to_expire;
798 u32 timer_arg;
799
800 timer_arg = 1 + i;
801 timer_arg &= 2047;
802 if (timer_arg == 0)
803 timer_arg = 1;
804
805 expected_to_expire = timer_arg + offset;
806
807 pool_get (tm->test_elts, e);
808 memset (e, 0, sizeof (*e));
809 e->expected_to_expire = expected_to_expire;
810 e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
811 (&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
812 timer_arg);
813 }
814 run_single_wheel (&tm->single_wheel, tm->ntimers + 3);
815
816 if (pool_elts (tm->test_elts))
817 fformat (stdout, "Note: %d elements remain in pool\n",
818 pool_elts (tm->test_elts));
819
820 /* *INDENT-OFF* */
821 pool_foreach (e, tm->test_elts,
822 ({
823 fformat(stdout, "[%d] expected to expire %d\n",
824 e - tm->test_elts,
825 e->expected_to_expire);
826 }));
827 /* *INDENT-ON* */
828
829 fformat (stdout,
830 "final wheel time %d, fast index %d\n",
831 tm->single_wheel.current_tick,
832 tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
833
834 pool_free (tm->test_elts);
835 tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
836 return 0;
837}
838
839static clib_error_t *
840test1_double (tw_timer_test_main_t * tm)
841{
842 u32 i;
843 tw_timer_test_elt_t *e;
844 u32 offset;
845
846 tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
847 expired_timer_double_callback,
Filip Tehlar816f4372017-04-26 16:09:06 +0200848 1.0 /* timer interval */ , ~0);
Dave Barach8e8f98c2017-02-03 11:58:53 -0500849
850 /*
851 * Prime offset, to make sure that the wheel starts in a
852 * non-trivial position
853 */
854 offset = 227989;
855
856 run_double_wheel (&tm->double_wheel, offset);
857
858 fformat (stdout, "initial wheel time %d, fast index %d\n",
859 tm->double_wheel.current_tick,
860 tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
861
862 for (i = 0; i < tm->ntimers; i++)
863 {
864 pool_get (tm->test_elts, e);
865 memset (e, 0, sizeof (*e));
866
867 e->expected_to_expire = i + offset + 1;
868 e->stop_timer_handle = tw_timer_start_16t_2w_512sl
869 (&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
870 i + 1);
871 }
872 run_double_wheel (&tm->double_wheel, tm->ntimers + 3);
873
874 if (pool_elts (tm->test_elts))
875 fformat (stdout, "Note: %d elements remain in pool\n",
876 pool_elts (tm->test_elts));
877
878 /* *INDENT-OFF* */
879 pool_foreach (e, tm->test_elts,
880 ({
881 fformat(stdout, "[%d] expected to expire %d\n",
882 e - tm->test_elts,
883 e->expected_to_expire);
884 }));
885 /* *INDENT-ON* */
886
887 fformat (stdout,
888 "final wheel time %d, fast index %d\n",
889 tm->double_wheel.current_tick,
890 tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
891
892 pool_free (tm->test_elts);
893 tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
894 return 0;
895}
896
897static clib_error_t *
Dave Barach4af9ba12017-06-07 15:18:23 -0400898test3_triple_double (tw_timer_test_main_t * tm)
899{
900 tw_timer_test_elt_t *e;
901 u32 initial_wheel_offset = 0;
902 u32 expiration_time;
903 u32 max_expiration_time = 0;
904 u32 adds = 0, deletes = 0;
905 f64 before, after;
906
907 clib_time_init (&tm->clib_time);
908
909 tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
910 expired_timer_triple_callback,
911 1.0 /* timer interval */ , ~0);
912
913 initial_wheel_offset = 0;
914 run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
915
916 fformat (stdout,
917 "initial wheel time %d, fi %d si %d gi %d\n",
918 tm->triple_wheel.current_tick,
919 tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
920 tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
921 tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
922
923 initial_wheel_offset = tm->triple_wheel.current_tick;
924
925 fformat (stdout, "Create a timer which expires at wheel-time (1, 0, 0)\n");
926
927 before = clib_time_now (&tm->clib_time);
928
929 /* Prime the pump */
930 pool_get (tm->test_elts, e);
931 memset (e, 0, sizeof (*e));
932
933 /* 1 glacier ring tick from now */
934 expiration_time = TW_SLOTS_PER_RING * TW_SLOTS_PER_RING;
935 e->expected_to_expire = expiration_time + initial_wheel_offset;
936 max_expiration_time = expiration_time;
937
938 e->stop_timer_handle =
939 tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
940 3 /* timer id */ ,
941 expiration_time);
942
943 run_triple_wheel (&tm->triple_wheel, max_expiration_time + 1);
944
945 after = clib_time_now (&tm->clib_time);
946
947 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
948 tm->triple_wheel.current_tick);
949 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
950 (after - before),
951 ((f64) adds + (f64) deletes +
952 (f64) tm->triple_wheel.current_tick) / (after - before));
953
954 if (pool_elts (tm->test_elts))
955 fformat (stdout, "Note: %d elements remain in pool\n",
956 pool_elts (tm->test_elts));
957
958 /* *INDENT-OFF* */
959 pool_foreach (e, tm->test_elts,
960 ({
961 fformat (stdout, "[%d] expected to expire %d\n",
962 e - tm->test_elts,
963 e->expected_to_expire);
964 }));
965 /* *INDENT-ON* */
966
967 pool_free (tm->test_elts);
968 tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
969 return 0;
970}
971
972static clib_error_t *
973test4_double_double (tw_timer_test_main_t * tm)
974{
975 u32 i;
976 tw_timer_test_elt_t *e;
977 u32 initial_wheel_offset;
978 u32 expiration_time;
979 u32 max_expiration_time = 0;
980 u32 *deleted_indices = 0;
981 u32 adds = 0, deletes = 0;
982 f64 before, after;
983
984 clib_time_init (&tm->clib_time);
985
986 tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
987 expired_timer_double_callback,
988 1.0 /* timer interval */ , ~0);
989 /* Prime offset */
990 initial_wheel_offset = 0;
991
992 run_double_wheel (&tm->double_wheel, initial_wheel_offset);
993
994 fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
995 tm->double_wheel.current_tick,
996 tm->double_wheel.current_index[TW_TIMER_RING_FAST],
997 tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
998
999 initial_wheel_offset = tm->double_wheel.current_tick;
1000
1001 fformat (stdout, "test timer which expires at 512 ticks\n");
1002
1003 before = clib_time_now (&tm->clib_time);
1004
1005 /* Prime the pump */
1006 for (i = 0; i < tm->ntimers; i++)
1007 {
1008 pool_get (tm->test_elts, e);
1009 memset (e, 0, sizeof (*e));
1010
1011 expiration_time = 512;
1012
1013 if (expiration_time > max_expiration_time)
1014 max_expiration_time = expiration_time;
1015
1016 e->expected_to_expire = expiration_time + initial_wheel_offset;
1017 e->stop_timer_handle =
1018 tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
1019 14 /* timer id */ ,
1020 expiration_time);
1021 }
1022
1023 adds = 1;
1024
1025 vec_free (deleted_indices);
1026
1027 run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
1028
1029 after = clib_time_now (&tm->clib_time);
1030
1031 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
1032 tm->double_wheel.current_tick);
1033 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
1034 (after - before),
1035 ((f64) adds + (f64) deletes +
1036 (f64) tm->double_wheel.current_tick) / (after - before));
1037
1038 if (pool_elts (tm->test_elts))
1039 fformat (stdout, "Note: %d elements remain in pool\n",
1040 pool_elts (tm->test_elts));
1041
1042 /* *INDENT-OFF* */
1043 pool_foreach (e, tm->test_elts,
1044 ({
1045 fformat (stdout, "[%d] expected to expire %d\n",
1046 e - tm->test_elts,
1047 e->expected_to_expire);
1048 }));
1049 /* *INDENT-ON* */
1050
1051 pool_free (tm->test_elts);
1052 tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
1053 return 0;
1054}
1055
1056static clib_error_t *
1057test5_double (tw_timer_test_main_t * tm)
1058{
1059 u32 i;
1060 tw_timer_test_elt_t *e;
1061 u32 initial_wheel_offset;
1062 u32 expiration_time;
1063 u32 max_expiration_time = 0;
1064 u32 adds = 0, deletes = 0;
1065 f64 before, after;
1066
1067 clib_time_init (&tm->clib_time);
1068
1069 tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
1070 expired_timer_double_callback,
1071 1.0 /* timer interval */ , ~0);
1072
1073 /* Prime offset */
1074 initial_wheel_offset = 7567;
1075
1076 run_double_wheel (&tm->double_wheel, initial_wheel_offset);
1077
1078 fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
1079 tm->double_wheel.current_tick,
1080 tm->double_wheel.current_index[TW_TIMER_RING_FAST],
1081 tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
1082
1083 initial_wheel_offset = tm->double_wheel.current_tick;
1084
1085 fformat (stdout,
1086 "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
1087 tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
1088
1089 before = clib_time_now (&tm->clib_time);
1090
1091 /* Prime the pump */
1092 for (i = 0; i < tm->ntimers; i++)
1093 {
1094 pool_get (tm->test_elts, e);
1095 memset (e, 0, sizeof (*e));
1096
1097 expiration_time = i + 1;
1098
1099 if (expiration_time > max_expiration_time)
1100 max_expiration_time = expiration_time;
1101
1102 e->expected_to_expire = expiration_time + initial_wheel_offset;
1103 e->stop_timer_handle =
1104 tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
1105 14 /* timer id */ ,
1106 expiration_time);
1107 }
1108
1109 adds += i;
1110
1111 run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
1112
1113 after = clib_time_now (&tm->clib_time);
1114
1115 fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
1116 tm->double_wheel.current_tick);
1117 fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
1118 (after - before),
1119 ((f64) adds + (f64) deletes +
1120 (f64) tm->double_wheel.current_tick) / (after - before));
1121
1122 if (pool_elts (tm->test_elts))
1123 fformat (stdout, "Note: %d elements remain in pool\n",
1124 pool_elts (tm->test_elts));
1125
1126 /* *INDENT-OFF* */
1127 pool_foreach (e, tm->test_elts,
1128 ({
1129 fformat (stdout, "[%d] expected to expire %d\n",
1130 e - tm->test_elts,
1131 e->expected_to_expire);
1132 }));
1133 /* *INDENT-ON* */
1134
1135 pool_free (tm->test_elts);
1136 tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
1137 return 0;
1138}
1139
1140static clib_error_t *
Dave Barach8e8f98c2017-02-03 11:58:53 -05001141timer_test_command_fn (tw_timer_test_main_t * tm, unformat_input_t * input)
1142{
1143
1144 int is_test1 = 0;
1145 int num_wheels = 1;
1146 int is_test2 = 0;
Dave Barach4af9ba12017-06-07 15:18:23 -04001147 int is_test3 = 0;
1148 int is_test4 = 0;
1149 int is_test5 = 0;
1150 int overflow = 0;
Dave Barach8e8f98c2017-02-03 11:58:53 -05001151
1152 memset (tm, 0, sizeof (*tm));
1153 /* Default values */
1154 tm->ntimers = 100000;
Dave Barach4af9ba12017-06-07 15:18:23 -04001155 tm->seed = 0xDEADDABEB00BFACE;
Dave Barach8e8f98c2017-02-03 11:58:53 -05001156 tm->niter = 1000;
1157 tm->ticks_per_iter = 727;
1158
1159 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1160 {
Dave Barach4af9ba12017-06-07 15:18:23 -04001161 if (unformat (input, "seed %lld", &tm->seed))
Dave Barach8e8f98c2017-02-03 11:58:53 -05001162 ;
1163 else if (unformat (input, "test1"))
1164 is_test1 = 1;
1165 else if (unformat (input, "test2"))
1166 is_test2 = 1;
Dave Barach4af9ba12017-06-07 15:18:23 -04001167 else if (unformat (input, "overflow"))
1168 overflow = 1;
1169 else if (unformat (input, "lebron"))
1170 is_test3 = 1;
1171 else if (unformat (input, "wilt"))
1172 is_test4 = 1;
1173 else if (unformat (input, "linear"))
1174 is_test5 = 1;
Dave Barach8e8f98c2017-02-03 11:58:53 -05001175 else if (unformat (input, "wheels %d", &num_wheels))
1176 ;
1177 else if (unformat (input, "ntimers %d", &tm->ntimers))
1178 ;
1179 else if (unformat (input, "niter %d", &tm->niter))
1180 ;
1181 else if (unformat (input, "ticks_per_iter %d", &tm->ticks_per_iter))
1182 ;
Dave Barach4af9ba12017-06-07 15:18:23 -04001183 else
1184 break;
Dave Barach8e8f98c2017-02-03 11:58:53 -05001185 }
1186
Dave Barach4af9ba12017-06-07 15:18:23 -04001187 if (is_test1 + is_test2 + is_test3 + is_test4 + is_test5 == 0)
Dave Barach8e8f98c2017-02-03 11:58:53 -05001188 return clib_error_return (0, "No test specified [test1..n]");
1189
Dave Barach4af9ba12017-06-07 15:18:23 -04001190 if (num_wheels < 1 || num_wheels > 3)
Dave Barach8e8f98c2017-02-03 11:58:53 -05001191 return clib_error_return (0, "unsupported... 1 or 2 wheels only");
1192
1193 if (is_test1)
1194 {
1195 if (num_wheels == 1)
1196 return test1_single (tm);
1197 else
1198 return test1_double (tm);
1199 }
1200 if (is_test2)
1201 {
1202 if (num_wheels == 1)
1203 return test2_single (tm);
Dave Barach4af9ba12017-06-07 15:18:23 -04001204 else if (num_wheels == 2)
Dave Barach8e8f98c2017-02-03 11:58:53 -05001205 return test2_double (tm);
Dave Barach4af9ba12017-06-07 15:18:23 -04001206 else if (num_wheels == 3)
1207 {
1208 if (overflow == 0)
1209 return test2_triple (tm);
1210 else
1211 return test2_triple_ov (tm);
1212 }
Dave Barach8e8f98c2017-02-03 11:58:53 -05001213 }
Dave Barach4af9ba12017-06-07 15:18:23 -04001214 if (is_test3)
1215 return test3_triple_double (tm);
1216
1217 if (is_test4)
1218 return test4_double_double (tm);
1219
1220 if (is_test5)
1221 return test5_double (tm);
1222
Dave Barach8e8f98c2017-02-03 11:58:53 -05001223 /* NOTREACHED */
1224 return 0;
1225}
1226
1227#ifdef CLIB_UNIX
1228int
1229main (int argc, char *argv[])
1230{
1231 unformat_input_t i;
1232 clib_error_t *error;
1233 tw_timer_test_main_t *tm = &tw_timer_test_main;
1234
1235 clib_mem_init (0, 3ULL << 30);
1236
1237 unformat_init_command_line (&i, argv);
1238 error = timer_test_command_fn (tm, &i);
1239 unformat_free (&i);
1240
1241 if (error)
1242 {
1243 clib_error_report (error);
1244 return 1;
1245 }
1246 return 0;
1247}
1248#endif /* CLIB_UNIX */
1249
Dave Barach4af9ba12017-06-07 15:18:23 -04001250/* For debugging... */
1251int
1252pifi (void *p, u32 index)
1253{
1254 return pool_is_free_index (p, index);
1255}
1256
1257u32
1258vl (void *p)
1259{
1260 return vec_len (p);
1261}
1262
1263uword
1264pe (void *v)
1265{
1266 return (pool_elts (v));
1267}
1268
Dave Barach8e8f98c2017-02-03 11:58:53 -05001269/*
1270 * fd.io coding-style-patch-verification: ON
1271 *
1272 * Local Variables:
1273 * eval: (c-set-style "gnu")
1274 * End:
1275 */