API Reference Manual  1.46.0
odp_bench_buffer.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2017-2018 Linaro Limited
3  * Copyright (c) 2022-2024 Nokia
4  */
5 
14 #include <odp_api.h>
15 #include <odp/helper/odph_api.h>
16 
17 #include <bench_common.h>
18 #include <export_results.h>
19 
20 #include <getopt.h>
21 #include <inttypes.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 
27 #define TEST_BUF_SIZE 1024
28 
30 #define TEST_UAREA_SIZE 8
31 
33 #define TEST_REPEAT_COUNT 1000
34 
36 #define TEST_ROUNDS 100u
37 
39 #define TEST_MAX_BURST 64
40 
42 #define TEST_DEF_BURST 8
43 
45 #define TEST_MAX_BENCH 40
46 
48 #define NO_PATH(file_name) (strrchr((file_name), '/') ? \
49  strrchr((file_name), '/') + 1 : (file_name))
50 
51 #define BENCH_INFO(run_fn, init_fn, term_fn, alt_name) \
52  {.name = #run_fn, .run = run_fn, .init = init_fn, .term = term_fn, .desc = alt_name}
53 
54 #define BENCH_INFO_COND(run_fn, init_fn, term_fn, alt_name, cond_fn) \
55  {.name = #run_fn, .run = run_fn, .init = init_fn, .term = term_fn, .desc = alt_name, \
56  .cond = cond_fn}
57 
61 typedef struct {
62  int bench_idx;
63  int burst_size;
64  int cache_size;
65  int time;
66  uint32_t rounds;
67 } appl_args_t;
68 
72 typedef struct {
74  appl_args_t appl;
76  bench_suite_t suite;
78  odp_pool_t pool;
80  uint32_t buf_size;
82  uint32_t uarea_size;
84  uint32_t max_flow_id;
86  odp_buffer_t buf_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST];
88  odp_event_t event_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST];
90  void *ptr_tbl[TEST_REPEAT_COUNT];
92  odp_pool_t pool_tbl[TEST_REPEAT_COUNT];
94  odp_event_type_t event_type_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST];
96  odp_event_subtype_t event_subtype_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST];
98  char cpumask_str[ODP_CPUMASK_STR_SIZE];
100  double result[TEST_MAX_BENCH];
101 } args_t;
102 
104 static args_t *gbl_args;
105 
106 static void sig_handler(int signo ODP_UNUSED)
107 {
108  if (gbl_args == NULL)
109  return;
110  odp_atomic_store_u32(&gbl_args->suite.exit_worker, 1);
111 }
112 
113 static void allocate_test_buffers(odp_buffer_t buf[], int num)
114 {
115  int num_buf = 0;
116 
117  while (num_buf < num) {
118  int ret;
119 
120  ret = odp_buffer_alloc_multi(gbl_args->pool, &buf[num_buf], num - num_buf);
121  if (ret < 0)
122  ODPH_ABORT("Allocating test buffers failed\n");
123 
124  num_buf += ret;
125  }
126 }
127 
128 static void create_buffers(void)
129 {
130  allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
131 }
132 
133 static void create_buffers_multi(void)
134 {
135  allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
136 }
137 
138 static void create_events(void)
139 {
140  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
141 
142  allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
143 
144  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
145  gbl_args->event_tbl[i] = odp_buffer_to_event(buf_tbl[i]);
146 }
147 
148 static void create_events_multi(void)
149 {
150  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
151 
152  allocate_test_buffers(gbl_args->buf_tbl,
153  TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
154 
155  for (int i = 0; i < TEST_REPEAT_COUNT * gbl_args->appl.burst_size; i++)
156  gbl_args->event_tbl[i] = odp_buffer_to_event(buf_tbl[i]);
157 }
158 
159 static void free_buffers(void)
160 {
161  odp_buffer_free_multi(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
162 }
163 
164 static void free_buffers_multi(void)
165 {
166  odp_buffer_free_multi(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
167 }
168 
169 static int check_uarea(void)
170 {
171  return !!gbl_args->uarea_size;
172 }
173 
174 static int check_flow_aware(void)
175 {
176  return !!gbl_args->max_flow_id;
177 }
178 
179 static int buffer_from_event(void)
180 {
181  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
182  odp_event_t *event_tbl = gbl_args->event_tbl;
183  int i;
184 
185  for (i = 0; i < TEST_REPEAT_COUNT; i++)
186  buf_tbl[i] = odp_buffer_from_event(event_tbl[i]);
187 
188  return i;
189 }
190 
191 static int buffer_from_event_multi(void)
192 {
193  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
194  odp_event_t *event_tbl = gbl_args->event_tbl;
195  int burst_size = gbl_args->appl.burst_size;
196  int i;
197 
198  for (i = 0; i < TEST_REPEAT_COUNT; i++)
199  odp_buffer_from_event_multi(&buf_tbl[i * burst_size],
200  &event_tbl[i * burst_size], burst_size);
201 
202  return i;
203 }
204 
205 static int buffer_to_event(void)
206 {
207  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
208  odp_event_t *event_tbl = gbl_args->event_tbl;
209  int i;
210 
211  for (i = 0; i < TEST_REPEAT_COUNT; i++)
212  event_tbl[i] = odp_buffer_to_event(buf_tbl[i]);
213 
214  return i;
215 }
216 
217 static int buffer_to_event_multi(void)
218 {
219  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
220  odp_event_t *event_tbl = gbl_args->event_tbl;
221  int burst_size = gbl_args->appl.burst_size;
222  int i;
223 
224  for (i = 0; i < TEST_REPEAT_COUNT; i++)
225  odp_buffer_to_event_multi(&buf_tbl[i * burst_size],
226  &event_tbl[i * burst_size], burst_size);
227 
228  return i;
229 }
230 
231 static int buffer_addr(void)
232 {
233  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
234  void **ptr_tbl = gbl_args->ptr_tbl;
235  int i;
236 
237  for (i = 0; i < TEST_REPEAT_COUNT; i++)
238  ptr_tbl[i] = odp_buffer_addr(buf_tbl[i]);
239 
240  return i;
241 }
242 
243 static int buffer_size(void)
244 {
245  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
246  uint32_t ret = 0;
247 
248  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
249  ret += odp_buffer_size(buf_tbl[i]);
250 
251  return ret;
252 }
253 
254 static int buffer_user_area(void)
255 {
256  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
257  void **ptr_tbl = gbl_args->ptr_tbl;
258  int i;
259 
260  for (i = 0; i < TEST_REPEAT_COUNT; i++)
261  ptr_tbl[i] = odp_buffer_user_area(buf_tbl[i]);
262 
263  return i;
264 }
265 
266 static int buffer_pool(void)
267 {
268  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
269  odp_pool_t *pool_tbl = gbl_args->pool_tbl;
270  int i;
271 
272  for (i = 0; i < TEST_REPEAT_COUNT; i++)
273  pool_tbl[i] = odp_buffer_pool(buf_tbl[i]);
274 
275  return i;
276 }
277 
278 static int buffer_alloc(void)
279 {
280  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
281  odp_pool_t pool = gbl_args->pool;
282  int i;
283 
284  for (i = 0; i < TEST_REPEAT_COUNT; i++)
285  buf_tbl[i] = odp_buffer_alloc(pool);
286 
287  return i;
288 }
289 
290 static int buffer_alloc_multi(void)
291 {
292  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
293  odp_pool_t pool = gbl_args->pool;
294  int burst_size = gbl_args->appl.burst_size;
295  int num = 0;
296 
297  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
298  num += odp_buffer_alloc_multi(pool, &buf_tbl[num], burst_size);
299 
300  return num;
301 }
302 
303 static int buffer_free(void)
304 {
305  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
306  int i;
307 
308  for (i = 0; i < TEST_REPEAT_COUNT; i++)
309  odp_buffer_free(buf_tbl[i]);
310 
311  return i;
312 }
313 
314 static int buffer_free_multi(void)
315 {
316  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
317  int burst_size = gbl_args->appl.burst_size;
318  int i;
319 
320  for (i = 0; i < TEST_REPEAT_COUNT; i++)
321  odp_buffer_free_multi(&buf_tbl[i * burst_size], burst_size);
322 
323  return i;
324 }
325 
326 static int buffer_alloc_free(void)
327 {
328  odp_pool_t pool = gbl_args->pool;
329  int i;
330 
331  for (i = 0; i < TEST_REPEAT_COUNT; i++) {
332  odp_buffer_t buf = odp_buffer_alloc(pool);
333 
334  if (odp_unlikely(buf == ODP_BUFFER_INVALID))
335  return 0;
336 
337  odp_buffer_free(buf);
338  }
339  return i;
340 }
341 
342 static int buffer_alloc_free_multi(void)
343 {
344  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
345  odp_pool_t pool = gbl_args->pool;
346  int burst_size = gbl_args->appl.burst_size;
347  int i;
348 
349  for (i = 0; i < TEST_REPEAT_COUNT; i++) {
350  int num = odp_buffer_alloc_multi(pool, buf_tbl, burst_size);
351 
352  if (odp_unlikely(num < 1))
353  return 0;
354 
355  odp_buffer_free_multi(buf_tbl, num);
356  }
357  return i;
358 }
359 
360 static int buffer_is_valid(void)
361 {
362  odp_buffer_t *buf_tbl = gbl_args->buf_tbl;
363  uint32_t ret = 0;
364 
365  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
366  ret += odp_buffer_is_valid(buf_tbl[i]);
367 
368  return ret;
369 }
370 
371 static int event_type(void)
372 {
373  odp_event_t *event_tbl = gbl_args->event_tbl;
374  odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl;
375  int i;
376 
377  for (i = 0; i < TEST_REPEAT_COUNT; i++)
378  event_type_tbl[i] = odp_event_type(event_tbl[i]);
379 
380  return i;
381 }
382 
383 static int event_subtype(void)
384 {
385  odp_event_t *event_tbl = gbl_args->event_tbl;
386  odp_event_subtype_t *event_subtype_tbl = gbl_args->event_subtype_tbl;
387  int i;
388 
389  for (i = 0; i < TEST_REPEAT_COUNT; i++)
390  event_subtype_tbl[i] = odp_event_subtype(event_tbl[i]);
391 
392  return i;
393 }
394 
395 static int event_types(void)
396 {
397  odp_event_t *event_tbl = gbl_args->event_tbl;
398  odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl;
399  odp_event_subtype_t *event_subtype_tbl = gbl_args->event_subtype_tbl;
400  int i;
401 
402  for (i = 0; i < TEST_REPEAT_COUNT; i++)
403  event_type_tbl[i] = odp_event_types(event_tbl[i], &event_subtype_tbl[i]);
404 
405  return i;
406 }
407 
408 static int event_types_multi(void)
409 {
410  odp_event_t *event_tbl = gbl_args->event_tbl;
411  odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl;
412  odp_event_subtype_t *event_subtype_tbl = gbl_args->event_subtype_tbl;
413  int burst_size = gbl_args->appl.burst_size;
414  int i;
415 
416  for (i = 0; i < TEST_REPEAT_COUNT; i++)
417  odp_event_types_multi(&event_tbl[i * burst_size],
418  &event_type_tbl[i * burst_size],
419  &event_subtype_tbl[i * burst_size], burst_size);
420 
421  return i;
422 }
423 
424 static int event_types_multi_no_sub(void)
425 {
426  odp_event_t *event_tbl = gbl_args->event_tbl;
427  odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl;
428  int burst_size = gbl_args->appl.burst_size;
429  int i;
430 
431  for (i = 0; i < TEST_REPEAT_COUNT; i++)
432  odp_event_types_multi(&event_tbl[i * burst_size],
433  &event_type_tbl[i * burst_size], NULL, burst_size);
434 
435  return i;
436 }
437 
438 static int event_type_multi(void)
439 {
440  odp_event_t *event_tbl = gbl_args->event_tbl;
441  odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl;
442  int burst_size = gbl_args->appl.burst_size;
443  uint32_t ret = 0;
444 
445  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
446  ret += odp_event_type_multi(&event_tbl[i * burst_size], burst_size,
447  &event_type_tbl[i]);
448 
449  return ret;
450 }
451 
452 static int event_pool(void)
453 {
454  odp_event_t *event_tbl = gbl_args->event_tbl;
455  odp_pool_t *pool_tbl = gbl_args->pool_tbl;
456  int i;
457 
458  for (i = 0; i < TEST_REPEAT_COUNT; i++)
459  pool_tbl[i] = odp_event_pool(event_tbl[i]);
460 
461  return i;
462 }
463 
464 static int event_user_area(void)
465 {
466  odp_event_t *event_tbl = gbl_args->event_tbl;
467  void **ptr_tbl = gbl_args->ptr_tbl;
468  int i;
469 
470  for (i = 0; i < TEST_REPEAT_COUNT; i++)
471  ptr_tbl[i] = odp_event_user_area(event_tbl[i]);
472 
473  return i;
474 }
475 
476 static int event_user_area_and_flag(void)
477 {
478  odp_event_t *event_tbl = gbl_args->event_tbl;
479  void **ptr_tbl = gbl_args->ptr_tbl;
480  int ret = 0;
481  int flag;
482 
483  for (int i = 0; i < TEST_REPEAT_COUNT; i++) {
484  ptr_tbl[i] = odp_event_user_area_and_flag(event_tbl[i], &flag);
485  ret += flag;
486  }
487 
488  return ret;
489 }
490 
491 static int event_is_valid(void)
492 {
493  odp_event_t *event_tbl = gbl_args->event_tbl;
494 
495  uint32_t ret = 0;
496 
497  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
498  ret += odp_event_is_valid(event_tbl[i]);
499 
500  return ret;
501 }
502 
503 static int event_free(void)
504 {
505  odp_event_t *event_tbl = gbl_args->event_tbl;
506 
507  int i;
508 
509  for (i = 0; i < TEST_REPEAT_COUNT; i++)
510  odp_event_free(event_tbl[i]);
511 
512  return i;
513 }
514 
515 static int event_free_multi(void)
516 {
517  odp_event_t *event_tbl = gbl_args->event_tbl;
518  int burst_size = gbl_args->appl.burst_size;
519  int i;
520 
521  for (i = 0; i < TEST_REPEAT_COUNT; i++)
522  odp_event_free_multi(&event_tbl[i * burst_size], burst_size);
523 
524  return i;
525 }
526 
527 static int event_free_sp(void)
528 {
529  odp_event_t *event_tbl = gbl_args->event_tbl;
530  int burst_size = gbl_args->appl.burst_size;
531  int i;
532 
533  for (i = 0; i < TEST_REPEAT_COUNT; i++)
534  odp_event_free_sp(&event_tbl[i * burst_size], burst_size);
535 
536  return i;
537 }
538 
539 static int event_flow_id(void)
540 {
541  odp_event_t *event_tbl = gbl_args->event_tbl;
542  uint32_t ret = 0;
543 
544  for (int i = 0; i < TEST_REPEAT_COUNT; i++)
545  ret += odp_event_flow_id(event_tbl[i]);
546 
547  return !ret;
548 }
549 
550 static int event_flow_id_set(void)
551 {
552  odp_event_t *event_tbl = gbl_args->event_tbl;
553  int i = 0;
554 
555  for (i = 0; i < TEST_REPEAT_COUNT; i++)
556  odp_event_flow_id_set(event_tbl[i], 0);
557 
558  return i;
559 }
560 
564 static void usage(char *progname)
565 {
566  printf("\n"
567  "OpenDataPlane Buffer/Event API microbenchmarks.\n"
568  "\n"
569  "Usage: %s OPTIONS\n"
570  " E.g. %s\n"
571  "\n"
572  "Optional OPTIONS:\n"
573  " -b, --burst <num> Test burst size.\n"
574  " -c, --cache_size <num> Pool cache size.\n"
575  " -i, --index <idx> Benchmark index to run indefinitely.\n"
576  " -r, --rounds <num> Run each test case 'num' times (default %u).\n"
577  " -t, --time <opt> Time measurement. 0: measure CPU cycles (default), 1: measure time\n"
578  " -h, --help Display help and exit.\n\n"
579  "\n", NO_PATH(progname), NO_PATH(progname), TEST_ROUNDS);
580 }
581 
589 static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
590 {
591  int opt;
592  static const struct option longopts[] = {
593  {"burst", required_argument, NULL, 'b'},
594  {"cache_size", required_argument, NULL, 'c'},
595  {"index", required_argument, NULL, 'i'},
596  {"rounds", required_argument, NULL, 'r'},
597  {"time", required_argument, NULL, 't'},
598  {"help", no_argument, NULL, 'h'},
599  {NULL, 0, NULL, 0}
600  };
601 
602  static const char *shortopts = "c:b:i:r:t:h";
603 
604  appl_args->bench_idx = 0; /* Run all benchmarks */
605  appl_args->burst_size = TEST_DEF_BURST;
606  appl_args->cache_size = -1;
607  appl_args->rounds = TEST_ROUNDS;
608  appl_args->time = 0;
609 
610  while (1) {
611  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
612 
613  if (opt == -1)
614  break; /* No more options */
615 
616  switch (opt) {
617  case 'c':
618  appl_args->cache_size = atoi(optarg);
619  break;
620  case 'b':
621  appl_args->burst_size = atoi(optarg);
622  break;
623  case 'h':
624  usage(argv[0]);
625  exit(EXIT_SUCCESS);
626  break;
627  case 'i':
628  appl_args->bench_idx = atoi(optarg);
629  break;
630  case 'r':
631  appl_args->rounds = atoi(optarg);
632  break;
633  case 't':
634  appl_args->time = atoi(optarg);
635  break;
636  default:
637  break;
638  }
639  }
640 
641  if (appl_args->burst_size < 1 ||
642  appl_args->burst_size > TEST_MAX_BURST) {
643  printf("Invalid burst size (max %d)\n", TEST_MAX_BURST);
644  exit(EXIT_FAILURE);
645  }
646 
647  if (appl_args->rounds < 1) {
648  printf("Invalid number test rounds: %d\n", appl_args->rounds);
649  exit(EXIT_FAILURE);
650  }
651 
652  optind = 1; /* Reset 'extern optind' from the getopt lib */
653 }
654 
658 static void print_info(void)
659 {
661 
662  printf("\n"
663  "odp_bench_buffer options\n"
664  "------------------------\n");
665 
666  printf("Burst size: %d\n", gbl_args->appl.burst_size);
667  printf("Buffer size: %d\n", gbl_args->buf_size);
668  printf("CPU mask: %s\n", gbl_args->cpumask_str);
669  if (gbl_args->appl.cache_size < 0)
670  printf("Pool cache size: default\n");
671  else
672  printf("Pool cache size: %d\n", gbl_args->appl.cache_size);
673  printf("Measurement unit: %s\n", gbl_args->appl.time ? "nsec" : "CPU cycles");
674  printf("Test rounds: %u\n", gbl_args->appl.rounds);
675  printf("\n");
676 }
677 
678 static int bench_buffer_export(void *data)
679 {
680  args_t *gbl_args = data;
681  int ret = 0;
682 
683  if (test_common_write("%s", gbl_args->appl.time ?
684  "Function name,Average nsec per function call\n" :
685  "Function name,Average CPU cycles per function call\n")) {
686  ret = -1;
687  goto exit;
688  }
689 
690  for (int i = 0; i < gbl_args->suite.num_bench; i++) {
691  if (test_common_write("odp_%s,%f\n",
692  gbl_args->suite.bench[i].name,
693  gbl_args->suite.result[i])) {
694  ret = -1;
695  goto exit;
696  }
697  }
698 
699 exit:
700  test_common_write_term();
701 
702  return ret;
703 }
704 
708 bench_info_t test_suite[] = {
709  BENCH_INFO(buffer_from_event, create_events, free_buffers, NULL),
710  BENCH_INFO(buffer_from_event_multi, create_events_multi, free_buffers_multi, NULL),
711  BENCH_INFO(buffer_to_event, create_buffers, free_buffers, NULL),
712  BENCH_INFO(buffer_to_event_multi, create_buffers_multi, free_buffers_multi, NULL),
713  BENCH_INFO(buffer_addr, create_buffers, free_buffers, NULL),
714  BENCH_INFO(buffer_size, create_buffers, free_buffers, NULL),
715  BENCH_INFO_COND(buffer_user_area, create_buffers, free_buffers, NULL, check_uarea),
716  BENCH_INFO(buffer_pool, create_buffers, free_buffers, NULL),
717  BENCH_INFO(buffer_alloc, NULL, free_buffers, NULL),
718  BENCH_INFO(buffer_alloc_multi, NULL, free_buffers_multi, NULL),
719  BENCH_INFO(buffer_free, create_buffers, NULL, NULL),
720  BENCH_INFO(buffer_free_multi, create_buffers_multi, NULL, NULL),
721  BENCH_INFO(buffer_alloc_free, NULL, NULL, NULL),
722  BENCH_INFO(buffer_alloc_free_multi, NULL, NULL, NULL),
723  BENCH_INFO(buffer_is_valid, create_buffers, free_buffers, NULL),
724  BENCH_INFO(event_type, create_events, free_buffers, NULL),
725  BENCH_INFO(event_subtype, create_events, free_buffers, NULL),
726  BENCH_INFO(event_types, create_events, free_buffers, NULL),
727  BENCH_INFO(event_types_multi, create_events_multi, free_buffers_multi, NULL),
728  BENCH_INFO(event_types_multi_no_sub, create_events_multi, free_buffers_multi,
729  "event_types_multi (no sub)"),
730  BENCH_INFO(event_type_multi, create_events_multi, free_buffers_multi, NULL),
731  BENCH_INFO(event_pool, create_events, free_buffers, NULL),
732  BENCH_INFO_COND(event_user_area, create_events, free_buffers, NULL, check_uarea),
733  BENCH_INFO_COND(event_user_area_and_flag, create_events, free_buffers, NULL, check_uarea),
734  BENCH_INFO(event_is_valid, create_events, free_buffers, NULL),
735  BENCH_INFO(event_free, create_events, NULL, NULL),
736  BENCH_INFO(event_free_multi, create_events_multi, NULL, NULL),
737  BENCH_INFO(event_free_sp, create_events_multi, NULL, NULL),
738  BENCH_INFO_COND(event_flow_id, create_events, free_buffers, NULL, check_flow_aware),
739  BENCH_INFO_COND(event_flow_id_set, create_events, free_buffers, NULL, check_flow_aware),
740 };
741 
742 ODP_STATIC_ASSERT(ODPH_ARRAY_SIZE(test_suite) < TEST_MAX_BENCH,
743  "Result array is too small to hold all the results");
744 
748 int main(int argc, char *argv[])
749 {
750  odph_helper_options_t helper_options;
751  test_common_options_t common_options;
752  odph_thread_t worker_thread;
753  odph_thread_common_param_t thr_common;
754  odph_thread_param_t thr_param;
755  int cpu;
756  odp_shm_t shm;
757  odp_cpumask_t cpumask, default_mask;
758  odp_schedule_capability_t sched_capa;
760  odp_pool_param_t params;
761  odp_instance_t instance;
762  odp_init_t init_param;
763  uint32_t buf_num;
764  uint8_t ret;
765 
766  /* Let helper collect its own arguments (e.g. --odph_proc) */
767  argc = odph_parse_options(argc, argv);
768  if (odph_options(&helper_options)) {
769  ODPH_ERR("Error: reading ODP helper options failed\n");
770  exit(EXIT_FAILURE);
771  }
772 
773  argc = test_common_parse_options(argc, argv);
774  if (test_common_options(&common_options)) {
775  ODPH_ERR("Error: reading test options failed\n");
776  exit(EXIT_FAILURE);
777  }
778 
779  odp_init_param_init(&init_param);
780  init_param.mem_model = helper_options.mem_model;
781 
782  /* Init ODP before calling anything else */
783  if (odp_init_global(&instance, &init_param, NULL)) {
784  ODPH_ERR("Error: ODP global init failed\n");
785  exit(EXIT_FAILURE);
786  }
787 
788  /* Init this thread */
789  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
790  ODPH_ERR("Error: ODP local init failed\n");
791  exit(EXIT_FAILURE);
792  }
793 
794  /* Reserve memory for args from shared mem */
795  shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE, 0);
796  if (shm == ODP_SHM_INVALID) {
797  ODPH_ERR("Error: shared mem reserve failed\n");
798  exit(EXIT_FAILURE);
799  }
800 
801  gbl_args = odp_shm_addr(shm);
802  if (gbl_args == NULL) {
803  ODPH_ERR("Error: shared mem alloc failed\n");
804  exit(EXIT_FAILURE);
805  }
806 
807  memset(gbl_args, 0, sizeof(args_t));
808 
809  /* Parse and store the application arguments */
810  parse_args(argc, argv, &gbl_args->appl);
811 
812  bench_suite_init(&gbl_args->suite);
813  gbl_args->suite.bench = test_suite;
814  gbl_args->suite.num_bench = ODPH_ARRAY_SIZE(test_suite);
815  gbl_args->suite.indef_idx = gbl_args->appl.bench_idx;
816  gbl_args->suite.rounds = gbl_args->appl.rounds;
817  gbl_args->suite.repeat_count = TEST_REPEAT_COUNT;
818  gbl_args->suite.measure_time = !!gbl_args->appl.time;
819  if (common_options.is_export)
820  gbl_args->suite.result = gbl_args->result;
821 
822  /* Get default worker cpumask */
823  if (odp_cpumask_default_worker(&default_mask, 1) != 1) {
824  ODPH_ERR("Error: unable to allocate worker thread\n");
825  exit(EXIT_FAILURE);
826  }
827  (void)odp_cpumask_to_str(&default_mask, gbl_args->cpumask_str,
828  sizeof(gbl_args->cpumask_str));
829 
830  if (odp_schedule_capability(&sched_capa)) {
831  ODPH_ERR("Error: schedule capability failed\n");
832  exit(EXIT_FAILURE);
833  }
834 
835  gbl_args->max_flow_id = 0;
836  if (sched_capa.max_flow_id) {
837  odp_schedule_config_t sched_config;
838 
839  odp_schedule_config_init(&sched_config);
840  sched_config.max_flow_id = 1;
841 
842  if (odp_schedule_config(&sched_config)) {
843  ODPH_ERR("Error: schedule config failed\n");
844  exit(EXIT_FAILURE);
845  }
846  gbl_args->max_flow_id = 1;
847  }
848 
849  if (odp_pool_capability(&capa)) {
850  ODPH_ERR("Error: unable to query pool capability\n");
851  exit(EXIT_FAILURE);
852  }
853 
854  buf_num = gbl_args->appl.burst_size * TEST_REPEAT_COUNT;
855 
856  if (capa.buf.max_num && capa.buf.max_num < buf_num) {
857  ODPH_ERR("Error: pool size not supported (max %" PRIu32 ")\n", capa.buf.max_num);
858  exit(EXIT_FAILURE);
859  } else if (gbl_args->appl.cache_size > (int)capa.buf.max_cache_size) {
860  ODPH_ERR("Error: cache size not supported (max %" PRIu32 ")\n",
861  capa.buf.max_cache_size);
862  exit(EXIT_FAILURE);
863  }
864 
865  gbl_args->buf_size = TEST_BUF_SIZE;
866  if (capa.buf.max_size && capa.buf.max_size < TEST_BUF_SIZE)
867  gbl_args->buf_size = capa.buf.max_size;
868 
869  gbl_args->uarea_size = TEST_UAREA_SIZE < capa.buf.max_uarea_size ?
870  TEST_UAREA_SIZE : capa.buf.max_uarea_size;
871 
872  print_info();
873 
874  /* Create buffer pool */
875  odp_pool_param_init(&params);
876  params.buf.size = gbl_args->buf_size;
877  params.buf.num = buf_num;
878  params.buf.uarea_size = gbl_args->uarea_size;
879  if (gbl_args->appl.cache_size >= 0)
880  params.buf.cache_size = gbl_args->appl.cache_size;
881  params.type = ODP_POOL_BUFFER;
882 
883  gbl_args->pool = odp_pool_create("microbench", &params);
884  if (gbl_args->pool == ODP_POOL_INVALID) {
885  ODPH_ERR("Error: pool create failed\n");
886  exit(EXIT_FAILURE);
887  }
888 
889  odp_pool_print(gbl_args->pool);
890 
891  memset(&worker_thread, 0, sizeof(odph_thread_t));
892 
893  signal(SIGINT, sig_handler);
894 
895  /* Create worker thread */
896  cpu = odp_cpumask_first(&default_mask);
897 
898  odp_cpumask_zero(&cpumask);
899  odp_cpumask_set(&cpumask, cpu);
900 
901  odph_thread_common_param_init(&thr_common);
902  thr_common.instance = instance;
903  thr_common.cpumask = &cpumask;
904  thr_common.share_param = 1;
905 
906  odph_thread_param_init(&thr_param);
907  thr_param.start = bench_run;
908  thr_param.arg = &gbl_args->suite;
909  thr_param.thr_type = ODP_THREAD_WORKER;
910 
911  odph_thread_create(&worker_thread, &thr_common, &thr_param, 1);
912 
913  odph_thread_join(&worker_thread, 1);
914 
915  ret = gbl_args->suite.retval;
916 
917  if (ret == 0 && common_options.is_export) {
918  if (bench_buffer_export(gbl_args)) {
919  ODPH_ERR("Error: Export failed\n");
920  ret = -1;
921  }
922  }
923 
924  if (odp_pool_destroy(gbl_args->pool)) {
925  ODPH_ERR("Error: pool destroy\n");
926  exit(EXIT_FAILURE);
927  }
928 
929  if (odp_shm_free(shm)) {
930  ODPH_ERR("Error: shm free\n");
931  exit(EXIT_FAILURE);
932  }
933 
934  if (odp_term_local()) {
935  ODPH_ERR("Error: term local\n");
936  exit(EXIT_FAILURE);
937  }
938 
939  if (odp_term_global(instance)) {
940  ODPH_ERR("Error: term global\n");
941  exit(EXIT_FAILURE);
942  }
943 
944  return ret;
945 }
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void * odp_buffer_user_area(odp_buffer_t buf)
Buffer user area.
uint32_t odp_buffer_size(odp_buffer_t buf)
Buffer maximum data size.
odp_event_t odp_buffer_to_event(odp_buffer_t buf)
Convert buffer handle to event.
odp_buffer_t odp_buffer_alloc(odp_pool_t pool)
Buffer alloc.
void odp_buffer_free(odp_buffer_t buf)
Buffer free.
int odp_buffer_is_valid(odp_buffer_t buf)
Check that buffer is valid.
void * odp_buffer_addr(odp_buffer_t buf)
Buffer start address.
odp_buffer_t odp_buffer_from_event(odp_event_t ev)
Get buffer handle from event.
int odp_buffer_alloc_multi(odp_pool_t pool, odp_buffer_t buf[], int num)
Allocate multiple buffers.
#define ODP_BUFFER_INVALID
Invalid buffer.
void odp_buffer_free_multi(const odp_buffer_t buf[], int num)
Free multiple buffers.
void odp_buffer_from_event_multi(odp_buffer_t buf[], const odp_event_t ev[], int num)
Convert multiple buffer events to buffer handles.
void odp_buffer_to_event_multi(const odp_buffer_t buf[], odp_event_t ev[], int num)
Convert multiple buffer handles to events.
odp_pool_t odp_buffer_pool(odp_buffer_t buf)
Buffer pool of the buffer.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
#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_...
void odp_event_free_sp(const odp_event_t event[], int num)
Free multiple events to the same pool.
void odp_event_free_multi(const odp_event_t event[], int num)
Free multiple events.
odp_event_subtype_t odp_event_subtype(odp_event_t event)
Event subtype of an event.
void odp_event_free(odp_event_t event)
Free event.
odp_pool_t odp_event_pool(odp_event_t event)
Event pool.
void odp_event_types_multi(const odp_event_t event[], odp_event_type_t type[], odp_event_subtype_t subtype[], int num)
Event types and subtypes of multiple events.
int odp_event_type_multi(const odp_event_t event[], int num, odp_event_type_t *type)
Event type of multiple events.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
odp_event_subtype_t
Event subtype.
odp_event_type_t
Event type.
void odp_event_flow_id_set(odp_event_t event, uint32_t flow_id)
Set event flow id value.
uint32_t odp_event_flow_id(odp_event_t event)
Event flow id value.
void * odp_event_user_area(odp_event_t event)
Event user area.
odp_event_type_t odp_event_types(odp_event_t event, odp_event_subtype_t *subtype)
Event type and subtype of an event.
void * odp_event_user_area_and_flag(odp_event_t event, int *flag)
Event user area and flag.
int odp_event_is_valid(odp_event_t event)
Check that event is valid.
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()
void odp_pool_print(odp_pool_t pool)
Print pool info.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_BUFFER
Buffer pool.
void odp_schedule_config_init(odp_schedule_config_t *config)
Initialize schedule configuration options.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
int odp_schedule_capability(odp_schedule_capability_t *capa)
Query scheduler capabilities.
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.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
struct odp_pool_capability_t::@121 buf
Buffer pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t max_uarea_size
Maximum user area size in bytes.
uint32_t max_size
Maximum buffer data size in bytes.
uint32_t max_cache_size
Maximum size of thread local cache.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
uint32_t cache_size
Maximum number of buffers cached locally per thread.
uint32_t size
Minimum buffer size in bytes.
odp_pool_type_t type
Pool type.
struct odp_pool_param_t::@125 buf
Parameters for buffer pools.
uint32_t max_flow_id
Maximum flow ID per queue.
Schedule configuration.
uint32_t max_flow_id
Maximum flow ID per queue.