udp: fix csum computation when offload disabled
[vpp.git] / src / vppinfra / test_tw_timer.c
1 #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_2t_2w_512sl.h>
6 #include <vppinfra/tw_timer_16t_2w_512sl.h>
7 #include <vppinfra/tw_timer_4t_3w_256sl.h>
8 #include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
9
10 typedef struct
11 {
12   /** Handle returned from tw_start_timer */
13   u32 stop_timer_handle;
14
15   /** Test item should expire at this clock tick */
16   u64 expected_to_expire;
17 } tw_timer_test_elt_t;
18
19 typedef struct
20 {
21   /** Pool of test objects */
22   tw_timer_test_elt_t *test_elts;
23
24   /** The single-wheel */
25   tw_timer_wheel_2t_1w_2048sl_t single_wheel;
26
27   /** The double-wheel */
28   tw_timer_wheel_16t_2w_512sl_t double_wheel;
29
30   /* The triple wheel */
31   tw_timer_wheel_4t_3w_256sl_t triple_wheel;
32
33   /* The triple wheel with overflow vector */
34   tw_timer_wheel_1t_3w_1024sl_ov_t triple_ov_wheel;
35
36   /* Another two timer wheel geometry */
37   tw_timer_wheel_2t_2w_512sl_t two_timer_double_wheel;
38
39   /** random number seed */
40   u64 seed;
41
42   /** number of timers */
43   u32 ntimers;
44
45   /** number of "churn" iterations */
46   u32 niter;
47
48   /** number of clock ticks per churn iteration */
49   u32 ticks_per_iter;
50
51   /** cpu timer */
52   clib_time_t clib_time;
53 } tw_timer_test_main_t;
54
55 tw_timer_test_main_t tw_timer_test_main;
56
57 static void
58 run_single_wheel (tw_timer_wheel_2t_1w_2048sl_t * tw, u32 n_ticks)
59 {
60   u32 i;
61   f64 now = tw->last_run_time + 1.01;
62
63   for (i = 0; i < n_ticks; i++)
64     {
65       tw_timer_expire_timers_2t_1w_2048sl (tw, now);
66       now += 1.01;
67     }
68 }
69
70 static void
71 run_double_wheel (tw_timer_wheel_16t_2w_512sl_t * tw, u32 n_ticks)
72 {
73   u32 i;
74   f64 now = tw->last_run_time + 1.01;
75
76   for (i = 0; i < n_ticks; i++)
77     {
78       tw_timer_expire_timers_16t_2w_512sl (tw, now);
79       now += 1.01;
80     }
81 }
82
83 static void
84 run_two_timer_double_wheel (tw_timer_wheel_2t_2w_512sl_t * tw, u32 n_ticks)
85 {
86   u32 i;
87   f64 now = tw->last_run_time + 1.01;
88
89   for (i = 0; i < n_ticks; i++)
90     {
91       tw_timer_expire_timers_2t_2w_512sl (tw, now);
92       now += 1.01;
93     }
94 }
95
96 static void
97 run_triple_wheel (tw_timer_wheel_4t_3w_256sl_t * tw, u32 n_ticks)
98 {
99   u32 i;
100   f64 now = tw->last_run_time + 1.01;
101
102   for (i = 0; i < n_ticks; i++)
103     {
104       tw_timer_expire_timers_4t_3w_256sl (tw, now);
105       now += 1.01;
106     }
107 }
108
109 static void
110 run_triple_ov_wheel (tw_timer_wheel_1t_3w_1024sl_ov_t * tw, u32 n_ticks)
111 {
112   u32 i;
113   f64 now = tw->last_run_time + 1.01;
114
115   for (i = 0; i < n_ticks; i++)
116     {
117       tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
118       now += 1.01;
119     }
120 }
121
122 static void
123 expired_timer_single_callback (u32 * expired_timers)
124 {
125   int i;
126   u32 pool_index, timer_id;
127   tw_timer_test_elt_t *e;
128   tw_timer_test_main_t *tm = &tw_timer_test_main;
129
130   for (i = 0; i < vec_len (expired_timers); i++)
131     {
132       pool_index = expired_timers[i] & 0x7FFFFFFF;
133       timer_id = expired_timers[i] >> 31;
134
135       ASSERT (timer_id == 1);
136
137       e = pool_elt_at_index (tm->test_elts, pool_index);
138
139       if (e->expected_to_expire != tm->single_wheel.current_tick)
140         {
141           fformat (stdout, "[%d] expired at %lld not %lld\n",
142                    e - tm->test_elts, tm->single_wheel.current_tick,
143                    e->expected_to_expire);
144         }
145       pool_put (tm->test_elts, e);
146     }
147 }
148
149 static void
150 expired_timer_double_callback (u32 * expired_timers)
151 {
152   int i;
153   u32 pool_index, timer_id;
154   tw_timer_test_elt_t *e;
155   tw_timer_test_main_t *tm = &tw_timer_test_main;
156
157   for (i = 0; i < vec_len (expired_timers); i++)
158     {
159       pool_index = expired_timers[i] & 0x0FFFFFFF;
160       timer_id = expired_timers[i] >> 28;
161
162       ASSERT (timer_id == 14);
163
164       e = pool_elt_at_index (tm->test_elts, pool_index);
165
166       if (e->expected_to_expire != tm->double_wheel.current_tick)
167         {
168           fformat (stdout, "[%d] expired at %lld not %lld\n",
169                    e - tm->test_elts, tm->double_wheel.current_tick,
170                    e->expected_to_expire);
171         }
172       pool_put (tm->test_elts, e);
173     }
174 }
175
176 static void
177 expired_timer_two_timer_double_callback (u32 * expired_timers)
178 {
179   int i;
180   u32 pool_index, timer_id;
181   tw_timer_test_elt_t *e;
182   tw_timer_test_main_t *tm = &tw_timer_test_main;
183
184   for (i = 0; i < vec_len (expired_timers); i++)
185     {
186       pool_index = expired_timers[i] & 0x7FFFFFFF;
187       timer_id = expired_timers[i] >> 31;
188
189       ASSERT (timer_id == 1);
190
191       e = pool_elt_at_index (tm->test_elts, pool_index);
192
193       if (e->expected_to_expire != tm->two_timer_double_wheel.current_tick)
194         {
195           fformat (stdout, "[%d] expired at %lld not %lld\n",
196                    e - tm->test_elts, tm->two_timer_double_wheel.current_tick,
197                    e->expected_to_expire);
198         }
199       pool_put (tm->test_elts, e);
200     }
201 }
202
203 static void
204 expired_timer_triple_callback (u32 * expired_timers)
205 {
206   int i;
207   u32 pool_index, timer_id;
208   tw_timer_test_elt_t *e;
209   tw_timer_test_main_t *tm = &tw_timer_test_main;
210
211   for (i = 0; i < vec_len (expired_timers); i++)
212     {
213       pool_index = expired_timers[i] & 0x3FFFFFFF;
214       timer_id = expired_timers[i] >> 30;
215
216       ASSERT (timer_id == 3);
217
218       e = pool_elt_at_index (tm->test_elts, pool_index);
219
220       if (e->expected_to_expire != tm->triple_wheel.current_tick)
221         {
222           fformat (stdout, "[%d] expired at %lld not %lld\n",
223                    e - tm->test_elts, tm->triple_wheel.current_tick,
224                    e->expected_to_expire);
225         }
226       pool_put (tm->test_elts, e);
227     }
228 }
229
230 static void
231 expired_timer_triple_ov_callback (u32 * expired_timers)
232 {
233   int i;
234   u32 pool_index;
235   tw_timer_test_elt_t *e;
236   tw_timer_test_main_t *tm = &tw_timer_test_main;
237
238   for (i = 0; i < vec_len (expired_timers); i++)
239     {
240       pool_index = expired_timers[i];
241
242       e = pool_elt_at_index (tm->test_elts, pool_index);
243
244       if (e->expected_to_expire != tm->triple_ov_wheel.current_tick)
245         {
246           fformat (stdout, "[%d] expired at %lld not %lld\n",
247                    e - tm->test_elts, tm->triple_ov_wheel.current_tick,
248                    e->expected_to_expire);
249         }
250       pool_put (tm->test_elts, e);
251     }
252 }
253
254 static clib_error_t *
255 test2_single (tw_timer_test_main_t * tm)
256 {
257   u32 i, j;
258   tw_timer_test_elt_t *e;
259   u32 initial_wheel_offset;
260   u64 expiration_time;
261   u32 max_expiration_time = 0;
262   u32 *deleted_indices = 0;
263   u32 adds = 0, deletes = 0;
264   f64 before, after;
265
266   clib_time_init (&tm->clib_time);
267
268   tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
269                                     expired_timer_single_callback,
270                                     1.0 /* timer interval */ , ~0);
271
272   /* Prime offset */
273   initial_wheel_offset = 757;
274
275   run_single_wheel (&tm->single_wheel, initial_wheel_offset);
276
277   fformat (stdout, "initial wheel time %d, fast index %d\n",
278            tm->single_wheel.current_tick,
279            tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
280
281   initial_wheel_offset = tm->single_wheel.current_tick;
282
283   fformat (stdout,
284            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
285            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
286
287   before = clib_time_now (&tm->clib_time);
288
289   /* Prime the pump */
290   for (i = 0; i < tm->ntimers; i++)
291     {
292       pool_get (tm->test_elts, e);
293       clib_memset (e, 0, sizeof (*e));
294
295       do
296         {
297           expiration_time = random_u64 (&tm->seed) & (2047);
298         }
299       while (expiration_time == 0);
300
301       if (expiration_time > max_expiration_time)
302         max_expiration_time = expiration_time;
303
304       e->expected_to_expire = expiration_time + initial_wheel_offset;
305       e->stop_timer_handle =
306         tw_timer_start_2t_1w_2048sl (&tm->single_wheel, e - tm->test_elts,
307                                      1 /* timer id */ ,
308                                      expiration_time);
309     }
310
311   adds += i;
312
313   for (i = 0; i < tm->niter; i++)
314     {
315       run_single_wheel (&tm->single_wheel, tm->ticks_per_iter);
316
317       j = 0;
318       vec_reset_length (deleted_indices);
319       pool_foreach (e, tm->test_elts)
320        {
321         tw_timer_stop_2t_1w_2048sl (&tm->single_wheel, e->stop_timer_handle);
322         vec_add1 (deleted_indices, e - tm->test_elts);
323         if (++j >= tm->ntimers / 4)
324           goto del_and_re_add;
325       }
326
327     del_and_re_add:
328       for (j = 0; j < vec_len (deleted_indices); j++)
329         {
330           pool_put_index (tm->test_elts, deleted_indices[j]);
331         }
332
333       deletes += j;
334
335       for (j = 0; j < tm->ntimers / 4; j++)
336         {
337           pool_get (tm->test_elts, e);
338           clib_memset (e, 0, sizeof (*e));
339
340           do
341             {
342               expiration_time = random_u64 (&tm->seed) & (2047);
343             }
344           while (expiration_time == 0);
345
346           if (expiration_time > max_expiration_time)
347             max_expiration_time = expiration_time;
348
349           e->expected_to_expire =
350             expiration_time + tm->single_wheel.current_tick;
351           e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
352             (&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
353              expiration_time);
354         }
355       adds += j;
356     }
357
358   vec_free (deleted_indices);
359
360   run_single_wheel (&tm->single_wheel, max_expiration_time + 1);
361
362   after = clib_time_now (&tm->clib_time);
363
364   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
365            tm->single_wheel.current_tick);
366   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
367            (after - before),
368            ((f64) adds + (f64) deletes +
369             (f64) tm->single_wheel.current_tick) / (after - before));
370
371   if (pool_elts (tm->test_elts))
372     fformat (stdout, "Note: %d elements remain in pool\n",
373              pool_elts (tm->test_elts));
374
375   pool_foreach (e, tm->test_elts)
376    {
377     fformat (stdout, "[%d] expected to expire %d\n",
378              e - tm->test_elts,
379              e->expected_to_expire);
380   }
381
382   pool_free (tm->test_elts);
383   tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
384   return 0;
385 }
386
387 static clib_error_t *
388 test2_double (tw_timer_test_main_t * tm)
389 {
390   u32 i, j;
391   tw_timer_test_elt_t *e;
392   u32 initial_wheel_offset;
393   u32 expiration_time;
394   u32 max_expiration_time = 0;
395   u32 *deleted_indices = 0;
396   u32 adds = 0, deletes = 0;
397   f64 before, after;
398
399   clib_time_init (&tm->clib_time);
400
401   tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
402                                     expired_timer_double_callback,
403                                     1.0 /* timer interval */ , ~0);
404
405   /* Prime offset */
406   initial_wheel_offset = 7577;
407
408   run_double_wheel (&tm->double_wheel, initial_wheel_offset);
409
410   fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
411            tm->double_wheel.current_tick,
412            tm->double_wheel.current_index[TW_TIMER_RING_FAST],
413            tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
414
415   initial_wheel_offset = tm->double_wheel.current_tick;
416
417   fformat (stdout,
418            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
419            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
420
421   before = clib_time_now (&tm->clib_time);
422
423   /* Prime the pump */
424   for (i = 0; i < tm->ntimers; i++)
425     {
426       pool_get (tm->test_elts, e);
427       clib_memset (e, 0, sizeof (*e));
428
429       do
430         {
431           expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
432         }
433       while (expiration_time == 0);
434
435       if (expiration_time > max_expiration_time)
436         max_expiration_time = expiration_time;
437
438       e->expected_to_expire = expiration_time + initial_wheel_offset;
439
440       e->stop_timer_handle =
441         tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
442                                      14 /* timer id */ ,
443                                      expiration_time);
444     }
445
446   adds += i;
447
448   for (i = 0; i < tm->niter; i++)
449     {
450       run_double_wheel (&tm->double_wheel, tm->ticks_per_iter);
451
452       j = 0;
453       vec_reset_length (deleted_indices);
454       pool_foreach (e, tm->test_elts)
455        {
456         tw_timer_stop_16t_2w_512sl (&tm->double_wheel, e->stop_timer_handle);
457         vec_add1 (deleted_indices, e - tm->test_elts);
458         if (++j >= tm->ntimers / 4)
459           goto del_and_re_add;
460       }
461
462     del_and_re_add:
463       for (j = 0; j < vec_len (deleted_indices); j++)
464         pool_put_index (tm->test_elts, deleted_indices[j]);
465
466       deletes += j;
467
468       for (j = 0; j < tm->ntimers / 4; j++)
469         {
470           pool_get (tm->test_elts, e);
471           clib_memset (e, 0, sizeof (*e));
472
473           do
474             {
475               expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
476             }
477           while (expiration_time == 0);
478
479           if (expiration_time > max_expiration_time)
480             max_expiration_time = expiration_time;
481
482           e->expected_to_expire = expiration_time +
483             tm->double_wheel.current_tick;
484
485           e->stop_timer_handle = tw_timer_start_16t_2w_512sl
486             (&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
487              expiration_time);
488         }
489       adds += j;
490     }
491
492   vec_free (deleted_indices);
493
494   run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
495
496   after = clib_time_now (&tm->clib_time);
497
498   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
499            tm->double_wheel.current_tick);
500   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
501            (after - before),
502            ((f64) adds + (f64) deletes +
503             (f64) tm->double_wheel.current_tick) / (after - before));
504
505   if (pool_elts (tm->test_elts))
506     fformat (stdout, "Note: %d elements remain in pool\n",
507              pool_elts (tm->test_elts));
508
509   pool_foreach (e, tm->test_elts)
510    {
511     fformat (stdout, "[%d] expected to expire %d\n",
512              e - tm->test_elts,
513              e->expected_to_expire);
514   }
515
516   pool_free (tm->test_elts);
517   tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
518   return 0;
519 }
520
521 static u32
522 get_expiration_time (tw_timer_test_main_t * tm)
523 {
524   u32 expiration_time;
525   do
526     {
527       expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
528     }
529   while (expiration_time == 0);
530   return expiration_time;
531 }
532
533 static clib_error_t *
534 test2_double_updates (tw_timer_test_main_t * tm)
535 {
536   u32 i, j;
537   tw_timer_test_elt_t *e;
538   u32 initial_wheel_offset;
539   u32 expiration_time;
540   u32 max_expiration_time = 0, updates = 0;
541   f64 before, after;
542
543   clib_time_init (&tm->clib_time);
544   tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
545                                     expired_timer_double_callback,
546                                     1.0 /* timer interval */ , ~0);
547
548   /* Prime offset */
549   initial_wheel_offset = 7577;
550   run_double_wheel (&tm->double_wheel, initial_wheel_offset);
551   fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
552            tm->double_wheel.current_tick,
553            tm->double_wheel.current_index[TW_TIMER_RING_FAST],
554            tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
555
556   initial_wheel_offset = tm->double_wheel.current_tick;
557   fformat (stdout,
558            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
559            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
560
561   before = clib_time_now (&tm->clib_time);
562
563   /* Prime the pump */
564   for (i = 0; i < tm->ntimers; i++)
565     {
566       pool_get (tm->test_elts, e);
567       clib_memset (e, 0, sizeof (*e));
568
569       expiration_time = get_expiration_time (tm);
570       max_expiration_time = clib_max (expiration_time, max_expiration_time);
571
572       e->expected_to_expire = expiration_time + initial_wheel_offset;
573       e->stop_timer_handle = tw_timer_start_16t_2w_512sl (&tm->double_wheel,
574                                                           e - tm->test_elts,
575                                                           14 /* timer id */ ,
576                                                           expiration_time);
577     }
578
579   for (i = 0; i < tm->niter; i++)
580     {
581       run_double_wheel (&tm->double_wheel, tm->ticks_per_iter);
582
583       j = 0;
584
585       pool_foreach (e, tm->test_elts)
586        {
587         expiration_time = get_expiration_time (tm);
588         max_expiration_time = clib_max (expiration_time, max_expiration_time);
589         e->expected_to_expire = expiration_time
590                                 + tm->double_wheel.current_tick;
591         tw_timer_update_16t_2w_512sl (&tm->double_wheel, e->stop_timer_handle,
592                                       expiration_time);
593         if (++j >= tm->ntimers / 4)
594           goto done;
595       }
596
597     done:
598       updates += j;
599     }
600
601   run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
602
603   after = clib_time_now (&tm->clib_time);
604
605   fformat (stdout, "%d updates, %d ticks\n", updates,
606            tm->double_wheel.current_tick);
607   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
608            (after - before),
609            ((f64) updates + (f64) tm->double_wheel.current_tick) / (after -
610                                                                     before));
611
612   if (pool_elts (tm->test_elts))
613     fformat (stdout, "Note: %d elements remain in pool\n",
614              pool_elts (tm->test_elts));
615
616   pool_foreach (e, tm->test_elts)
617    {
618     fformat (stdout, "[%d] expected to expire %d\n",
619              e - tm->test_elts,
620              e->expected_to_expire);
621   }
622
623   pool_free (tm->test_elts);
624   tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
625   return 0;
626 }
627
628 static clib_error_t *
629 test2_triple (tw_timer_test_main_t * tm)
630 {
631   u32 i, j;
632   tw_timer_test_elt_t *e;
633   u32 initial_wheel_offset = 0;
634   u32 expiration_time;
635   u32 max_expiration_time = 0;
636   u32 *deleted_indices = 0;
637   u32 adds = 0, deletes = 0;
638   f64 before, after;
639
640   clib_time_init (&tm->clib_time);
641
642   tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
643                                    expired_timer_triple_callback,
644                                    1.0 /* timer interval */ , ~0);
645
646
647   /* Prime offset */
648   initial_wheel_offset = 75700;
649   run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
650
651   fformat (stdout,
652            "initial wheel time %d, fi %d si %d gi %d\n",
653            tm->triple_wheel.current_tick,
654            tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
655            tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
656            tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
657
658   initial_wheel_offset = tm->triple_wheel.current_tick;
659
660   fformat (stdout,
661            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
662            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
663
664   before = clib_time_now (&tm->clib_time);
665
666   /* Prime the pump */
667   for (i = 0; i < tm->ntimers; i++)
668     {
669       pool_get (tm->test_elts, e);
670       clib_memset (e, 0, sizeof (*e));
671
672       do
673         {
674           expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
675         }
676       while (expiration_time == 0);
677
678       if (expiration_time > max_expiration_time)
679         max_expiration_time = expiration_time;
680
681       e->expected_to_expire = expiration_time + initial_wheel_offset;
682
683       e->stop_timer_handle =
684         tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
685                                     3 /* timer id */ ,
686                                     expiration_time);
687     }
688
689   adds += i;
690
691   for (i = 0; i < tm->niter; i++)
692     {
693       run_triple_wheel (&tm->triple_wheel, tm->ticks_per_iter);
694
695       j = 0;
696       vec_reset_length (deleted_indices);
697       pool_foreach (e, tm->test_elts)
698        {
699         tw_timer_stop_4t_3w_256sl (&tm->triple_wheel, e->stop_timer_handle);
700         vec_add1 (deleted_indices, e - tm->test_elts);
701         if (++j >= tm->ntimers / 4)
702           goto del_and_re_add;
703       }
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           clib_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_wheel.current_tick;
727
728           e->stop_timer_handle = tw_timer_start_4t_3w_256sl
729             (&tm->triple_wheel, e - tm->test_elts, 3 /* timer id */ ,
730              expiration_time);
731         }
732       adds += j;
733     }
734
735   vec_free (deleted_indices);
736
737   run_triple_wheel (&tm->triple_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_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_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   pool_foreach (e, tm->test_elts)
753    {
754     fformat (stdout, "[%d] expected to expire %d\n",
755              e - tm->test_elts,
756              e->expected_to_expire);
757   }
758
759   pool_free (tm->test_elts);
760   tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
761   return 0;
762 }
763
764 static clib_error_t *
765 test2_triple_ov (tw_timer_test_main_t * tm)
766 {
767   u32 i, j;
768   tw_timer_test_elt_t *e;
769   u32 initial_wheel_offset = 0;
770   u32 expiration_time;
771   u32 max_expiration_time = 0;
772   u32 *deleted_indices = 0;
773   u32 adds = 0, deletes = 0;
774   f64 before, after;
775
776   clib_time_init (&tm->clib_time);
777
778   tw_timer_wheel_init_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
779                                        expired_timer_triple_ov_callback,
780                                        1.0 /* timer interval */ , ~0);
781
782
783   /* Prime offset */
784   initial_wheel_offset = 75700;
785   run_triple_ov_wheel (&tm->triple_ov_wheel, initial_wheel_offset);
786
787   fformat (stdout,
788            "initial wheel time %d, fi %d si %d gi %d\n",
789            tm->triple_ov_wheel.current_tick,
790            tm->triple_ov_wheel.current_index[TW_TIMER_RING_FAST],
791            tm->triple_ov_wheel.current_index[TW_TIMER_RING_SLOW],
792            tm->triple_ov_wheel.current_index[TW_TIMER_RING_GLACIER]);
793
794   initial_wheel_offset = tm->triple_ov_wheel.current_tick;
795
796   fformat (stdout,
797            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
798            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
799
800   before = clib_time_now (&tm->clib_time);
801
802   /* Prime the pump */
803   for (i = 0; i < tm->ntimers; i++)
804     {
805       pool_get (tm->test_elts, e);
806       clib_memset (e, 0, sizeof (*e));
807
808       do
809         {
810           expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
811         }
812       while (expiration_time == 0);
813
814       if (expiration_time > max_expiration_time)
815         max_expiration_time = expiration_time;
816
817       e->expected_to_expire = expiration_time + initial_wheel_offset;
818
819       e->stop_timer_handle =
820         tw_timer_start_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
821                                         e - tm->test_elts, 0 /* timer id */ ,
822                                         expiration_time);
823     }
824
825   adds += i;
826
827   for (i = 0; i < tm->niter; i++)
828     {
829       run_triple_ov_wheel (&tm->triple_ov_wheel, tm->ticks_per_iter);
830
831       j = 0;
832       vec_reset_length (deleted_indices);
833       pool_foreach (e, tm->test_elts)
834        {
835         tw_timer_stop_1t_3w_1024sl_ov (&tm->triple_ov_wheel,
836                                        e->stop_timer_handle);
837         vec_add1 (deleted_indices, e - tm->test_elts);
838         if (++j >= tm->ntimers / 4)
839           goto del_and_re_add;
840       }
841
842     del_and_re_add:
843       for (j = 0; j < vec_len (deleted_indices); j++)
844         pool_put_index (tm->test_elts, deleted_indices[j]);
845
846       deletes += j;
847
848       for (j = 0; j < tm->ntimers / 4; j++)
849         {
850           pool_get (tm->test_elts, e);
851           clib_memset (e, 0, sizeof (*e));
852
853           do
854             {
855               expiration_time = random_u64 (&tm->seed) & ((1 << 17) - 1);
856             }
857           while (expiration_time == 0);
858
859           if (expiration_time > max_expiration_time)
860             max_expiration_time = expiration_time;
861
862           e->expected_to_expire = expiration_time +
863             tm->triple_ov_wheel.current_tick;
864
865           e->stop_timer_handle = tw_timer_start_1t_3w_1024sl_ov
866             (&tm->triple_ov_wheel, e - tm->test_elts, 0 /* timer id */ ,
867              expiration_time);
868         }
869       adds += j;
870     }
871
872   vec_free (deleted_indices);
873
874   run_triple_ov_wheel (&tm->triple_ov_wheel, max_expiration_time + 1);
875
876   after = clib_time_now (&tm->clib_time);
877
878   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
879            tm->triple_ov_wheel.current_tick);
880   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
881            (after - before),
882            ((f64) adds + (f64) deletes +
883             (f64) tm->triple_ov_wheel.current_tick) / (after - before));
884
885   if (pool_elts (tm->test_elts))
886     fformat (stdout, "Note: %d elements remain in pool\n",
887              pool_elts (tm->test_elts));
888
889   pool_foreach (e, tm->test_elts)
890    {
891     TWT (tw_timer) * t;
892
893     fformat (stdout, "[%d] expected to expire %d\n",
894              e - tm->test_elts,
895              e->expected_to_expire);
896     t = pool_elt_at_index (tm->triple_ov_wheel.timers, e->stop_timer_handle);
897     fformat (stdout, "  expiration_time %lld\n", t->expiration_time);
898   }
899
900   pool_free (tm->test_elts);
901   tw_timer_wheel_free_1t_3w_1024sl_ov (&tm->triple_ov_wheel);
902   return 0;
903 }
904
905 static clib_error_t *
906 test1_single (tw_timer_test_main_t * tm)
907 {
908   u32 i;
909   tw_timer_test_elt_t *e;
910   u32 offset;
911
912   tw_timer_wheel_init_2t_1w_2048sl (&tm->single_wheel,
913                                     expired_timer_single_callback,
914                                     1.0 /* timer interval */ , ~0);
915
916   /*
917    * Prime offset, to make sure that the wheel starts in a
918    * non-trivial position
919    */
920   offset = 123;
921
922   run_single_wheel (&tm->single_wheel, offset);
923
924   fformat (stdout, "initial wheel time %d, fast index %d\n",
925            tm->single_wheel.current_tick,
926            tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
927
928   offset = tm->single_wheel.current_tick;
929
930   for (i = 0; i < tm->ntimers; i++)
931     {
932       u32 expected_to_expire;
933       u32 timer_arg;
934
935       timer_arg = 1 + i;
936       timer_arg &= 2047;
937       if (timer_arg == 0)
938         timer_arg = 1;
939
940       expected_to_expire = timer_arg + tm->single_wheel.current_tick;
941
942       pool_get (tm->test_elts, e);
943       clib_memset (e, 0, sizeof (*e));
944       e->expected_to_expire = expected_to_expire;
945       e->stop_timer_handle = tw_timer_start_2t_1w_2048sl
946         (&tm->single_wheel, e - tm->test_elts, 1 /* timer id */ ,
947          timer_arg);
948     }
949   run_single_wheel (&tm->single_wheel, tm->ntimers + 3);
950
951   if (pool_elts (tm->test_elts))
952     fformat (stdout, "Note: %d elements remain in pool\n",
953              pool_elts (tm->test_elts));
954
955   pool_foreach (e, tm->test_elts)
956    {
957     fformat(stdout, "[%d] expected to expire %d\n",
958                      e - tm->test_elts,
959                      e->expected_to_expire);
960   }
961
962   fformat (stdout,
963            "final wheel time %d, fast index %d\n",
964            tm->single_wheel.current_tick,
965            tm->single_wheel.current_index[TW_TIMER_RING_FAST]);
966
967   pool_free (tm->test_elts);
968   tw_timer_wheel_free_2t_1w_2048sl (&tm->single_wheel);
969   return 0;
970 }
971
972 static clib_error_t *
973 test1_double (tw_timer_test_main_t * tm)
974 {
975   u32 i;
976   tw_timer_test_elt_t *e;
977   u32 offset;
978
979   tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
980                                     expired_timer_double_callback,
981                                     1.0 /* timer interval */ , ~0);
982
983   /*
984    * Prime offset, to make sure that the wheel starts in a
985    * non-trivial position
986    */
987   offset = 227989;
988
989   run_double_wheel (&tm->double_wheel, offset);
990
991   fformat (stdout, "initial wheel time %d, fast index %d\n",
992            tm->double_wheel.current_tick,
993            tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
994
995   for (i = 0; i < tm->ntimers; i++)
996     {
997       pool_get (tm->test_elts, e);
998       clib_memset (e, 0, sizeof (*e));
999
1000       e->expected_to_expire = i + tm->double_wheel.current_tick + 1;
1001       e->stop_timer_handle = tw_timer_start_16t_2w_512sl
1002         (&tm->double_wheel, e - tm->test_elts, 14 /* timer id */ ,
1003          i + 1);
1004     }
1005   run_double_wheel (&tm->double_wheel, tm->ntimers + 3);
1006
1007   if (pool_elts (tm->test_elts))
1008     fformat (stdout, "Note: %d elements remain in pool\n",
1009              pool_elts (tm->test_elts));
1010
1011   pool_foreach (e, tm->test_elts)
1012    {
1013     fformat(stdout, "[%d] expected to expire %d\n",
1014                      e - tm->test_elts,
1015                      e->expected_to_expire);
1016   }
1017
1018   fformat (stdout,
1019            "final wheel time %d, fast index %d\n",
1020            tm->double_wheel.current_tick,
1021            tm->double_wheel.current_index[TW_TIMER_RING_FAST]);
1022
1023   pool_free (tm->test_elts);
1024   tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
1025   return 0;
1026 }
1027
1028 static clib_error_t *
1029 test1_two_timer_double (tw_timer_test_main_t * tm)
1030 {
1031   u32 i;
1032   tw_timer_test_elt_t *e;
1033   u32 offset;
1034
1035   tw_timer_wheel_init_2t_2w_512sl (&tm->two_timer_double_wheel,
1036                                    expired_timer_two_timer_double_callback,
1037                                    1.0 /* timer interval */ , ~0);
1038
1039   /*
1040    * Prime offset, to make sure that the wheel starts in a
1041    * non-trivial position
1042    */
1043   offset = 2745;
1044
1045   run_two_timer_double_wheel (&tm->two_timer_double_wheel, offset);
1046
1047   fformat (stdout, "initial wheel time %d, fast index %d\n",
1048            tm->two_timer_double_wheel.current_tick,
1049            tm->two_timer_double_wheel.current_index[TW_TIMER_RING_FAST]);
1050
1051   for (i = 0; i < tm->ntimers; i++)
1052     {
1053       pool_get (tm->test_elts, e);
1054       clib_memset (e, 0, sizeof (*e));
1055
1056       e->expected_to_expire = i + tm->two_timer_double_wheel.current_tick + 1;
1057       e->stop_timer_handle = tw_timer_start_2t_2w_512sl
1058         (&tm->two_timer_double_wheel, e - tm->test_elts, 1 /* timer id */ ,
1059          i + 1);
1060     }
1061   run_two_timer_double_wheel (&tm->two_timer_double_wheel, tm->ntimers + 3);
1062
1063   if (pool_elts (tm->test_elts))
1064     fformat (stdout, "Note: %d elements remain in pool\n",
1065              pool_elts (tm->test_elts));
1066
1067   pool_foreach (e, tm->test_elts)
1068    {
1069     fformat(stdout, "[%d] expected to expire %d\n",
1070                      e - tm->test_elts,
1071                      e->expected_to_expire);
1072   }
1073
1074   fformat (stdout,
1075            "final wheel time %d, fast index %d\n",
1076            tm->two_timer_double_wheel.current_tick,
1077            tm->two_timer_double_wheel.current_index[TW_TIMER_RING_FAST]);
1078
1079   pool_free (tm->test_elts);
1080   tw_timer_wheel_free_2t_2w_512sl (&tm->two_timer_double_wheel);
1081   return 0;
1082 }
1083
1084 static clib_error_t *
1085 test3_triple_double (tw_timer_test_main_t * tm)
1086 {
1087   tw_timer_test_elt_t *e;
1088   u32 initial_wheel_offset = 0;
1089   u32 expiration_time;
1090   u32 max_expiration_time = 0;
1091   u32 adds = 0, deletes = 0;
1092   f64 before, after;
1093
1094   clib_time_init (&tm->clib_time);
1095
1096   tw_timer_wheel_init_4t_3w_256sl (&tm->triple_wheel,
1097                                    expired_timer_triple_callback,
1098                                    1.0 /* timer interval */ , ~0);
1099
1100   initial_wheel_offset = 0;
1101   run_triple_wheel (&tm->triple_wheel, initial_wheel_offset);
1102
1103   fformat (stdout,
1104            "initial wheel time %d, fi %d si %d gi %d\n",
1105            tm->triple_wheel.current_tick,
1106            tm->triple_wheel.current_index[TW_TIMER_RING_FAST],
1107            tm->triple_wheel.current_index[TW_TIMER_RING_SLOW],
1108            tm->triple_wheel.current_index[TW_TIMER_RING_GLACIER]);
1109
1110   initial_wheel_offset = tm->triple_wheel.current_tick;
1111
1112   fformat (stdout, "Create a timer which expires at wheel-time (1, 0, 0)\n");
1113
1114   before = clib_time_now (&tm->clib_time);
1115
1116   /* Prime the pump */
1117   pool_get (tm->test_elts, e);
1118   clib_memset (e, 0, sizeof (*e));
1119
1120   /* 1 glacier ring tick from now */
1121   expiration_time = TW_SLOTS_PER_RING * TW_SLOTS_PER_RING;
1122   e->expected_to_expire = expiration_time + initial_wheel_offset;
1123   max_expiration_time = expiration_time;
1124
1125   e->stop_timer_handle =
1126     tw_timer_start_4t_3w_256sl (&tm->triple_wheel, e - tm->test_elts,
1127                                 3 /* timer id */ ,
1128                                 expiration_time);
1129
1130   run_triple_wheel (&tm->triple_wheel, max_expiration_time + 1);
1131
1132   after = clib_time_now (&tm->clib_time);
1133
1134   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
1135            tm->triple_wheel.current_tick);
1136   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
1137            (after - before),
1138            ((f64) adds + (f64) deletes +
1139             (f64) tm->triple_wheel.current_tick) / (after - before));
1140
1141   if (pool_elts (tm->test_elts))
1142     fformat (stdout, "Note: %d elements remain in pool\n",
1143              pool_elts (tm->test_elts));
1144
1145   pool_foreach (e, tm->test_elts)
1146    {
1147     fformat (stdout, "[%d] expected to expire %d\n",
1148              e - tm->test_elts,
1149              e->expected_to_expire);
1150   }
1151
1152   pool_free (tm->test_elts);
1153   tw_timer_wheel_free_4t_3w_256sl (&tm->triple_wheel);
1154   return 0;
1155 }
1156
1157 static clib_error_t *
1158 test4_double_double (tw_timer_test_main_t * tm)
1159 {
1160   u32 i;
1161   tw_timer_test_elt_t *e;
1162   u32 initial_wheel_offset;
1163   u32 expiration_time;
1164   u32 max_expiration_time = 0;
1165   u32 *deleted_indices = 0;
1166   u32 adds = 0, deletes = 0;
1167   f64 before, after;
1168
1169   clib_time_init (&tm->clib_time);
1170
1171   tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
1172                                     expired_timer_double_callback,
1173                                     1.0 /* timer interval */ , ~0);
1174   /* Prime offset */
1175   initial_wheel_offset = 0;
1176
1177   run_double_wheel (&tm->double_wheel, initial_wheel_offset);
1178
1179   fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
1180            tm->double_wheel.current_tick,
1181            tm->double_wheel.current_index[TW_TIMER_RING_FAST],
1182            tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
1183
1184   initial_wheel_offset = tm->double_wheel.current_tick;
1185
1186   fformat (stdout, "test timer which expires at 512 ticks\n");
1187
1188   before = clib_time_now (&tm->clib_time);
1189
1190   /* Prime the pump */
1191   for (i = 0; i < tm->ntimers; i++)
1192     {
1193       pool_get (tm->test_elts, e);
1194       clib_memset (e, 0, sizeof (*e));
1195
1196       expiration_time = 512;
1197
1198       if (expiration_time > max_expiration_time)
1199         max_expiration_time = expiration_time;
1200
1201       e->expected_to_expire = expiration_time + initial_wheel_offset;
1202       e->stop_timer_handle =
1203         tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
1204                                      14 /* timer id */ ,
1205                                      expiration_time);
1206     }
1207
1208   adds = 1;
1209
1210   vec_free (deleted_indices);
1211
1212   run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
1213
1214   after = clib_time_now (&tm->clib_time);
1215
1216   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
1217            tm->double_wheel.current_tick);
1218   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
1219            (after - before),
1220            ((f64) adds + (f64) deletes +
1221             (f64) tm->double_wheel.current_tick) / (after - before));
1222
1223   if (pool_elts (tm->test_elts))
1224     fformat (stdout, "Note: %d elements remain in pool\n",
1225              pool_elts (tm->test_elts));
1226
1227   pool_foreach (e, tm->test_elts)
1228    {
1229     fformat (stdout, "[%d] expected to expire %d\n",
1230              e - tm->test_elts,
1231              e->expected_to_expire);
1232   }
1233
1234   pool_free (tm->test_elts);
1235   tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
1236   return 0;
1237 }
1238
1239 static clib_error_t *
1240 test5_double (tw_timer_test_main_t * tm)
1241 {
1242   u32 i;
1243   tw_timer_test_elt_t *e;
1244   u32 initial_wheel_offset;
1245   u32 expiration_time;
1246   u32 max_expiration_time = 0;
1247   u32 adds = 0, deletes = 0;
1248   f64 before, after;
1249
1250   clib_time_init (&tm->clib_time);
1251
1252   tw_timer_wheel_init_16t_2w_512sl (&tm->double_wheel,
1253                                     expired_timer_double_callback,
1254                                     1.0 /* timer interval */ , ~0);
1255
1256   /* Prime offset */
1257   initial_wheel_offset = 7567;
1258
1259   run_double_wheel (&tm->double_wheel, initial_wheel_offset);
1260
1261   fformat (stdout, "initial wheel time %d, fast index %d slow index %d\n",
1262            tm->double_wheel.current_tick,
1263            tm->double_wheel.current_index[TW_TIMER_RING_FAST],
1264            tm->double_wheel.current_index[TW_TIMER_RING_SLOW]);
1265
1266   initial_wheel_offset = tm->double_wheel.current_tick;
1267
1268   fformat (stdout,
1269            "test %d timers, %d iter, %d ticks per iter, 0x%llx seed\n",
1270            tm->ntimers, tm->niter, tm->ticks_per_iter, tm->seed);
1271
1272   before = clib_time_now (&tm->clib_time);
1273
1274   /* Prime the pump */
1275   for (i = 0; i < tm->ntimers; i++)
1276     {
1277       pool_get (tm->test_elts, e);
1278       clib_memset (e, 0, sizeof (*e));
1279
1280       expiration_time = i + 1;
1281
1282       if (expiration_time > max_expiration_time)
1283         max_expiration_time = expiration_time;
1284
1285       e->expected_to_expire = expiration_time + initial_wheel_offset;
1286       e->stop_timer_handle =
1287         tw_timer_start_16t_2w_512sl (&tm->double_wheel, e - tm->test_elts,
1288                                      14 /* timer id */ ,
1289                                      expiration_time);
1290     }
1291
1292   adds += i;
1293
1294   run_double_wheel (&tm->double_wheel, max_expiration_time + 1);
1295
1296   after = clib_time_now (&tm->clib_time);
1297
1298   fformat (stdout, "%d adds, %d deletes, %d ticks\n", adds, deletes,
1299            tm->double_wheel.current_tick);
1300   fformat (stdout, "test ran %.2f seconds, %.2f ops/second\n",
1301            (after - before),
1302            ((f64) adds + (f64) deletes +
1303             (f64) tm->double_wheel.current_tick) / (after - before));
1304
1305   if (pool_elts (tm->test_elts))
1306     fformat (stdout, "Note: %d elements remain in pool\n",
1307              pool_elts (tm->test_elts));
1308
1309   pool_foreach (e, tm->test_elts)
1310    {
1311     fformat (stdout, "[%d] expected to expire %d\n",
1312              e - tm->test_elts,
1313              e->expected_to_expire);
1314   }
1315
1316   pool_free (tm->test_elts);
1317   tw_timer_wheel_free_16t_2w_512sl (&tm->double_wheel);
1318   return 0;
1319 }
1320
1321 static clib_error_t *
1322 timer_test_command_fn (tw_timer_test_main_t * tm, unformat_input_t * input)
1323 {
1324
1325   int is_test1 = 0, is_updates = 0;
1326   int num_wheels = 1;
1327   int is_test2 = 0;
1328   int is_test3 = 0;
1329   int is_test4 = 0;
1330   int is_test5 = 0;
1331   int overflow = 0;
1332
1333   clib_memset (tm, 0, sizeof (*tm));
1334   /* Default values */
1335   tm->ntimers = 100000;
1336   tm->seed = 0xDEADDABEB00BFACE;
1337   tm->niter = 1000;
1338   tm->ticks_per_iter = 727;
1339
1340   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1341     {
1342       if (unformat (input, "seed %lld", &tm->seed))
1343         ;
1344       else if (unformat (input, "test1"))
1345         is_test1 = 1;
1346       else if (unformat (input, "test2"))
1347         is_test2 = 1;
1348       else if (unformat (input, "overflow"))
1349         overflow = 1;
1350       else if (unformat (input, "lebron"))
1351         is_test3 = 1;
1352       else if (unformat (input, "wilt"))
1353         is_test4 = 1;
1354       else if (unformat (input, "linear"))
1355         is_test5 = 1;
1356       else if (unformat (input, "updates"))
1357         is_updates = 1;
1358       else if (unformat (input, "wheels %d", &num_wheels))
1359         ;
1360       else if (unformat (input, "ntimers %d", &tm->ntimers))
1361         ;
1362       else if (unformat (input, "niter %d", &tm->niter))
1363         ;
1364       else if (unformat (input, "ticks_per_iter %d", &tm->ticks_per_iter))
1365         ;
1366       else
1367         break;
1368     }
1369
1370   if (is_test1 + is_test2 + is_test3 + is_test4 + is_test5 == 0)
1371     return clib_error_return (0, "No test specified [test1..n]");
1372
1373   if (num_wheels < 1 || num_wheels > 3)
1374     return clib_error_return (0, "unsupported... 1 or 2 wheels only");
1375
1376   if (is_test1)
1377     {
1378       if (num_wheels == 1)
1379         return test1_single (tm);
1380       else
1381         {
1382           (void) test1_double (tm);
1383           return test1_two_timer_double (tm);
1384         }
1385     }
1386   if (is_test2)
1387     {
1388       if (num_wheels == 1)
1389         return test2_single (tm);
1390       else if (num_wheels == 2)
1391         if (is_updates)
1392           return test2_double_updates (tm);
1393         else
1394           return test2_double (tm);
1395       else if (num_wheels == 3)
1396         {
1397           if (overflow == 0)
1398             return test2_triple (tm);
1399           else
1400             return test2_triple_ov (tm);
1401         }
1402     }
1403   if (is_test3)
1404     return test3_triple_double (tm);
1405
1406   if (is_test4)
1407     return test4_double_double (tm);
1408
1409   if (is_test5)
1410     return test5_double (tm);
1411
1412   /* NOTREACHED */
1413   return 0;
1414 }
1415
1416 #ifdef CLIB_UNIX
1417 int
1418 main (int argc, char *argv[])
1419 {
1420   unformat_input_t i;
1421   clib_error_t *error;
1422   tw_timer_test_main_t *tm = &tw_timer_test_main;
1423
1424   clib_mem_init (0, 3ULL << 30);
1425
1426   unformat_init_command_line (&i, argv);
1427   error = timer_test_command_fn (tm, &i);
1428   unformat_free (&i);
1429
1430   if (error)
1431     {
1432       clib_error_report (error);
1433       return 1;
1434     }
1435   return 0;
1436 }
1437 #endif /* CLIB_UNIX */
1438
1439 /* For debugging... */
1440 int
1441 pifi (void *p, u32 index)
1442 {
1443   return pool_is_free_index (p, index);
1444 }
1445
1446 u32
1447 vl (void *p)
1448 {
1449   return vec_len (p);
1450 }
1451
1452 uword
1453 pe (void *v)
1454 {
1455   return (pool_elts (v));
1456 }
1457
1458 /*
1459  * fd.io coding-style-patch-verification: ON
1460  *
1461  * Local Variables:
1462  * eval: (c-set-style "gnu")
1463  * End:
1464  */