API Reference Manual  1.46.0
odp_timer_perf.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2019-2023 Nokia
3  */
4 
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdint.h>
16 #include <inttypes.h>
17 #include <signal.h>
18 #include <stdlib.h>
19 #include <getopt.h>
20 
21 #include <odp_api.h>
22 #include <odp/helper/odph_api.h>
23 
24 #define MODE_SCHED_OVERH 0
25 #define MODE_START_CANCEL 1
26 #define MODE_START_EXPIRE 2
27 #define MAX_TIMER_POOLS 32
28 #define MAX_TIMERS 10000
29 #define START_NS (100 * ODP_TIME_MSEC_IN_NS)
30 
31 typedef struct test_options_t {
32  uint32_t num_cpu;
33  uint32_t num_tp;
34  uint32_t num_timer;
35  uint64_t res_ns;
36  uint64_t period_ns;
37  int shared;
38  int mode;
39  uint64_t test_rounds;
40 
41 } test_options_t;
42 
43 typedef struct time_stat_t {
44  uint64_t num;
45  uint64_t sum_ns;
46  uint64_t max_ns;
47 
48 } time_stat_t;
49 
50 typedef struct test_stat_t {
51  uint64_t rounds;
52  uint64_t events;
53  uint64_t nsec;
54  uint64_t cycles_0;
55  uint64_t cycles_1;
56 
57  uint64_t cancels;
58  uint64_t sets;
59 
60  time_stat_t before;
61  time_stat_t after;
62 
63 } test_stat_t;
64 
65 typedef struct test_stat_sum_t {
66  uint64_t rounds;
67  uint64_t events;
68  uint64_t nsec;
69  uint64_t cycles_0;
70  uint64_t cycles_1;
71 
72  uint64_t cancels;
73  uint64_t sets;
74 
75  time_stat_t before;
76  time_stat_t after;
77 
78  double time_ave;
79  uint32_t num;
80 
81 } test_stat_sum_t;
82 
83 typedef struct thread_arg_t {
84  void *global;
85  int worker_idx;
86 
87 } thread_arg_t;
88 
89 typedef struct timer_ctx_t {
90  uint64_t target_ns;
91  uint64_t target_tick;
92  uint32_t tp_idx;
93  uint32_t timer_idx;
94  int last;
95 
96 } timer_ctx_t;
97 
98 typedef struct timer_pool_t {
100  uint64_t start_tick;
101  uint64_t period_tick;
102 
103 } timer_pool_t;
104 
105 typedef struct test_global_t {
106  test_options_t test_options;
107  odp_atomic_u32_t exit_test;
108  odp_atomic_u32_t timers_started;
109  odp_barrier_t barrier;
110  odp_cpumask_t cpumask;
111  timer_pool_t timer_pool[MAX_TIMER_POOLS];
112  odp_pool_t pool[MAX_TIMER_POOLS];
113  odp_queue_t queue[MAX_TIMER_POOLS];
114  odp_timer_t timer[MAX_TIMER_POOLS][MAX_TIMERS];
115  timer_ctx_t timer_ctx[MAX_TIMER_POOLS][MAX_TIMERS];
116  odph_thread_t thread_tbl[ODP_THREAD_COUNT_MAX];
117  test_stat_t stat[ODP_THREAD_COUNT_MAX];
118  thread_arg_t thread_arg[ODP_THREAD_COUNT_MAX];
119  test_stat_sum_t stat_sum;
120 
121 } test_global_t;
122 
123 test_global_t *test_global;
124 
125 static void print_usage(void)
126 {
127  printf("\n"
128  "Timer performance test\n"
129  "\n"
130  "Usage: odp_timer_perf [options]\n"
131  "\n"
132  " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default: 1\n"
133  " -n, --num_tp Number of timer pools. Default: 1\n"
134  " -t, --num_timer Number of timers per timer pool. Default: 10\n"
135  " -r, --res_ns Resolution in nsec. Default: 10000000\n"
136  " -p, --period_ns Timeout period in nsec. Default: 100000000\n"
137  " -s, --shared Shared vs private timer pool. Currently, private pools can be\n"
138  " tested only with single CPU. Default: 1\n"
139  " 0: Private timer pools\n"
140  " 1: Shared timer pools\n"
141  " -m, --mode Select test mode. Default: 0\n"
142  " 0: Measure odp_schedule() overhead when using timers\n"
143  " 1: Measure timer set + cancel performance\n"
144  " 2: Measure schedule and timer start overhead while continuously\n"
145  " restarting expiring timers\n"
146  " -R, --rounds Number of test rounds in timer set + cancel test.\n"
147  " Default: 100000\n"
148  " -h, --help This help\n"
149  "\n");
150 }
151 
152 static int parse_options(int argc, char *argv[], test_options_t *test_options)
153 {
154  int opt;
155  int ret = 0;
156 
157  static const struct option longopts[] = {
158  {"num_cpu", required_argument, NULL, 'c'},
159  {"num_tp ", required_argument, NULL, 'n'},
160  {"num_timer", required_argument, NULL, 't'},
161  {"res_ns", required_argument, NULL, 'r'},
162  {"period_ns", required_argument, NULL, 'p'},
163  {"shared", required_argument, NULL, 's'},
164  {"mode", required_argument, NULL, 'm'},
165  {"rounds", required_argument, NULL, 'R'},
166  {"help", no_argument, NULL, 'h'},
167  {NULL, 0, NULL, 0}
168  };
169 
170  static const char *shortopts = "+c:n:t:r:p:s:m:R:h";
171 
172  test_options->num_cpu = 1;
173  test_options->num_tp = 1;
174  test_options->num_timer = 10;
175  test_options->res_ns = 10 * ODP_TIME_MSEC_IN_NS;
176  test_options->period_ns = 100 * ODP_TIME_MSEC_IN_NS;
177  test_options->shared = 1;
178  test_options->mode = 0;
179  test_options->test_rounds = 100000;
180 
181  while (1) {
182  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
183 
184  if (opt == -1)
185  break;
186 
187  switch (opt) {
188  case 'c':
189  test_options->num_cpu = atoi(optarg);
190  break;
191  case 'n':
192  test_options->num_tp = atoi(optarg);
193  break;
194  case 't':
195  test_options->num_timer = atoi(optarg);
196  break;
197  case 'r':
198  test_options->res_ns = atoll(optarg);
199  break;
200  case 'p':
201  test_options->period_ns = atoll(optarg);
202  break;
203  case 's':
204  test_options->shared = atoi(optarg);
205  break;
206  case 'm':
207  test_options->mode = atoi(optarg);
208  break;
209  case 'R':
210  test_options->test_rounds = atoll(optarg);
211  break;
212  case 'h':
213  /* fall through */
214  default:
215  print_usage();
216  ret = -1;
217  break;
218  }
219  }
220 
221  if (test_options->num_timer > MAX_TIMERS) {
222  ODPH_ERR("Too many timers. Max %u\n", MAX_TIMERS);
223  ret = -1;
224  }
225 
226  return ret;
227 }
228 
229 static int set_num_cpu(test_global_t *global)
230 {
231  int ret;
232  test_options_t *test_options = &global->test_options;
233  int num_cpu = test_options->num_cpu;
234  int shared = test_options->shared;
235 
236  /* One thread used for the main thread */
237  if (num_cpu > ODP_THREAD_COUNT_MAX - 1) {
238  ODPH_ERR("Too many workers. Maximum is %i.\n", ODP_THREAD_COUNT_MAX - 1);
239  return -1;
240  }
241 
242  ret = odp_cpumask_default_worker(&global->cpumask, num_cpu);
243 
244  if (num_cpu && ret != num_cpu) {
245  ODPH_ERR("Too many workers. Max supported %i\n.", ret);
246  return -1;
247  }
248 
249  if (shared == 0 && num_cpu != 1) {
250  ODPH_ERR("Private pool test supports only single CPU\n.");
251  return -1;
252  }
253 
254  /* Zero: all available workers */
255  if (num_cpu == 0) {
256  num_cpu = ret;
257  test_options->num_cpu = num_cpu;
258  }
259 
260  if (shared) /* Main thread + all workers */
261  odp_barrier_init(&global->barrier, num_cpu + 1);
262  else /* Only the main thread */
263  odp_barrier_init(&global->barrier, 1);
264 
265  return 0;
266 }
267 
268 static int create_timer_pools(test_global_t *global)
269 {
270  odp_timer_capability_t timer_capa;
271  odp_timer_res_capability_t timer_res_capa;
272  odp_timer_pool_param_t timer_pool_param;
273  odp_timer_pool_t tp;
274  odp_queue_param_t queue_param;
275  odp_queue_t queue;
276  odp_pool_param_t pool_param;
277  odp_pool_t pool;
278  uint64_t max_tmo_ns, min_tmo_ns;
279  uint32_t i, j;
280  uint32_t max_timers;
281  int priv;
282  test_options_t *test_options = &global->test_options;
283  uint32_t num_cpu = test_options->num_cpu;
284  uint32_t num_tp = test_options->num_tp;
285  uint32_t num_timer = test_options->num_timer;
286  uint64_t res_ns = test_options->res_ns;
287  uint64_t period_ns = test_options->period_ns;
288  int mode = test_options->mode;
289  char tp_name[] = "timer_pool_00";
290 
291  max_tmo_ns = START_NS + (num_timer * period_ns);
292  min_tmo_ns = START_NS / 2;
293 
294  if (test_options->mode == MODE_START_EXPIRE) {
295  /*
296  * Timers are set to 1-2 periods from current time. Add an
297  * arbitrary margin of one period, resulting in maximum of
298  * three periods.
299  */
300  max_tmo_ns = period_ns * 3;
301  min_tmo_ns = test_options->res_ns / 2;
302  }
303 
304  priv = 0;
305  if (test_options->shared == 0)
306  priv = 1;
307 
308  printf("\nTimer performance test\n");
309  printf(" mode %i\n", mode);
310  printf(" num cpu %u\n", num_cpu);
311  printf(" private pool %i\n", priv);
312  printf(" num timer pool %u\n", num_tp);
313  printf(" num timer %u\n", num_timer);
314  printf(" resolution %" PRIu64 " nsec\n", res_ns);
315  printf(" period %" PRIu64 " nsec\n", period_ns);
316  printf(" max timeout %" PRIu64 " nsec\n", max_tmo_ns);
317  printf(" min timeout %" PRIu64 " nsec\n", min_tmo_ns);
318  printf(" first timer at %.2f sec\n", (double)START_NS / ODP_TIME_SEC_IN_NS);
319  if (mode == MODE_SCHED_OVERH)
320  printf(" test duration %.2f sec\n", (double)max_tmo_ns / ODP_TIME_SEC_IN_NS);
321  else
322  printf(" test rounds %" PRIu64 "\n", test_options->test_rounds);
323 
324  for (i = 0; i < MAX_TIMER_POOLS; i++) {
325  global->timer_pool[i].tp = ODP_TIMER_POOL_INVALID;
326  global->pool[i] = ODP_POOL_INVALID;
327  global->queue[i] = ODP_QUEUE_INVALID;
328 
329  for (j = 0; j < MAX_TIMERS; j++)
330  global->timer[i][j] = ODP_TIMER_INVALID;
331  }
332 
333  if (odp_timer_capability(ODP_CLOCK_DEFAULT, &timer_capa)) {
334  ODPH_ERR("Timer capability failed\n");
335  return -1;
336  }
337 
338  memset(&timer_res_capa, 0, sizeof(odp_timer_res_capability_t));
339  timer_res_capa.res_ns = res_ns;
340  if (odp_timer_res_capability(ODP_CLOCK_DEFAULT, &timer_res_capa)) {
341  ODPH_ERR("Timer resolution capability failed\n");
342  return -1;
343  }
344 
345  if (res_ns < timer_capa.max_res.res_ns) {
346  ODPH_ERR("Too high resolution\n");
347  return -1;
348  }
349 
350  if (min_tmo_ns < timer_res_capa.min_tmo) {
351  ODPH_ERR("Too short min timeout\n");
352  return -1;
353  }
354 
355  if (max_tmo_ns > timer_res_capa.max_tmo) {
356  ODPH_ERR("Too long max timeout\n");
357  return -1;
358  }
359 
360  max_timers = timer_capa.max_timers;
361  if (max_timers && num_timer > max_timers) {
362  ODPH_ERR("Too many timers (max %u)\n", max_timers);
363  return -1;
364  }
365 
366  if (num_tp > timer_capa.max_pools) {
367  ODPH_ERR("Too many timer pools (max %u)\n", timer_capa.max_pools);
368  return -1;
369  }
370 
371  odp_timer_pool_param_init(&timer_pool_param);
372  timer_pool_param.res_ns = res_ns;
373  timer_pool_param.min_tmo = min_tmo_ns;
374  timer_pool_param.max_tmo = max_tmo_ns;
375  timer_pool_param.num_timers = num_timer;
376  timer_pool_param.priv = priv;
377  timer_pool_param.clk_src = ODP_CLOCK_DEFAULT;
378 
379  odp_pool_param_init(&pool_param);
380  pool_param.type = ODP_POOL_TIMEOUT;
381  pool_param.tmo.num = num_timer;
382 
383  odp_queue_param_init(&queue_param);
384  queue_param.type = ODP_QUEUE_TYPE_SCHED;
385  queue_param.sched.prio = odp_schedule_default_prio();
386  queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;
387  queue_param.sched.group = ODP_SCHED_GROUP_ALL;
388 
389  for (i = 0; i < num_tp; i++) {
390  if (num_tp < 100) {
391  tp_name[11] = '0' + i / 10;
392  tp_name[12] = '0' + i % 10;
393  }
394 
395  tp = odp_timer_pool_create(tp_name, &timer_pool_param);
396  global->timer_pool[i].tp = tp;
397  if (tp == ODP_TIMER_POOL_INVALID) {
398  ODPH_ERR("Timer pool create failed (%u)\n", i);
399  return -1;
400  }
401 
402  if (odp_timer_pool_start_multi(&tp, 1) != 1) {
403  ODPH_ERR("Timer pool start failed (%u)\n", i);
404  return -1;
405  }
406 
407  pool = odp_pool_create(tp_name, &pool_param);
408  global->pool[i] = pool;
409  if (pool == ODP_POOL_INVALID) {
410  ODPH_ERR("Pool create failed (%u)\n", i);
411  return -1;
412  }
413 
414  queue = odp_queue_create(tp_name, &queue_param);
415  global->queue[i] = queue;
416  if (queue == ODP_QUEUE_INVALID) {
417  ODPH_ERR("Queue create failed (%u)\n", i);
418  return -1;
419  }
420 
421  global->timer_pool[i].period_tick = odp_timer_ns_to_tick(tp,
422  test_options->period_ns);
423  global->timer_pool[i].start_tick = odp_timer_ns_to_tick(tp, START_NS);
424  }
425 
426  printf(" start %" PRIu64 " tick\n", global->timer_pool[0].start_tick);
427  printf(" period %" PRIu64 " ticks\n", global->timer_pool[0].period_tick);
428  printf("\n");
429 
430  return 0;
431 }
432 
433 static int set_timers(test_global_t *global)
434 {
435  odp_timer_pool_info_t timer_pool_info;
436  odp_timer_pool_t tp;
437  odp_timer_t timer;
438  odp_pool_t pool;
439  odp_queue_t queue;
440  odp_time_t time;
441  uint64_t tick_cur, nsec, time_ns;
442  uint64_t max_tmo_ns;
443  uint32_t i, j;
444  test_options_t *test_options = &global->test_options;
445  uint32_t num_tp = test_options->num_tp;
446  uint32_t num_timer = test_options->num_timer;
447  uint64_t period_ns = test_options->period_ns;
448 
449  max_tmo_ns = START_NS + (num_timer * period_ns);
450 
451  for (i = 0; i < num_tp; i++) {
452  tp = global->timer_pool[i].tp;
453  pool = global->pool[i];
454  queue = global->queue[i];
455 
456  nsec = max_tmo_ns;
457  tick_cur = odp_timer_current_tick(tp);
458  time = odp_time_global();
459  time_ns = odp_time_to_ns(time);
460 
461  for (j = 0; j < num_timer; j++) {
462  uint64_t tick_ns;
463  odp_timeout_t timeout;
464  odp_event_t ev;
465  int status;
466  timer_ctx_t *ctx = &global->timer_ctx[i][j];
467  odp_timer_start_t start_param;
468 
469  /* Set timers backwards, the last timer is set first */
470  if (j == 0)
471  ctx->last = 1;
472 
473  ctx->target_ns = time_ns + nsec;
474  ctx->tp_idx = i;
475  ctx->timer_idx = j;
476 
477  timeout = odp_timeout_alloc(pool);
478  ev = odp_timeout_to_event(timeout);
479 
480  timer = odp_timer_alloc(tp, queue, ctx);
481  global->timer[i][j] = timer;
482 
483  tick_ns = odp_timer_ns_to_tick(tp, nsec);
484  nsec = nsec - period_ns;
485 
486  start_param.tick_type = ODP_TIMER_TICK_ABS;
487  start_param.tick = tick_cur + tick_ns;
488  start_param.tmo_ev = ev;
489 
490  if (test_options->mode == MODE_START_EXPIRE) {
491  uint64_t offset_ns = period_ns + j * period_ns / num_timer;
492 
493  ctx->target_ns = time_ns + offset_ns;
494  ctx->target_tick = tick_cur + odp_timer_ns_to_tick(tp, offset_ns);
495  start_param.tick = ctx->target_tick;
496  }
497 
498  status = odp_timer_start(timer, &start_param);
499  if (status != ODP_TIMER_SUCCESS) {
500  ODPH_ERR("Timer set %i/%i (ret %i)\n", i, j, status);
501  return -1;
502  }
503  }
504 
505  if (odp_timer_pool_info(tp, &timer_pool_info)) {
506  ODPH_ERR("Timer pool info failed\n");
507  return -1;
508  }
509 
510  printf("Timer pool info [%i]:\n", i);
511  printf(" cur_timers %u\n", timer_pool_info.cur_timers);
512  printf(" hwm_timers %u\n", timer_pool_info.hwm_timers);
513  printf("\n");
514  }
515 
516  return 0;
517 }
518 
519 static int destroy_timer_pool(test_global_t *global)
520 {
521  odp_timer_pool_t tp;
522  odp_pool_t pool;
523  odp_queue_t queue;
524  odp_timer_t timer;
525  uint32_t i, j;
526  test_options_t *test_options = &global->test_options;
527  uint32_t num_timer = test_options->num_timer;
528  uint32_t num_tp = test_options->num_tp;
529 
530  for (i = 0; i < num_tp; i++) {
531  for (j = 0; j < num_timer; j++) {
532  timer = global->timer[i][j];
533 
534  if (timer == ODP_TIMER_INVALID)
535  break;
536 
537  if (odp_timer_free(timer))
538  printf("Timer free failed: %i/%i\n", i, j);
539  }
540 
541  queue = global->queue[i];
542  if (queue != ODP_QUEUE_INVALID)
543  odp_queue_destroy(queue);
544 
545  pool = global->pool[i];
546  if (pool != ODP_POOL_INVALID)
547  odp_pool_destroy(pool);
548 
549  tp = global->timer_pool[i].tp;
550  if (tp != ODP_TIMER_POOL_INVALID)
552  }
553 
554  return 0;
555 }
556 
557 static int sched_mode_worker(void *arg)
558 {
559  int thr;
560  uint32_t exit_test;
561  odp_event_t ev;
562  odp_timeout_t tmo;
563  uint64_t c2, diff, nsec, time_ns, target_ns;
564  odp_time_t t1, t2, time;
565  time_stat_t before, after;
566  timer_ctx_t *ctx;
567  thread_arg_t *thread_arg = arg;
568  test_global_t *global = thread_arg->global;
569  test_options_t *test_options = &global->test_options;
570  uint32_t num_tp = test_options->num_tp;
571  uint64_t cycles = 0;
572  uint64_t events = 0;
573  uint64_t rounds = 0;
574  uint64_t c1 = 0;
575  int meas = 1;
576  int ret = 0;
577 
578  memset(&before, 0, sizeof(time_stat_t));
579  memset(&after, 0, sizeof(time_stat_t));
580 
581  thr = odp_thread_id();
582 
583  /* Start all workers at the same time */
584  odp_barrier_wait(&global->barrier);
585 
586  t1 = odp_time_local();
587 
588  while (1) {
589  if (meas) {
590  c1 = odp_cpu_cycles();
591  meas = 0;
592  }
593 
594  ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
595  rounds++;
596 
597  exit_test = odp_atomic_load_u32(&global->exit_test);
598  if (odp_likely(ev == ODP_EVENT_INVALID && exit_test < num_tp))
599  continue;
600 
601  c2 = odp_cpu_cycles();
602  diff = odp_cpu_cycles_diff(c2, c1);
603  cycles += diff;
604 
605  if (ev == ODP_EVENT_INVALID && exit_test >= num_tp)
606  break;
607 
608  time = odp_time_global();
609  time_ns = odp_time_to_ns(time);
610  events++;
611  meas = 1;
612 
613  tmo = odp_timeout_from_event(ev);
614  ctx = odp_timeout_user_ptr(tmo);
615  odp_timeout_free(tmo);
616 
617  target_ns = ctx->target_ns;
618  if (time_ns < target_ns) {
619  diff = target_ns - time_ns;
620  before.num++;
621  before.sum_ns += diff;
622  if (diff > before.max_ns)
623  before.max_ns = diff;
624 
625  ODPH_DBG("before %" PRIu64 "\n", diff);
626  } else {
627  diff = time_ns - target_ns;
628  after.num++;
629  after.sum_ns += diff;
630  if (diff > after.max_ns)
631  after.max_ns = diff;
632 
633  ODPH_DBG("after %" PRIu64 "\n", time_ns - target_ns);
634  }
635 
636  if (ctx->last)
637  odp_atomic_inc_u32(&global->exit_test);
638  }
639 
640  t2 = odp_time_local();
641  nsec = odp_time_diff_ns(t2, t1);
642 
643  /* Update stats*/
644  global->stat[thr].events = events;
645  global->stat[thr].cycles_0 = cycles;
646  global->stat[thr].rounds = rounds;
647  global->stat[thr].nsec = nsec;
648  global->stat[thr].before = before;
649  global->stat[thr].after = after;
650 
651  return ret;
652 }
653 
654 static int cancel_timers(test_global_t *global, uint32_t worker_idx)
655 {
656  uint32_t i, j;
657  int r;
658  odp_timer_t timer;
659  odp_event_t ev;
660  test_options_t *test_options = &global->test_options;
661  uint32_t num_tp = test_options->num_tp;
662  uint32_t num_timer = test_options->num_timer;
663  uint32_t num_worker = test_options->num_cpu;
664  int ret = 0;
665 
666  for (i = 0; i < num_tp; i++) {
667  for (j = worker_idx; j < num_timer; j += num_worker) {
668  timer = global->timer[i][j];
669  if (timer == ODP_TIMER_INVALID)
670  continue;
671 
672  r = odp_timer_cancel(timer, &ev);
673 
674  if (r == ODP_TIMER_SUCCESS) {
675  odp_event_free(ev);
676  } else if (r == ODP_TIMER_TOO_NEAR) {
677  ret = 1;
678  } else {
679  ret = -1;
680  break;
681  }
682  }
683  }
684 
685  return ret;
686 }
687 
688 static int set_cancel_mode_worker(void *arg)
689 {
690  uint64_t tick, start_tick, period_tick, nsec;
691  uint64_t c1, c2;
692  int thr, status;
693  uint32_t i, j, worker_idx;
694  odp_event_t ev;
695  odp_time_t t1, t2;
696  odp_timer_t timer;
697  odp_timer_pool_t tp;
698  odp_timeout_t tmo;
699  odp_timer_start_t start_param;
700  thread_arg_t *thread_arg = arg;
701  test_global_t *global = thread_arg->global;
702  test_options_t *test_options = &global->test_options;
703  uint32_t num_tp = test_options->num_tp;
704  uint32_t num_timer = test_options->num_timer;
705  uint32_t num_worker = test_options->num_cpu;
706  int ret = 0;
707  int started = 0;
708  uint64_t test_rounds = test_options->test_rounds;
709  uint64_t num_tmo = 0;
710  uint64_t num_cancel = 0;
711  uint64_t num_set = 0;
712  uint64_t cancel_cycles = 0, start_cycles = 0;
713  odp_event_t ev_tbl[MAX_TIMERS];
714 
715  thr = odp_thread_id();
716  worker_idx = thread_arg->worker_idx;
717  t1 = ODP_TIME_NULL;
718 
719  /* Start all workers at the same time */
720  odp_barrier_wait(&global->barrier);
721 
722  while (1) {
723  ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
724 
725  if (odp_unlikely(ev != ODP_EVENT_INVALID)) {
726  /* Timeout, set timer again. When start_tick is large enough, this should
727  * not happen. */
728  timer_ctx_t *ctx;
729 
730  tmo = odp_timeout_from_event(ev);
731  ctx = odp_timeout_user_ptr(tmo);
732  i = ctx->tp_idx;
733  j = ctx->timer_idx;
734  timer = global->timer[i][j];
735  start_tick = global->timer_pool[i].start_tick;
736  period_tick = global->timer_pool[i].period_tick;
737  tick = start_tick + j * period_tick;
738 
739  start_param.tick_type = ODP_TIMER_TICK_REL;
740  start_param.tick = tick;
741  start_param.tmo_ev = ev;
742 
743  status = odp_timer_start(timer, &start_param);
744  num_tmo++;
745  num_set++;
746 
747  if (status != ODP_TIMER_SUCCESS) {
748  ODPH_ERR("Timer set (tmo) failed (ret %i)\n", status);
749  ret = -1;
750  break;
751  }
752 
753  continue;
754  }
755 
756  if (odp_unlikely(odp_atomic_load_u32(&global->exit_test)))
757  break;
758 
759  if (odp_unlikely(started == 0)) {
760  /* Run schedule loop while waiting for timers to be created */
761  if (odp_atomic_load_acq_u32(&global->timers_started) == 0)
762  continue;
763 
764  /* Start measurements */
765  started = 1;
766  t1 = odp_time_local();
767  }
768 
769  /* Cancel and set timers again */
770  for (i = 0; i < num_tp; i++) {
771  tp = global->timer_pool[i].tp;
772  if (tp == ODP_TIMER_POOL_INVALID)
773  continue;
774 
775  start_tick = global->timer_pool[i].start_tick;
776  period_tick = global->timer_pool[i].period_tick;
777 
778  tick = odp_timer_current_tick(tp) + start_tick;
779  c1 = odp_cpu_cycles();
780 
781  for (j = worker_idx; j < num_timer; j += num_worker) {
782  ev_tbl[j] = ODP_EVENT_INVALID;
783 
784  timer = global->timer[i][j];
785  if (timer == ODP_TIMER_INVALID)
786  continue;
787 
788  status = odp_timer_cancel(timer, &ev_tbl[j]);
789  num_cancel++;
790 
791  if (odp_unlikely(status == ODP_TIMER_TOO_NEAR)) {
792  continue;
793  } else if (odp_unlikely(status != ODP_TIMER_SUCCESS)) {
794  ODPH_ERR("Timer (%u/%u) cancel failed (ret %i)\n", i, j,
795  status);
796  ret = -1;
797  break;
798  }
799  }
800 
801  c2 = odp_cpu_cycles();
802  cancel_cycles += odp_cpu_cycles_diff(c2, c1);
803  c1 = c2;
804 
805  for (j = worker_idx; j < num_timer; j += num_worker) {
806  if (ev_tbl[j] == ODP_EVENT_INVALID)
807  continue;
808 
809  timer = global->timer[i][j];
810  if (timer == ODP_TIMER_INVALID)
811  continue;
812 
813  start_param.tick_type = ODP_TIMER_TICK_ABS;
814  start_param.tick = tick + j * period_tick;
815  start_param.tmo_ev = ev_tbl[j];
816 
817  status = odp_timer_start(timer, &start_param);
818  num_set++;
819 
820  if (status != ODP_TIMER_SUCCESS) {
821  ODPH_ERR("Timer (%u/%u) set failed (ret %i)\n", i, j,
822  status);
823  ret = -1;
824  break;
825  }
826  }
827 
828  c2 = odp_cpu_cycles();
829  start_cycles += odp_cpu_cycles_diff(c2, c1);
830  }
831 
832  if (test_rounds) {
833  test_rounds--;
834  if (test_rounds == 0)
835  break;
836  }
837  }
838 
839  t2 = odp_time_local();
840  nsec = odp_time_diff_ns(t2, t1);
841 
842  /* Cancel all timers that belong to this thread */
843  if (cancel_timers(global, worker_idx))
844  ODPH_ERR("Timer cancel failed\n");
845 
846  /* Update stats */
847  global->stat[thr].events = num_tmo;
848  global->stat[thr].rounds = test_options->test_rounds - test_rounds;
849  global->stat[thr].nsec = nsec;
850  global->stat[thr].cycles_0 = cancel_cycles;
851  global->stat[thr].cycles_1 = start_cycles;
852 
853  global->stat[thr].cancels = num_cancel;
854  global->stat[thr].sets = num_set;
855 
856  return ret;
857 }
858 
859 static int set_expire_mode_worker(void *arg)
860 {
861  int status, thr;
862  uint32_t i, j, exit_test;
863  odp_event_t ev;
864  odp_timeout_t tmo;
865  uint64_t c2, c3, c4, diff, nsec, time_ns, target_ns, period_tick, wait;
866  odp_timer_t timer;
867  odp_timer_start_t start_param;
868  odp_time_t t1, t2;
869  time_stat_t before, after;
870  timer_ctx_t *ctx;
871  thread_arg_t *thread_arg = arg;
872  test_global_t *global = thread_arg->global;
873  test_options_t *opt = &global->test_options;
874  uint32_t num_tp = opt->num_tp;
875  uint64_t sched_cycles = 0;
876  uint64_t start_cycles = 0;
877  uint64_t events = 0;
878  uint64_t rounds = 0;
879  uint64_t c1 = 0;
880  int meas = 1;
881  int ret = 0;
882 
883  memset(&before, 0, sizeof(time_stat_t));
884  memset(&after, 0, sizeof(time_stat_t));
885 
886  thr = odp_thread_id();
887 
888  /* Start all workers at the same time */
889  odp_barrier_wait(&global->barrier);
890 
891  t1 = odp_time_local();
892 
893  while (events < opt->test_rounds * opt->num_timer / opt->num_cpu) {
894  if (meas) {
895  c1 = odp_cpu_cycles();
896  meas = 0;
897  }
898 
899  ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
900  rounds++;
901 
902  exit_test = odp_atomic_load_u32(&global->exit_test);
903  if (odp_likely(ev == ODP_EVENT_INVALID && exit_test < num_tp))
904  continue;
905 
906  c2 = odp_cpu_cycles();
907  diff = odp_cpu_cycles_diff(c2, c1);
908  sched_cycles += diff;
909 
910  if (ev == ODP_EVENT_INVALID && exit_test >= num_tp)
911  break;
912 
913  events++;
914  meas = 1;
915  tmo = odp_timeout_from_event(ev);
916  ctx = odp_timeout_user_ptr(tmo);
917  i = ctx->tp_idx;
918  j = ctx->timer_idx;
919  timer = global->timer[i][j];
920  period_tick = global->timer_pool[i].period_tick;
921  time_ns = odp_time_global_ns();
922  target_ns = ctx->target_ns;
923 
924  if (time_ns < target_ns) {
925  diff = target_ns - time_ns;
926  before.num++;
927  before.sum_ns += diff;
928  if (diff > before.max_ns)
929  before.max_ns = diff;
930 
931  ODPH_DBG("before %" PRIu64 "\n", diff);
932  } else {
933  diff = time_ns - target_ns;
934  after.num++;
935  after.sum_ns += diff;
936  if (diff > after.max_ns)
937  after.max_ns = diff;
938 
939  ODPH_DBG("after %" PRIu64 "\n", diff);
940  }
941 
942  /* Start the timer again */
943  start_param.tick_type = ODP_TIMER_TICK_ABS;
944  ctx->target_ns += opt->period_ns;
945  ctx->target_tick += period_tick;
946  start_param.tick = ctx->target_tick;
947  start_param.tmo_ev = ev;
948  c3 = odp_cpu_cycles();
949 
950  status = odp_timer_start(timer, &start_param);
951 
952  c4 = odp_cpu_cycles();
953  diff = odp_cpu_cycles_diff(c4, c3);
954  start_cycles += diff;
955 
956  if (status != ODP_TIMER_SUCCESS) {
957  ODPH_ERR("Timer set (tmo) failed (ret %i)\n", status);
958  ret = -1;
959  break;
960  }
961  }
962 
963  t2 = odp_time_local();
964  nsec = odp_time_diff_ns(t2, t1);
965 
966  /* Cancel all timers that belong to this thread */
967  status = cancel_timers(global, thread_arg->worker_idx);
968 
969  wait = ODP_SCHED_NO_WAIT;
970  if (status > 0)
971  wait = odp_schedule_wait_time(opt->period_ns);
972 
973  /* Wait and free remaining events */
974  while (1) {
975  ev = odp_schedule(NULL, wait);
976  if (ev == ODP_EVENT_INVALID)
977  break;
978  odp_event_free(ev);
979  }
980 
981  /* Update stats*/
982  global->stat[thr].events = events;
983  global->stat[thr].cycles_0 = sched_cycles;
984  global->stat[thr].cycles_1 = start_cycles;
985  global->stat[thr].rounds = rounds;
986  global->stat[thr].nsec = nsec;
987  global->stat[thr].before = before;
988  global->stat[thr].after = after;
989 
990  return ret;
991 }
992 
993 static int start_workers(test_global_t *global, odp_instance_t instance)
994 {
995  odph_thread_common_param_t thr_common;
996  int i, ret;
997  test_options_t *test_options = &global->test_options;
998  int num_cpu = test_options->num_cpu;
999  odph_thread_param_t thr_param[num_cpu];
1000 
1001  memset(global->thread_tbl, 0, sizeof(global->thread_tbl));
1002  odph_thread_common_param_init(&thr_common);
1003 
1004  thr_common.instance = instance;
1005  thr_common.cpumask = &global->cpumask;
1006 
1007  for (i = 0; i < num_cpu; i++) {
1008  odph_thread_param_init(&thr_param[i]);
1009 
1010  if (test_options->mode == MODE_SCHED_OVERH)
1011  thr_param[i].start = sched_mode_worker;
1012  else if (test_options->mode == MODE_START_CANCEL)
1013  thr_param[i].start = set_cancel_mode_worker;
1014  else
1015  thr_param[i].start = set_expire_mode_worker;
1016 
1017  thr_param[i].arg = &global->thread_arg[i];
1018  thr_param[i].thr_type = ODP_THREAD_WORKER;
1019  }
1020 
1021  ret = odph_thread_create(global->thread_tbl, &thr_common, thr_param,
1022  num_cpu);
1023 
1024  if (ret != num_cpu) {
1025  ODPH_ERR("Thread create failed %i\n", ret);
1026  return -1;
1027  }
1028 
1029  return 0;
1030 }
1031 
1032 static void sum_stat(test_global_t *global)
1033 {
1034  int i;
1035  test_stat_sum_t *sum = &global->stat_sum;
1036 
1037  memset(sum, 0, sizeof(test_stat_sum_t));
1038 
1039  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1040  if (global->stat[i].rounds == 0)
1041  continue;
1042 
1043  sum->num++;
1044  sum->events += global->stat[i].events;
1045  sum->rounds += global->stat[i].rounds;
1046  sum->cycles_0 += global->stat[i].cycles_0;
1047  sum->cycles_1 += global->stat[i].cycles_1;
1048  sum->nsec += global->stat[i].nsec;
1049  sum->cancels += global->stat[i].cancels;
1050  sum->sets += global->stat[i].sets;
1051 
1052  sum->before.num += global->stat[i].before.num;
1053  sum->before.sum_ns += global->stat[i].before.sum_ns;
1054  sum->after.num += global->stat[i].after.num;
1055  sum->after.sum_ns += global->stat[i].after.sum_ns;
1056 
1057  if (global->stat[i].before.max_ns > sum->before.max_ns)
1058  sum->before.max_ns = global->stat[i].before.max_ns;
1059 
1060  if (global->stat[i].after.max_ns > sum->after.max_ns)
1061  sum->after.max_ns = global->stat[i].after.max_ns;
1062  }
1063 
1064  if (sum->num)
1065  sum->time_ave = ((double)sum->nsec / sum->num) / ODP_TIME_SEC_IN_NS;
1066 }
1067 
1068 static void print_stat_sched_mode(test_global_t *global)
1069 {
1070  int i;
1071  test_stat_sum_t *sum = &global->stat_sum;
1072  double round_ave = 0.0;
1073  double before_ave = 0.0;
1074  double after_ave = 0.0;
1075  int num = 0;
1076 
1077  printf("\n");
1078  printf("RESULTS - schedule() cycles per thread:\n");
1079  printf("----------------------------------------------\n");
1080  printf(" 1 2 3 4 5 6 7 8 9 10");
1081 
1082  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1083  if (global->stat[i].rounds) {
1084  if ((num % 10) == 0)
1085  printf("\n ");
1086 
1087  printf("%6.1f ", (double)global->stat[i].cycles_0 / global->stat[i].rounds);
1088  num++;
1089  }
1090  }
1091 
1092  printf("\n\n");
1093 
1094  if (sum->num)
1095  round_ave = (double)sum->rounds / sum->num;
1096 
1097  if (sum->before.num)
1098  before_ave = (double)sum->before.sum_ns / sum->before.num;
1099 
1100  if (sum->after.num)
1101  after_ave = (double)sum->after.sum_ns / sum->after.num;
1102 
1103  printf("TOTAL (%i workers)\n", sum->num);
1104  printf(" events: %" PRIu64 "\n", sum->events);
1105  printf(" ave time: %.2f sec\n", sum->time_ave);
1106  printf(" ave rounds per sec: %.2fM\n", (round_ave / sum->time_ave) / 1000000.0);
1107  printf(" num before: %" PRIu64 "\n", sum->before.num);
1108  printf(" ave before: %.1f nsec\n", before_ave);
1109  printf(" max before: %" PRIu64 " nsec\n", sum->before.max_ns);
1110  printf(" num after: %" PRIu64 "\n", sum->after.num);
1111  printf(" ave after: %.1f nsec\n", after_ave);
1112  printf(" max after: %" PRIu64 " nsec\n", sum->after.max_ns);
1113  printf("\n");
1114 }
1115 
1116 static void print_stat_set_cancel_mode(test_global_t *global)
1117 {
1118  int i;
1119  test_stat_sum_t *sum = &global->stat_sum;
1120  double set_ave = 0.0;
1121  int num = 0;
1122 
1123  printf("\n");
1124  printf("RESULTS\n");
1125  printf("odp_timer_cancel() cycles per thread:\n");
1126  printf("-------------------------------------------------\n");
1127  printf(" 1 2 3 4 5 6 7 8 9 10");
1128 
1129  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1130  const test_stat_t *si = &global->stat[i];
1131 
1132  if (si->cancels) {
1133  if ((num % 10) == 0)
1134  printf("\n ");
1135 
1136  printf("%6.1f ", (double)si->cycles_0 / si->cancels);
1137  num++;
1138  }
1139  }
1140 
1141  printf("\n\n");
1142 
1143  num = 0;
1144  printf("odp_timer_start() cycles per thread:\n");
1145  printf("-------------------------------------------------\n");
1146  printf(" 1 2 3 4 5 6 7 8 9 10");
1147 
1148  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1149  const test_stat_t *si = &global->stat[i];
1150 
1151  if (si->sets) {
1152  if ((num % 10) == 0)
1153  printf("\n ");
1154 
1155  printf("%6.1f ", (double)si->cycles_1 / si->sets);
1156  num++;
1157  }
1158  }
1159 
1160  if (sum->num)
1161  set_ave = (double)sum->sets / sum->num;
1162 
1163  printf("\n\n");
1164  printf("TOTAL (%i workers)\n", sum->num);
1165  printf(" rounds: %" PRIu64 "\n", sum->rounds);
1166  printf(" timeouts: %" PRIu64 "\n", sum->events);
1167  printf(" timer cancels: %" PRIu64 "\n", sum->cancels);
1168  printf(" cancels failed: %" PRIu64 "\n", sum->cancels - sum->sets);
1169  printf(" timer sets: %" PRIu64 "\n", sum->sets);
1170  printf(" ave time: %.2f sec\n", sum->time_ave);
1171  printf(" cancel+set per cpu: %.2fM per sec\n", (set_ave / sum->time_ave) / 1000000.0);
1172  printf("\n");
1173 }
1174 
1175 static void print_stat_expire_mode(test_global_t *global)
1176 {
1177  int i;
1178  test_stat_sum_t *sum = &global->stat_sum;
1179  double round_ave = 0.0;
1180  double before_ave = 0.0;
1181  double after_ave = 0.0;
1182  int num = 0;
1183 
1184  printf("\n");
1185  printf("RESULTS\n");
1186  printf("odp_schedule() cycles per thread:\n");
1187  printf("-------------------------------------------------\n");
1188  printf(" 1 2 3 4 5 6 7 8 9 10");
1189 
1190  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1191  if (global->stat[i].rounds) {
1192  if ((num % 10) == 0)
1193  printf("\n ");
1194 
1195  printf("%6.1f ", (double)global->stat[i].cycles_0 / global->stat[i].rounds);
1196  num++;
1197  }
1198  }
1199 
1200  printf("\n\n");
1201 
1202  num = 0;
1203  printf("odp_timer_start() cycles per thread:\n");
1204  printf("-------------------------------------------------\n");
1205  printf(" 1 2 3 4 5 6 7 8 9 10");
1206 
1207  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1208  if (global->stat[i].events) {
1209  if ((num % 10) == 0)
1210  printf("\n ");
1211 
1212  printf("%6.1f ", (double)global->stat[i].cycles_1 / global->stat[i].events);
1213  num++;
1214  }
1215  }
1216 
1217  printf("\n\n");
1218 
1219  if (sum->num)
1220  round_ave = (double)sum->rounds / sum->num;
1221 
1222  if (sum->before.num)
1223  before_ave = (double)sum->before.sum_ns / sum->before.num;
1224 
1225  if (sum->after.num)
1226  after_ave = (double)sum->after.sum_ns / sum->after.num;
1227 
1228  printf("TOTAL (%i workers)\n", sum->num);
1229  printf(" events: %" PRIu64 "\n", sum->events);
1230  printf(" ave time: %.2f sec\n", sum->time_ave);
1231  printf(" ave rounds per sec: %.2fM\n", (round_ave / sum->time_ave) / 1000000.0);
1232  printf(" num before: %" PRIu64 "\n", sum->before.num);
1233  printf(" ave before: %.1f nsec\n", before_ave);
1234  printf(" max before: %" PRIu64 " nsec\n", sum->before.max_ns);
1235  printf(" num after: %" PRIu64 "\n", sum->after.num);
1236  printf(" ave after: %.1f nsec\n", after_ave);
1237  printf(" max after: %" PRIu64 " nsec\n", sum->after.max_ns);
1238  printf("\n");
1239 }
1240 
1241 static void sig_handler(int signo)
1242 {
1243  (void)signo;
1244 
1245  if (test_global == NULL)
1246  return;
1247  odp_atomic_add_u32(&test_global->exit_test, MAX_TIMER_POOLS);
1248 }
1249 
1250 int main(int argc, char **argv)
1251 {
1252  odph_helper_options_t helper_options;
1253  odp_instance_t instance;
1254  odp_init_t init;
1255  odp_shm_t shm;
1256  test_global_t *global;
1257  test_options_t *test_options;
1258  int i, shared, mode;
1259 
1260  signal(SIGINT, sig_handler);
1261 
1262  /* Let helper collect its own arguments (e.g. --odph_proc) */
1263  argc = odph_parse_options(argc, argv);
1264  if (odph_options(&helper_options)) {
1265  ODPH_ERR("Reading ODP helper options failed.\n");
1266  exit(EXIT_FAILURE);
1267  }
1268 
1269  /* List features not to be used */
1270  odp_init_param_init(&init);
1271  init.not_used.feat.cls = 1;
1272  init.not_used.feat.compress = 1;
1273  init.not_used.feat.crypto = 1;
1274  init.not_used.feat.ipsec = 1;
1275  init.not_used.feat.tm = 1;
1276 
1277  init.mem_model = helper_options.mem_model;
1278 
1279  /* Init ODP before calling anything else */
1280  if (odp_init_global(&instance, &init, NULL)) {
1281  ODPH_ERR("Global init failed.\n");
1282  return -1;
1283  }
1284 
1285  /* Init this thread */
1286  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
1287  ODPH_ERR("Local init failed.\n");
1288  return -1;
1289  }
1290 
1291  shm = odp_shm_reserve("timer_perf_global", sizeof(test_global_t), ODP_CACHE_LINE_SIZE, 0);
1292  if (shm == ODP_SHM_INVALID) {
1293  ODPH_ERR("Shared mem reserve failed.\n");
1294  exit(EXIT_FAILURE);
1295  }
1296 
1297  global = odp_shm_addr(shm);
1298  if (global == NULL) {
1299  ODPH_ERR("Shared mem alloc failed\n");
1300  exit(EXIT_FAILURE);
1301  }
1302  test_global = global;
1303 
1304  memset(global, 0, sizeof(test_global_t));
1305  odp_atomic_init_u32(&global->exit_test, 0);
1306  odp_atomic_init_u32(&global->timers_started, 0);
1307 
1308  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1309  global->thread_arg[i].global = global;
1310  global->thread_arg[i].worker_idx = i;
1311  }
1312 
1313  if (parse_options(argc, argv, &global->test_options))
1314  return -1;
1315 
1316  test_options = &global->test_options;
1317  shared = test_options->shared;
1318  mode = test_options->mode;
1319 
1321 
1322  odp_schedule_config(NULL);
1323 
1324  if (set_num_cpu(global))
1325  return -1;
1326 
1327  if (create_timer_pools(global))
1328  return -1;
1329 
1330  if (shared) {
1331  /* Start worker threads */
1332  start_workers(global, instance);
1333 
1334  /* Wait until workers have started.
1335  * Scheduler calls from workers may be needed to run timer
1336  * pools in a software implementation. Wait 1 msec to ensure
1337  * that timer pools are running before setting timers. */
1338  odp_barrier_wait(&global->barrier);
1340  }
1341 
1342  /* Set timers. Force workers to exit on failure. */
1343  if (set_timers(global))
1344  odp_atomic_add_u32(&global->exit_test, MAX_TIMER_POOLS);
1345  else
1346  odp_atomic_store_rel_u32(&global->timers_started, 1);
1347 
1348  if (!shared) {
1349  /* Test private pools on the master thread */
1350  if (mode == MODE_SCHED_OVERH) {
1351  if (sched_mode_worker(&global->thread_arg[0])) {
1352  ODPH_ERR("Sched_mode_worker failed\n");
1353  return -1;
1354  }
1355  } else if (mode == MODE_START_CANCEL) {
1356  if (set_cancel_mode_worker(&global->thread_arg[0])) {
1357  ODPH_ERR("Set_cancel_mode_worker failed\n");
1358  return -1;
1359  }
1360  } else {
1361  if (set_expire_mode_worker(&global->thread_arg[0])) {
1362  ODPH_ERR("Set_expire_mode_worker failed\n");
1363  return -1;
1364  }
1365  }
1366  } else {
1367  /* Wait workers to exit */
1368  odph_thread_join(global->thread_tbl,
1369  global->test_options.num_cpu);
1370  }
1371 
1372  sum_stat(global);
1373 
1374  if (mode == MODE_SCHED_OVERH)
1375  print_stat_sched_mode(global);
1376  else if (mode == MODE_START_CANCEL)
1377  print_stat_set_cancel_mode(global);
1378  else
1379  print_stat_expire_mode(global);
1380 
1381  destroy_timer_pool(global);
1382 
1383  if (odp_shm_free(shm)) {
1384  ODPH_ERR("Shared mem free failed.\n");
1385  exit(EXIT_FAILURE);
1386  }
1387 
1388  if (odp_term_local()) {
1389  ODPH_ERR("Term local failed.\n");
1390  return -1;
1391  }
1392 
1393  if (odp_term_global(instance)) {
1394  ODPH_ERR("Term global failed.\n");
1395  return -1;
1396  }
1397 
1398  return 0;
1399 }
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
void odp_atomic_add_u32(odp_atomic_u32_t *atom, uint32_t val)
Add to atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_inc_u32(odp_atomic_u32_t *atom)
Increment atomic uint32 variable.
uint32_t odp_atomic_load_acq_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable using ACQUIRE memory ordering.
void odp_atomic_store_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable using RELEASE memory ordering.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
#define odp_likely(x)
Branch likely taken.
Definition: spec/hints.h:59
uint64_t odp_cpu_cycles_diff(uint64_t c2, uint64_t c1)
CPU cycle count difference.
uint64_t odp_cpu_cycles(void)
Current CPU cycle count.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
void odp_event_free(odp_event_t event)
Free event.
#define ODP_EVENT_INVALID
Invalid event.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_TIMEOUT
Timeout pool.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
odp_time_t odp_time_global(void)
Current global time.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_NULL
Zero time stamp.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_global_ns(void)
Current global time in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
void odp_timeout_free(odp_timeout_t tmo)
Timeout free.
int odp_timer_pool_start_multi(odp_timer_pool_t timer_pool[], int num)
Start timer pools.
odp_timeout_t odp_timeout_alloc(odp_pool_t pool)
Timeout alloc.
int odp_timer_free(odp_timer_t timer)
Free a timer.
odp_timeout_t odp_timeout_from_event(odp_event_t ev)
Get timeout handle from a ODP_EVENT_TIMEOUT type event.
#define ODP_TIMER_POOL_INVALID
Invalid timer pool handle.
odp_timer_pool_t odp_timer_pool_create(const char *name, const odp_timer_pool_param_t *params)
Create a timer pool.
int odp_timer_cancel(odp_timer_t timer, odp_event_t *tmo_ev)
Cancel a timer.
uint64_t odp_timer_current_tick(odp_timer_pool_t timer_pool)
Current tick value.
int odp_timer_capability(odp_timer_clk_src_t clk_src, odp_timer_capability_t *capa)
Query timer capabilities per clock source.
uint64_t odp_timer_ns_to_tick(odp_timer_pool_t timer_pool, uint64_t ns)
Convert nanoseconds to timer ticks.
int odp_timer_start(odp_timer_t timer, const odp_timer_start_t *start_param)
Start a timer.
int odp_timer_res_capability(odp_timer_clk_src_t clk_src, odp_timer_res_capability_t *res_capa)
Timer resolution capability.
odp_event_t odp_timeout_to_event(odp_timeout_t tmo)
Convert timeout handle to event handle.
int odp_timer_pool_info(odp_timer_pool_t timer_pool, odp_timer_pool_info_t *info)
Query timer pool configuration and current state.
odp_timer_t odp_timer_alloc(odp_timer_pool_t timer_pool, odp_queue_t queue, const void *user_ptr)
Allocate a timer.
#define ODP_CLOCK_DEFAULT
The default clock source.
#define ODP_TIMER_INVALID
Invalid timer handle.
void odp_timer_pool_param_init(odp_timer_pool_param_t *param)
Initialize timer pool parameters.
void odp_timer_pool_destroy(odp_timer_pool_t timer_pool)
Destroy a timer pool.
void * odp_timeout_user_ptr(odp_timeout_t tmo)
Return user pointer for the timeout.
@ ODP_TIMER_SUCCESS
Timer operation succeeded.
@ ODP_TIMER_TOO_NEAR
Timer operation failed, too near to the current time.
@ ODP_TIMER_TICK_REL
Relative ticks.
@ ODP_TIMER_TICK_ABS
Absolute ticks.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
Pool parameters.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@127 tmo
Parameters for timeout pools.
odp_pool_type_t type
Pool type.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
uint32_t max_timers
Maximum number of single shot timers in a pool.
uint32_t max_pools
Maximum number of timer pools for single shot timers (per clock source)
odp_timer_res_capability_t max_res
Maximum resolution.
ODP timer pool information and configuration.
uint32_t hwm_timers
High watermark of allocated timers.
uint32_t cur_timers
Number of currently allocated timers.
Timer pool parameters.
uint64_t res_ns
Timeout resolution in nanoseconds.
int priv
Thread private timer pool.
uint64_t min_tmo
Minimum relative timeout in nanoseconds.
uint32_t num_timers
Number of timers in the pool.
odp_timer_clk_src_t clk_src
Clock source for timers.
uint64_t max_tmo
Maximum relative timeout in nanoseconds.
Timer resolution capability.
uint64_t max_tmo
Maximum relative timeout in nanoseconds.
uint64_t min_tmo
Minimum relative timeout in nanoseconds.
uint64_t res_ns
Timeout resolution in nanoseconds.
Timer start parameters.
uint64_t tick
Expiration time in ticks.
odp_event_t tmo_ev
Timeout event.
odp_timer_tick_type_t tick_type
Tick type.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_xxx()
uint32_t crypto
Crypto APIs, e.g., odp_crypto_xxx()
uint32_t ipsec
IPsec APIs, e.g., odp_ipsec_xxx()
uint32_t cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
struct odp_feature_t::@148 feat
Individual feature bits.
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()