API Reference Manual  1.46.0
odp_bench_timer.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2023-2024 Nokia
3  */
4 
13 #ifndef _GNU_SOURCE
14 #define _GNU_SOURCE /* Needed for sigaction */
15 #endif
16 
17 #include <odp_api.h>
18 #include <odp/helper/odph_api.h>
19 
20 #include <bench_common.h>
21 #include <export_results.h>
22 
23 #include <getopt.h>
24 #include <inttypes.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 
29 /* Number of API function calls per test case */
30 #define REPEAT_COUNT 1000
31 
32 /* Default number of rounds per test case */
33 #define ROUNDS 1000u
34 
36 #define UAREA_SIZE 8
37 
39 #define TIMER_NSEC 50000000
40 
42 #define TEST_MAX_BENCH 20
43 
44 #define BENCH_INFO(run_fn, max, alt_name) \
45  {.name = #run_fn, .run = run_fn, .max_rounds = max, .desc = alt_name}
46 
47 typedef struct {
48  /* Command line options */
49  struct {
50  /* Clock source to be used */
51  int clk_src;
52 
53  /* Measure time vs CPU cycles */
54  int time;
55 
56  /* Benchmark index to run indefinitely */
57  int bench_idx;
58 
59  /* Rounds per test case */
60  uint32_t rounds;
61 
62  } opt;
63 
64  /* Common benchmark suite data */
65  bench_suite_t suite;
66 
67  odp_timer_pool_t timer_pool;
68  odp_timer_t timer;
69  odp_queue_t queue;
70  odp_pool_t pool;
71  odp_timeout_t timeout;
72  odp_event_t event;
73  uint64_t timer_nsec;
74  uint64_t tick;
75  uint64_t nsec;
76  double tick_hz;
77  int plain_queue;
78 
79  /* Test case input / output data */
80  uint64_t a1[REPEAT_COUNT];
81  odp_event_t ev[REPEAT_COUNT];
82  odp_timeout_t tmo[REPEAT_COUNT];
83  odp_timer_t tim[REPEAT_COUNT];
84 
85  /* CPU mask as string */
86  char cpumask_str[ODP_CPUMASK_STR_SIZE];
87 
88  /* Array for storing results */
89  double result[TEST_MAX_BENCH];
90 
91 } gbl_args_t;
92 
93 static gbl_args_t *gbl_args;
94 
95 static void sig_handler(int signo ODP_UNUSED)
96 {
97  if (gbl_args == NULL)
98  return;
99  odp_atomic_store_u32(&gbl_args->suite.exit_worker, 1);
100 }
101 
102 static int setup_sig_handler(void)
103 {
104  struct sigaction action;
105 
106  memset(&action, 0, sizeof(action));
107  action.sa_handler = sig_handler;
108 
109  /* No additional signals blocked. By default, the signal which triggered
110  * the handler is blocked. */
111  if (sigemptyset(&action.sa_mask))
112  return -1;
113 
114  if (sigaction(SIGINT, &action, NULL))
115  return -1;
116 
117  return 0;
118 }
119 
120 static int timer_current_tick(void)
121 {
122  int i;
123  odp_timer_pool_t timer_pool = gbl_args->timer_pool;
124  uint64_t *a1 = gbl_args->a1;
125 
126  for (i = 0; i < REPEAT_COUNT; i++)
127  a1[i] = odp_timer_current_tick(timer_pool);
128 
129  return i;
130 }
131 
132 static int timer_tick_to_ns(void)
133 {
134  int i;
135  odp_timer_pool_t timer_pool = gbl_args->timer_pool;
136  uint64_t *a1 = gbl_args->a1;
137  uint64_t tick = gbl_args->tick;
138 
139  for (i = 0; i < REPEAT_COUNT; i++)
140  a1[i] = odp_timer_tick_to_ns(timer_pool, tick);
141 
142  return i;
143 }
144 
145 static int timer_ns_to_tick(void)
146 {
147  int i;
148  odp_timer_pool_t timer_pool = gbl_args->timer_pool;
149  uint64_t *a1 = gbl_args->a1;
150  uint64_t nsec = gbl_args->nsec;
151 
152  for (i = 0; i < REPEAT_COUNT; i++)
153  a1[i] = odp_timer_ns_to_tick(timer_pool, nsec);
154 
155  return i;
156 }
157 
158 static int timeout_to_event(void)
159 {
160  int i;
161  odp_event_t *ev = gbl_args->ev;
162  odp_timeout_t timeout = gbl_args->timeout;
163 
164  for (i = 0; i < REPEAT_COUNT; i++)
165  ev[i] = odp_timeout_to_event(timeout);
166 
167  gbl_args->suite.dummy += odp_event_to_u64(ev[0]);
168 
169  return i;
170 }
171 
172 static int timeout_from_event(void)
173 {
174  int i;
175  odp_event_t ev = gbl_args->event;
176  odp_timeout_t *tmo = gbl_args->tmo;
177 
178  for (i = 0; i < REPEAT_COUNT; i++)
179  tmo[i] = odp_timeout_from_event(ev);
180 
181  gbl_args->suite.dummy += odp_timeout_to_u64(tmo[0]);
182 
183  return i;
184 }
185 
186 static int timeout_timer(void)
187 {
188  int i;
189  odp_timeout_t timeout = gbl_args->timeout;
190  odp_timer_t *tim = gbl_args->tim;
191 
192  for (i = 0; i < REPEAT_COUNT; i++)
193  tim[i] = odp_timeout_timer(timeout);
194 
195  gbl_args->suite.dummy += odp_timer_to_u64(tim[0]);
196 
197  return i;
198 }
199 
200 static int timeout_tick(void)
201 {
202  int i;
203  odp_timeout_t timeout = gbl_args->timeout;
204  uint64_t *a1 = gbl_args->a1;
205 
206  for (i = 0; i < REPEAT_COUNT; i++)
207  a1[i] = odp_timeout_tick(timeout);
208 
209  return i;
210 }
211 
212 static int timeout_user_ptr(void)
213 {
214  int i;
215  odp_timeout_t timeout = gbl_args->timeout;
216  uint64_t *a1 = gbl_args->a1;
217 
218  for (i = 0; i < REPEAT_COUNT; i++)
219  a1[i] = (uintptr_t)odp_timeout_user_ptr(timeout);
220 
221  return i;
222 }
223 
224 static int timeout_user_area(void)
225 {
226  int i;
227  odp_timeout_t timeout = gbl_args->timeout;
228  uint64_t *a1 = gbl_args->a1;
229 
230  for (i = 0; i < REPEAT_COUNT; i++)
231  a1[i] = (uintptr_t)odp_timeout_user_area(timeout);
232 
233  return i;
234 }
235 
236 static int timeout_to_u64(void)
237 {
238  int i;
239  odp_timeout_t timeout = gbl_args->timeout;
240  uint64_t *a1 = gbl_args->a1;
241 
242  for (i = 0; i < REPEAT_COUNT; i++)
243  a1[i] = odp_timeout_to_u64(timeout);
244 
245  return i;
246 }
247 
248 static int timer_to_u64(void)
249 {
250  int i;
251  odp_timer_t timer = gbl_args->timer;
252  uint64_t *a1 = gbl_args->a1;
253 
254  for (i = 0; i < REPEAT_COUNT; i++)
255  a1[i] = odp_timer_to_u64(timer);
256 
257  return i;
258 }
259 
260 static int timer_pool_to_u64(void)
261 {
262  int i;
263  odp_timer_pool_t tp = gbl_args->timer_pool;
264  uint64_t *a1 = gbl_args->a1;
265 
266  for (i = 0; i < REPEAT_COUNT; i++)
267  a1[i] = odp_timer_pool_to_u64(tp);
268 
269  return i;
270 }
271 
272 static int bench_timer_export(void *data)
273 {
274  gbl_args_t *gbl_args = data;
275  int ret = 0;
276 
277  if (test_common_write("%s", gbl_args->opt.time ?
278  "Function name,Average nsec per function call\n" :
279  "Function name,Average CPU cycles per function call\n")) {
280  ret = -1;
281  goto exit;
282  }
283 
284  for (int i = 0; i < gbl_args->suite.num_bench; i++) {
285  if (test_common_write("odp_%s,%f\n",
286  gbl_args->suite.bench[i].name,
287  gbl_args->suite.result[i])) {
288  ret = -1;
289  goto exit;
290  }
291  }
292 
293 exit:
294  test_common_write_term();
295 
296  return ret;
297 }
298 
299 bench_info_t test_suite[] = {
300  BENCH_INFO(timer_current_tick, 0, NULL),
301  BENCH_INFO(timer_tick_to_ns, 0, NULL),
302  BENCH_INFO(timer_ns_to_tick, 0, NULL),
303  BENCH_INFO(timeout_to_event, 0, NULL),
304  BENCH_INFO(timeout_from_event, 0, NULL),
305  BENCH_INFO(timeout_timer, 0, NULL),
306  BENCH_INFO(timeout_tick, 0, NULL),
307  BENCH_INFO(timeout_user_ptr, 0, NULL),
308  BENCH_INFO(timeout_user_area, 0, NULL),
309  BENCH_INFO(timeout_to_u64, 0, NULL),
310  BENCH_INFO(timer_to_u64, 0, NULL),
311  BENCH_INFO(timer_pool_to_u64, 0, NULL),
312 };
313 
314 ODP_STATIC_ASSERT(ODPH_ARRAY_SIZE(test_suite) < TEST_MAX_BENCH,
315  "Result array is too small to hold all the results");
316 
317 /* Print usage information */
318 static void usage(void)
319 {
320  printf("\n"
321  "ODP timer API micro benchmarks\n"
322  "\n"
323  "Options:\n"
324  " -s, --clk_src Clock source select (default 0):\n"
325  " 0: ODP_CLOCK_DEFAULT\n"
326  " 1: ODP_CLOCK_SRC_1, ...\n"
327  " -t, --time <opt> Time measurement. 0: measure CPU cycles (default), 1: measure time\n"
328  " -i, --index <idx> Benchmark index to run indefinitely.\n"
329  " -r, --rounds <num> Run each test case 'num' times (default %u).\n"
330  " -h, --help Display help and exit.\n\n"
331  "\n", ROUNDS);
332 }
333 
334 /* Parse command line arguments */
335 static int parse_args(int argc, char *argv[])
336 {
337  int opt;
338  static const struct option longopts[] = {
339  {"clk_src", required_argument, NULL, 's'},
340  {"time", required_argument, NULL, 't'},
341  {"index", required_argument, NULL, 'i'},
342  {"rounds", required_argument, NULL, 'r'},
343  {"help", no_argument, NULL, 'h'},
344  {NULL, 0, NULL, 0}
345  };
346 
347  static const char *shortopts = "s:t:i:r:h";
348 
349  gbl_args->opt.clk_src = ODP_CLOCK_DEFAULT;
350  gbl_args->opt.time = 0; /* Measure CPU cycles */
351  gbl_args->opt.bench_idx = 0; /* Run all benchmarks */
352  gbl_args->opt.rounds = ROUNDS;
353 
354  while (1) {
355  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
356 
357  if (opt == -1)
358  break; /* No more options */
359 
360  switch (opt) {
361  case 's':
362  gbl_args->opt.clk_src = atoi(optarg);
363  break;
364  case 't':
365  gbl_args->opt.time = atoi(optarg);
366  break;
367  case 'i':
368  gbl_args->opt.bench_idx = atoi(optarg);
369  break;
370  case 'r':
371  gbl_args->opt.rounds = atoi(optarg);
372  break;
373  case 'h':
374  usage();
375  return 1;
376  default:
377  ODPH_ERR("Bad option. Use -h for help.\n");
378  return -1;
379  }
380  }
381 
382  if (gbl_args->opt.rounds < 1) {
383  ODPH_ERR("Invalid test cycle repeat count: %u\n", gbl_args->opt.rounds);
384  return -1;
385  }
386 
387  if (gbl_args->opt.bench_idx < 0 ||
388  gbl_args->opt.bench_idx > (int)ODPH_ARRAY_SIZE(test_suite)) {
389  ODPH_ERR("Bad bench index %i\n", gbl_args->opt.bench_idx);
390  return -1;
391  }
392 
393  optind = 1; /* Reset 'extern optind' from the getopt lib */
394 
395  return 0;
396 }
397 
398 /* Print system and application info */
399 static void print_info(void)
400 {
402 
403  printf("\n"
404  "odp_bench_timer options\n"
405  "-----------------------\n");
406 
407  printf("CPU mask: %s\n", gbl_args->cpumask_str);
408  printf("Clock source: %i\n", gbl_args->opt.clk_src);
409  printf("Measurement unit: %s\n", gbl_args->opt.time ? "nsec" : "CPU cycles");
410  printf("Test rounds: %u\n", gbl_args->opt.rounds);
411  printf("Timer duration: %" PRIu64 " nsec\n", gbl_args->timer_nsec);
412  printf("Timer tick freq: %.2f Hz\n", gbl_args->tick_hz);
413  printf("\n");
414 }
415 
416 static int create_timer(void)
417 {
418  odp_pool_capability_t pool_capa;
419  odp_timer_capability_t timer_capa;
420  odp_timer_clk_src_t clk_src;
421  odp_timer_pool_param_t tp_param;
422  odp_timer_pool_t tp;
423  odp_pool_t pool;
424  odp_pool_param_t pool_param;
425  odp_timeout_t tmo;
426  odp_queue_param_t queue_param;
427  odp_queue_t queue;
428  odp_timer_t timer;
429  uint64_t t1, t2, diff, tick1, tick2;
430 
431  if (odp_pool_capability(&pool_capa)) {
432  ODPH_ERR("Pool capa failed\n");
433  return -1;
434  }
435 
436  clk_src = gbl_args->opt.clk_src;
437  if (odp_timer_capability(clk_src, &timer_capa)) {
438  ODPH_ERR("Timer capa failed\n");
439  return -1;
440  }
441 
442  odp_timer_pool_param_init(&tp_param);
443  tp_param.clk_src = clk_src;
444  tp_param.res_ns = timer_capa.max_res.res_ns;
445  tp_param.min_tmo = timer_capa.max_res.min_tmo;
446  tp_param.max_tmo = timer_capa.max_res.max_tmo;
447  tp_param.num_timers = 10;
448 
449  tp = odp_timer_pool_create("bench_timer", &tp_param);
450 
451  if (tp == ODP_TIMER_POOL_INVALID) {
452  ODPH_ERR("Timer pool create failed\n");
453  return -1;
454  }
455 
456  if (odp_timer_pool_start_multi(&tp, 1) != 1) {
457  ODPH_ERR("Timer pool start failed\n");
458  return -1;
459  }
460 
461  gbl_args->timer_pool = tp;
462 
463  gbl_args->timer_nsec = TIMER_NSEC;
464  if (TIMER_NSEC < tp_param.min_tmo)
465  gbl_args->timer_nsec = tp_param.min_tmo;
466  else if (TIMER_NSEC > tp_param.max_tmo)
467  gbl_args->timer_nsec = tp_param.max_tmo;
468 
469  odp_pool_param_init(&pool_param);
470  pool_param.type = ODP_POOL_TIMEOUT;
471  pool_param.tmo.num = 10;
472  pool_param.tmo.uarea_size = UAREA_SIZE;
473  if (UAREA_SIZE > pool_capa.tmo.max_uarea_size)
474  pool_param.tmo.uarea_size = pool_capa.tmo.max_uarea_size;
475 
476  pool = odp_pool_create("bench_timer", &pool_param);
477 
478  if (pool == ODP_POOL_INVALID) {
479  ODPH_ERR("Timeout pool create failed\n");
480  return -1;
481  }
482 
483  gbl_args->pool = pool;
484 
485  tmo = odp_timeout_alloc(pool);
486 
487  if (tmo == ODP_TIMEOUT_INVALID) {
488  ODPH_ERR("Timeout alloc failed\n");
489  return -1;
490  }
491 
492  gbl_args->timeout = tmo;
493  gbl_args->tick = odp_timer_current_tick(tp);
494  gbl_args->nsec = odp_timer_tick_to_ns(tp, gbl_args->tick);
495 
496  /* Measure timer tick frequency for test information */
498  tick1 = odp_timer_current_tick(tp);
499 
501 
502  tick2 = odp_timer_current_tick(tp);
504  diff = t2 - t1;
505 
506  if (diff)
507  gbl_args->tick_hz = (tick2 - tick1) / ((double)diff / ODP_TIME_SEC_IN_NS);
508 
509  odp_queue_param_init(&queue_param);
510  queue_param.type = ODP_QUEUE_TYPE_SCHED;
511  queue_param.sched.prio = odp_schedule_default_prio();
512  queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;
513  queue_param.sched.group = ODP_SCHED_GROUP_ALL;
514 
515  if (timer_capa.queue_type_sched == 0) {
516  queue_param.type = ODP_QUEUE_TYPE_PLAIN;
517  gbl_args->plain_queue = 1;
518  }
519 
520  queue = odp_queue_create("bench_timer", &queue_param);
521  if (queue == ODP_QUEUE_INVALID) {
522  ODPH_ERR("Queue create failed\n");
523  return -1;
524  }
525 
526  gbl_args->queue = queue;
527 
528  timer = odp_timer_alloc(tp, queue, (void *)(uintptr_t)0xdeadbeef);
529  if (timer == ODP_TIMER_INVALID) {
530  ODPH_ERR("Timer alloc failed\n");
531  return -1;
532  }
533 
534  gbl_args->timer = timer;
535 
536  return 0;
537 }
538 
539 static int wait_timer(void)
540 {
541  odp_timer_start_t start_param;
542  odp_timer_t timer = gbl_args->timer;
543  odp_timer_pool_t tp = gbl_args->timer_pool;
544  uint64_t wait_nsec = 2 * gbl_args->timer_nsec;
545  uint64_t sched_wait = odp_schedule_wait_time(wait_nsec);
546  odp_event_t ev;
547  uint64_t start;
548 
549  start_param.tick_type = ODP_TIMER_TICK_REL;
550  start_param.tick = odp_timer_ns_to_tick(tp, gbl_args->timer_nsec);
551  start_param.tmo_ev = odp_timeout_to_event(gbl_args->timeout);
552 
553  if (odp_timer_start(timer, &start_param) != ODP_TIMER_SUCCESS) {
554  ODPH_ERR("Timer start failed\n");
555  return -1;
556  }
557 
558  gbl_args->timeout = ODP_TIMEOUT_INVALID;
559  gbl_args->event = ODP_EVENT_INVALID;
560 
561  /* Wait for timeout */
562  if (gbl_args->plain_queue) {
563  start = odp_time_global_ns();
564  while (1) {
565  ev = odp_queue_deq(gbl_args->queue);
566 
567  if (ev != ODP_EVENT_INVALID)
568  break;
569 
570  if ((odp_time_global_ns() - start) > wait_nsec) {
571  ODPH_ERR("Timeout event missing\n");
572  return -1;
573  }
574  }
575 
576  gbl_args->event = ev;
577  } else {
578  ev = odp_schedule(NULL, sched_wait);
579 
580  if (ev == ODP_EVENT_INVALID) {
581  ODPH_ERR("Timeout event missing\n");
582  return -1;
583  }
584 
585  gbl_args->event = ev;
586 
587  /* Free schedule context */
589  ODPH_ERR("Extra timeout event\n");
590  return -1;
591  }
592  }
593 
594  if (odp_event_type(gbl_args->event) != ODP_EVENT_TIMEOUT) {
595  ODPH_ERR("Bad event type\n");
596  return -1;
597  }
598 
599  gbl_args->timeout = odp_timeout_from_event(gbl_args->event);
600 
601  return 0;
602 }
603 
604 int main(int argc, char *argv[])
605 {
606  odph_helper_options_t helper_options;
607  test_common_options_t common_options;
608  odph_thread_t worker_thread;
609  odph_thread_common_param_t thr_common;
610  odph_thread_param_t thr_param;
611  int cpu, i;
612  odp_shm_t shm;
613  odp_cpumask_t cpumask, default_mask;
614  odp_instance_t instance;
615  odp_init_t init_param;
616  int ret = 0;
617 
618  /* Let helper collect its own arguments (e.g. --odph_proc) */
619  argc = odph_parse_options(argc, argv);
620  if (odph_options(&helper_options)) {
621  ODPH_ERR("Reading ODP helper options failed\n");
622  exit(EXIT_FAILURE);
623  }
624 
625  argc = test_common_parse_options(argc, argv);
626  if (test_common_options(&common_options)) {
627  ODPH_ERR("Reading test options failed\n");
628  exit(EXIT_FAILURE);
629  }
630 
631  odp_init_param_init(&init_param);
632  init_param.mem_model = helper_options.mem_model;
633 
634  /* Init ODP before calling anything else */
635  if (odp_init_global(&instance, &init_param, NULL)) {
636  ODPH_ERR("Global init failed\n");
637  exit(EXIT_FAILURE);
638  }
639 
640  /* Init this thread */
641  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
642  ODPH_ERR("Local init failed\n");
643  exit(EXIT_FAILURE);
644  }
645 
646  if (setup_sig_handler()) {
647  ODPH_ERR("Signal handler setup failed\n");
648  exit(EXIT_FAILURE);
649  }
650 
651  odp_schedule_config(NULL);
652 
653  /* Reserve memory for args from shared mem */
654  shm = odp_shm_reserve("shm_args", sizeof(gbl_args_t), ODP_CACHE_LINE_SIZE, 0);
655  if (shm == ODP_SHM_INVALID) {
656  ODPH_ERR("Shared mem reserve failed\n");
657  exit(EXIT_FAILURE);
658  }
659 
660  gbl_args = odp_shm_addr(shm);
661  if (gbl_args == NULL) {
662  ODPH_ERR("Shared mem alloc failed\n");
663  exit(EXIT_FAILURE);
664  }
665 
666  memset(gbl_args, 0, sizeof(gbl_args_t));
667  gbl_args->timer_pool = ODP_TIMER_POOL_INVALID;
668  gbl_args->timer = ODP_TIMER_INVALID;
669  gbl_args->queue = ODP_QUEUE_INVALID;
670  gbl_args->pool = ODP_POOL_INVALID;
671  gbl_args->timeout = ODP_TIMEOUT_INVALID;
672 
673  for (i = 0; i < REPEAT_COUNT; i++) {
674  gbl_args->a1[i] = i;
675  gbl_args->ev[i] = ODP_EVENT_INVALID;
676  gbl_args->tmo[i] = ODP_TIMEOUT_INVALID;
677  gbl_args->tim[i] = ODP_TIMER_INVALID;
678  }
679 
680  /* Parse and store the application arguments */
681  ret = parse_args(argc, argv);
682  if (ret)
683  goto exit;
684 
685  bench_suite_init(&gbl_args->suite);
686  gbl_args->suite.bench = test_suite;
687  gbl_args->suite.num_bench = ODPH_ARRAY_SIZE(test_suite);
688  gbl_args->suite.measure_time = !!gbl_args->opt.time;
689  gbl_args->suite.indef_idx = gbl_args->opt.bench_idx;
690  gbl_args->suite.rounds = gbl_args->opt.rounds;
691  gbl_args->suite.repeat_count = REPEAT_COUNT;
692  if (common_options.is_export)
693  gbl_args->suite.result = gbl_args->result;
694 
695  /* Get default worker cpumask */
696  if (odp_cpumask_default_worker(&default_mask, 1) != 1) {
697  ODPH_ERR("Unable to allocate worker thread\n");
698  ret = -1;
699  goto exit;
700  }
701 
702  (void)odp_cpumask_to_str(&default_mask, gbl_args->cpumask_str,
703  sizeof(gbl_args->cpumask_str));
704 
705  /* Create timer and other resources */
706  ret = create_timer();
707  if (ret)
708  goto exit;
709 
710  print_info();
711 
712  /* Start one timer and wait for the timeout event. Timer expiration fills in
713  * timeout event metadata. */
714  ret = wait_timer();
715  if (ret)
716  goto exit;
717 
718  memset(&worker_thread, 0, sizeof(odph_thread_t));
719 
720  /* Create worker thread */
721  cpu = odp_cpumask_first(&default_mask);
722 
723  odp_cpumask_zero(&cpumask);
724  odp_cpumask_set(&cpumask, cpu);
725 
726  odph_thread_common_param_init(&thr_common);
727  thr_common.instance = instance;
728  thr_common.cpumask = &cpumask;
729  thr_common.share_param = 1;
730 
731  odph_thread_param_init(&thr_param);
732  thr_param.start = bench_run;
733  thr_param.arg = &gbl_args->suite;
734  thr_param.thr_type = ODP_THREAD_WORKER;
735 
736  odph_thread_create(&worker_thread, &thr_common, &thr_param, 1);
737 
738  odph_thread_join(&worker_thread, 1);
739 
740  ret = gbl_args->suite.retval;
741 
742  if (ret == 0 && common_options.is_export) {
743  if (bench_timer_export(gbl_args)) {
744  ODPH_ERR("Error: Export failed\n");
745  ret = -1;
746  }
747  }
748 
749 exit:
750  if (gbl_args->timeout != ODP_TIMEOUT_INVALID)
751  odp_timeout_free(gbl_args->timeout);
752 
753  if (gbl_args->pool != ODP_POOL_INVALID)
754  odp_pool_destroy(gbl_args->pool);
755 
756  if (gbl_args->timer != ODP_TIMER_INVALID) {
757  if (odp_timer_free(gbl_args->timer)) {
758  ODPH_ERR("Timer free failed\n");
759  exit(EXIT_FAILURE);
760  }
761  }
762 
763  if (gbl_args->timer_pool != ODP_TIMER_POOL_INVALID)
764  odp_timer_pool_destroy(gbl_args->timer_pool);
765 
766  if (gbl_args->queue != ODP_QUEUE_INVALID) {
767  if (odp_queue_destroy(gbl_args->queue)) {
768  ODPH_ERR("Queue destroy failed\n");
769  exit(EXIT_FAILURE);
770  }
771  }
772 
773  if (odp_shm_free(shm)) {
774  ODPH_ERR("Shared mem free failed\n");
775  exit(EXIT_FAILURE);
776  }
777 
778  if (odp_term_local()) {
779  ODPH_ERR("Local term failed\n");
780  exit(EXIT_FAILURE);
781  }
782 
783  if (odp_term_global(instance)) {
784  ODPH_ERR("Global term failed\n");
785  exit(EXIT_FAILURE);
786  }
787 
788  if (ret < 0)
789  return EXIT_FAILURE;
790 
791  return EXIT_SUCCESS;
792 }
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition: spec/hints.h:54
void odp_cpumask_set(odp_cpumask_t *mask, int cpu)
Add CPU to mask.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
void odp_cpumask_zero(odp_cpumask_t *mask)
Clear entire CPU mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
uint64_t odp_event_to_u64(odp_event_t hdl)
Get printable value for an odp_event_t.
#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.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
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.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
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_event_t odp_queue_deq(odp_queue_t queue)
Dequeue an event from a 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.
@ ODP_QUEUE_TYPE_PLAIN
Plain 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.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
uint64_t odp_time_global_strict_ns(void)
Current global time in nanoseconds (strict)
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_global_ns(void)
Current global time in nanoseconds.
void odp_timeout_free(odp_timeout_t tmo)
Timeout free.
uint64_t odp_timer_tick_to_ns(odp_timer_pool_t timer_pool, uint64_t ticks)
Convert timer ticks to nanoseconds.
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.
uint64_t odp_timeout_tick(odp_timeout_t tmo)
Timeout expiration tick.
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.
odp_timer_t odp_timeout_timer(odp_timeout_t tmo)
Return timer handle for the timeout.
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.
void * odp_timeout_user_area(odp_timeout_t tmo)
Timeout user area.
uint64_t odp_timer_ns_to_tick(odp_timer_pool_t timer_pool, uint64_t ns)
Convert nanoseconds to timer ticks.
uint64_t odp_timeout_to_u64(odp_timeout_t tmo)
Get printable value for an odp_timeout_t.
odp_timer_clk_src_t
Clock sources for timer pools.
int odp_timer_start(odp_timer_t timer, const odp_timer_start_t *start_param)
Start a timer.
odp_event_t odp_timeout_to_event(odp_timeout_t tmo)
Convert timeout handle to event handle.
#define ODP_TIMEOUT_INVALID
Invalid timeout handle.
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.
uint64_t odp_timer_pool_to_u64(odp_timer_pool_t timer_pool)
Get printable value for an odp_timer_pool_t.
#define ODP_TIMER_INVALID
Invalid timer handle.
uint64_t odp_timer_to_u64(odp_timer_t timer)
Get printable value for an odp_timer_t.
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_TICK_REL
Relative ticks.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
struct odp_pool_capability_t::@123 tmo
Timeout pool capabilities
uint32_t max_uarea_size
Maximum user area size in bytes.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
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.
odp_timer_res_capability_t max_res
Maximum resolution.
odp_bool_t queue_type_sched
Scheduled queue destination support.
Timer pool parameters.
uint64_t res_ns
Timeout resolution in nanoseconds.
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.
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.