API Reference Manual  1.50.0
odp_pool_perf.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2018 Linaro Limited
3  * Copyright (c) 2019-2026 Nokia
4  */
5 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdint.h>
17 #include <inttypes.h>
18 #include <stdlib.h>
19 #include <getopt.h>
20 
21 #include <odp_api.h>
22 #include <odp/helper/odph_api.h>
23 
24 #include <export_results.h>
25 
26 #define DEFAULT_BURST_SIZE 32
27 
28 #define STAT_AVAILABLE 0x1
29 #define STAT_CACHE 0x2
30 #define STAT_THR_CACHE 0x4
31 #define STAT_ALLOC_OPS 0x10
32 #define STAT_FREE_OPS 0x20
33 #define STAT_TOTAL_OPS 0x40
34 
35 typedef struct test_options_t {
36  uint32_t num_cpu;
37  uint32_t num_event;
38  uint32_t num_round;
39  uint32_t max_burst;
40  uint32_t num_burst;
41  uint32_t data_size;
42  uint32_t cache_size;
43  uint32_t stats_mode;
44  int pool_type;
45 
46 } test_options_t;
47 
48 typedef struct test_stat_t {
49  uint64_t rounds;
50  uint64_t frees;
51  uint64_t events;
52  uint64_t nsec;
53  uint64_t cycles;
54 
55 } test_stat_t;
56 
57 typedef struct test_global_t {
58  test_options_t test_options;
59 
60  odp_barrier_t barrier;
61  odp_pool_t pool;
62  odp_cpumask_t cpumask;
63  odph_thread_t thread_tbl[ODP_THREAD_COUNT_MAX];
64  test_stat_t stat[ODP_THREAD_COUNT_MAX];
65  test_common_options_t common_options;
66 
67 } test_global_t;
68 
69 static void print_usage(void)
70 {
71  printf("\n"
72  "Pool performance test\n"
73  "\n"
74  "Usage: odp_pool_perf [options]\n"
75  "\n"
76  " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default 1.\n"
77  " -e, --num_event Number of events\n"
78  " -r, --num_round Number of rounds\n"
79  " -b, --burst Maximum number of events per operation (default %d). When 0, single\n"
80  " event alloc/free functions are used instead of multi event variants.\n"
81  " -n, --num_burst Number of bursts allocated/freed back-to-back\n"
82  " -s, --data_size Data size in bytes\n"
83  " -S, --stats_mode Pool statistics usage. Enable counters with combination of these flags:\n"
84  " 0: no pool statistics (default)\n"
85  " 0x1: available\n"
86  " 0x2: cache_available\n"
87  " 0x4: thread_cache_available\n"
88  " 0x10: alloc_ops\n"
89  " 0x20: free_ops\n"
90  " 0x40: total_ops\n"
91  " -t, --pool_type 0: Buffer pool (default)\n"
92  " 1: Packet pool\n"
93  " -C, --cache_size Pool cache size (per thread)\n"
94  " -h, --help This help\n"
95  "\n", DEFAULT_BURST_SIZE);
96 }
97 
98 static int parse_options(int argc, char *argv[], test_options_t *test_options)
99 {
100  int opt;
101  int ret = 0;
102 
103  static const struct option longopts[] = {
104  {"num_cpu", required_argument, NULL, 'c'},
105  {"num_event", required_argument, NULL, 'e'},
106  {"num_round", required_argument, NULL, 'r'},
107  {"burst", required_argument, NULL, 'b'},
108  {"num_burst", required_argument, NULL, 'n'},
109  {"data_size", required_argument, NULL, 's'},
110  {"stats_mode", required_argument, NULL, 'S'},
111  {"pool_type", required_argument, NULL, 't'},
112  {"cache_size", required_argument, NULL, 'C'},
113  {"help", no_argument, NULL, 'h'},
114  {NULL, 0, NULL, 0}
115  };
116 
117  static const char *shortopts = "+c:e:r:b:n:s:S:t:C:h";
118 
119  test_options->num_cpu = 1;
120  test_options->num_event = 1000;
121  test_options->num_round = 100000;
122  test_options->max_burst = DEFAULT_BURST_SIZE;
123  test_options->num_burst = 1;
124  test_options->data_size = 64;
125  test_options->stats_mode = 0;
126  test_options->pool_type = 0;
127  test_options->cache_size = UINT32_MAX;
128 
129  while (1) {
130  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
131 
132  if (opt == -1)
133  break;
134 
135  switch (opt) {
136  case 'c':
137  test_options->num_cpu = atoi(optarg);
138  break;
139  case 'e':
140  test_options->num_event = atoi(optarg);
141  break;
142  case 'r':
143  test_options->num_round = atoi(optarg);
144  break;
145  case 'b':
146  test_options->max_burst = atoi(optarg);
147  break;
148  case 'n':
149  test_options->num_burst = atoi(optarg);
150  break;
151  case 's':
152  test_options->data_size = atoi(optarg);
153  break;
154  case 'S':
155  test_options->stats_mode = strtoul(optarg, NULL, 0);
156  break;
157  case 't':
158  test_options->pool_type = atoi(optarg);
159  break;
160  case 'C':
161  test_options->cache_size = atoi(optarg);
162  break;
163  case 'h':
164  /* fall through */
165  default:
166  print_usage();
167  ret = -1;
168  break;
169  }
170  }
171 
172  if (test_options->num_burst * ODPH_MAX(test_options->max_burst, 1U) >
173  test_options->num_event) {
174  printf("Not enough events (%u) for the burst configuration.\n"
175  "Use smaller burst size (%u) or less bursts (%u)\n",
176  test_options->num_event, test_options->max_burst,
177  test_options->num_burst);
178  ret = -1;
179  }
180 
181  return ret;
182 }
183 
184 static int set_num_cpu(test_global_t *global)
185 {
186  int ret;
187  test_options_t *test_options = &global->test_options;
188  int num_cpu = test_options->num_cpu;
189 
190  /* One thread used for the main thread */
191  if (num_cpu > ODP_THREAD_COUNT_MAX - 1) {
192  printf("Error: Too many workers. Maximum is %i.\n",
194  return -1;
195  }
196 
197  ret = odp_cpumask_default_worker(&global->cpumask, num_cpu);
198 
199  if (num_cpu && ret != num_cpu) {
200  printf("Error: Too many workers. Max supported %i.\n", ret);
201  return -1;
202  }
203 
204  /* Zero: all available workers */
205  if (num_cpu == 0) {
206  num_cpu = ret;
207  test_options->num_cpu = num_cpu;
208  }
209 
210  odp_barrier_init(&global->barrier, num_cpu);
211 
212  return 0;
213 }
214 
215 static int create_pool(test_global_t *global)
216 {
217  odp_pool_capability_t pool_capa;
218  odp_pool_param_t pool_param;
219  odp_pool_t pool;
220  odp_pool_stats_opt_t stats, stats_capa;
221  uint32_t max_num, max_size, min_cache_size, max_cache_size;
222  test_options_t *test_options = &global->test_options;
223  uint32_t num_event = test_options->num_event;
224  uint32_t num_round = test_options->num_round;
225  uint32_t max_burst = test_options->max_burst;
226  uint32_t num_burst = test_options->num_burst;
227  uint32_t num_cpu = test_options->num_cpu;
228  uint32_t data_size = test_options->data_size;
229  uint32_t cache_size = test_options->cache_size;
230  uint32_t stats_mode = test_options->stats_mode;
231  int packet_pool = test_options->pool_type;
232 
233  stats.all = 0;
234 
235  odp_pool_param_init(&pool_param);
236 
237  if (cache_size == UINT32_MAX)
238  cache_size = packet_pool ? pool_param.pkt.cache_size :
239  pool_param.buf.cache_size;
240 
241  if (stats_mode & STAT_AVAILABLE)
242  stats.bit.available = 1;
243  if (stats_mode & STAT_CACHE)
244  stats.bit.cache_available = 1;
245  if (stats_mode & STAT_THR_CACHE)
246  stats.bit.thread_cache_available = 1;
247  if (stats_mode & STAT_ALLOC_OPS)
248  stats.bit.alloc_ops = 1;
249  if (stats_mode & STAT_FREE_OPS)
250  stats.bit.free_ops = 1;
251  if (stats_mode & STAT_TOTAL_OPS)
252  stats.bit.total_ops = 1;
253 
254  printf("\nPool performance test\n");
255  printf(" num cpu %u\n", num_cpu);
256  printf(" num rounds %u\n", num_round);
257  printf(" num events %u\n", num_event);
258  printf(" max burst %u\n", max_burst);
259  printf(" num bursts %u\n", num_burst);
260  printf(" data size %u\n", data_size);
261  printf(" cache size %u\n", cache_size);
262  printf(" stats mode 0x%x\n", stats_mode);
263  printf(" pool type %s\n", packet_pool ? "packet" : "buffer");
264  printf(" op type %s\n\n", test_options->max_burst == 0 ? "single" : "multi");
265 
266  if (odp_pool_capability(&pool_capa)) {
267  printf("Error: Pool capa failed.\n");
268  return -1;
269  }
270 
271  if (packet_pool) {
272  max_num = pool_capa.pkt.max_num;
273  max_size = pool_capa.pkt.max_len;
274  max_cache_size = pool_capa.pkt.max_cache_size;
275  min_cache_size = pool_capa.pkt.min_cache_size;
276  stats_capa = pool_capa.pkt.stats;
277  } else {
278  max_num = pool_capa.buf.max_num;
279  max_size = pool_capa.buf.max_size;
280  max_cache_size = pool_capa.buf.max_cache_size;
281  min_cache_size = pool_capa.buf.min_cache_size;
282  stats_capa = pool_capa.buf.stats;
283  }
284 
285  if ((stats_capa.all & stats.all) != stats.all) {
286  printf("Error: requested statistics not supported (0x%" PRIx64 " / 0x%" PRIx64 ")\n",
287  stats.all, stats_capa.all);
288  return -1;
289  }
290 
291  if (cache_size < min_cache_size) {
292  printf("Error: min cache size supported %u\n", min_cache_size);
293  return -1;
294  }
295 
296  if (cache_size > max_cache_size) {
297  printf("Error: max cache size supported %u\n", max_cache_size);
298  return -1;
299  }
300 
301  if (max_num && num_event > max_num) {
302  printf("Error: max events supported %u\n", max_num);
303  return -1;
304  }
305 
306  if (max_size && data_size > max_size) {
307  printf("Error: max data size supported %u\n", max_size);
308  return -1;
309  }
310 
311  if (packet_pool) {
312  pool_param.type = ODP_POOL_PACKET;
313  pool_param.pkt.num = num_event;
314  pool_param.pkt.len = data_size;
315  pool_param.pkt.max_num = num_event;
316  pool_param.pkt.max_len = data_size;
317  pool_param.pkt.cache_size = cache_size;
318  } else {
319  pool_param.type = ODP_POOL_BUFFER;
320  pool_param.buf.num = num_event;
321  pool_param.buf.size = data_size;
322  pool_param.buf.cache_size = cache_size;
323  }
324 
325  pool_param.stats.all = stats.all;
326 
327  pool = odp_pool_create("pool perf", &pool_param);
328 
329  if (pool == ODP_POOL_INVALID) {
330  printf("Error: Pool create failed.\n");
331  return -1;
332  }
333 
334  global->pool = pool;
335 
336  return 0;
337 }
338 
339 static inline void record_results(test_stat_t *stats, uint64_t start_cycles, odp_time_t start_time,
340  uint64_t rounds, uint64_t frees, uint64_t events)
341 {
342  uint64_t finish_cycles = odp_cpu_cycles();
343  odp_time_t finish_time = odp_time_local();
344 
345  stats->rounds = rounds;
346  stats->frees = frees;
347  stats->events = events;
348  stats->nsec = odp_time_diff_ns(finish_time, start_time);
349  stats->cycles = odp_cpu_cycles_diff(finish_cycles, start_cycles);
350 }
351 
352 static int test_buffer_pool(void *arg)
353 {
354  int ret, thr;
355  uint32_t num, num_free, num_freed, i, rounds;
356  uint64_t start_cycles, events, frees;
357  odp_time_t start_time;
358  test_global_t *global = arg;
359  test_options_t *test_options = &global->test_options;
360  uint32_t num_round = test_options->num_round;
361  uint32_t max_burst = test_options->max_burst;
362  uint32_t num_burst = test_options->num_burst;
363  uint32_t max_num = num_burst * max_burst;
364  odp_pool_t pool = global->pool;
365  odp_buffer_t buf[max_num];
366 
367  thr = odp_thread_id();
368 
369  for (i = 0; i < max_num; i++)
370  buf[i] = ODP_BUFFER_INVALID;
371 
372  events = 0;
373  frees = 0;
374  ret = 0;
375 
376  /* Start all workers at the same time */
377  odp_barrier_wait(&global->barrier);
378 
379  start_time = odp_time_local();
380  start_cycles = odp_cpu_cycles();
381 
382  for (rounds = 0; rounds < num_round; rounds++) {
383  num = 0;
384 
385  for (i = 0; i < num_burst; i++) {
386  ret = odp_buffer_alloc_multi(pool, &buf[num],
387  max_burst);
388  if (odp_unlikely(ret < 0)) {
389  printf("Error: Alloc failed. Round %u\n",
390  rounds);
391  if (num)
392  odp_buffer_free_multi(buf, num);
393 
394  return -1;
395  }
396 
397  num += ret;
398  }
399 
400  if (odp_unlikely(num == 0))
401  continue;
402 
403  events += num;
404  num_freed = 0;
405 
406  while (num_freed < num) {
407  num_free = num - num_freed;
408  if (num_free > max_burst)
409  num_free = max_burst;
410 
411  odp_buffer_free_multi(&buf[num_freed], num_free);
412  frees++;
413  num_freed += num_free;
414  }
415  }
416 
417  record_results(&global->stat[thr], start_cycles, start_time, rounds, frees, events);
418 
419  return 0;
420 }
421 
422 static int test_buffer_pool_single(void *arg)
423 {
424  int thr;
425  uint32_t num, num_freed, i, rounds;
426  uint64_t start_cycles, events, frees;
427  odp_time_t start_time;
428  test_global_t *global = arg;
429  test_options_t *test_options = &global->test_options;
430  uint32_t num_round = test_options->num_round;
431  uint32_t num_burst = test_options->num_burst;
432  odp_pool_t pool = global->pool;
433  odp_buffer_t buf[num_burst];
434 
435  thr = odp_thread_id();
436 
437  for (i = 0; i < num_burst; i++)
438  buf[i] = ODP_BUFFER_INVALID;
439 
440  events = 0;
441  frees = 0;
442 
443  /* Start all workers at the same time */
444  odp_barrier_wait(&global->barrier);
445 
446  start_time = odp_time_local();
447  start_cycles = odp_cpu_cycles();
448 
449  for (rounds = 0; rounds < num_round; rounds++) {
450  num = 0;
451 
452  for (i = 0; i < num_burst; i++) {
453  buf[num] = odp_buffer_alloc(pool);
454 
455  if (odp_unlikely(buf[num] == ODP_BUFFER_INVALID))
456  continue;
457  num++;
458  }
459 
460  if (odp_unlikely(num == 0))
461  continue;
462 
463  events += num;
464  num_freed = 0;
465 
466  while (num_freed < num) {
467  odp_buffer_free(buf[num_freed]);
468  frees++;
469  num_freed++;
470  }
471  }
472 
473  record_results(&global->stat[thr], start_cycles, start_time, rounds, frees, events);
474 
475  return 0;
476 }
477 
478 static int test_packet_pool(void *arg)
479 {
480  int ret, thr;
481  uint32_t num, num_free, num_freed, i, rounds;
482  uint64_t start_cycles, events, frees;
483  odp_time_t start_time;
484  test_global_t *global = arg;
485  test_options_t *test_options = &global->test_options;
486  uint32_t num_round = test_options->num_round;
487  uint32_t max_burst = test_options->max_burst;
488  uint32_t num_burst = test_options->num_burst;
489  uint32_t max_num = num_burst * max_burst;
490  uint32_t data_size = test_options->data_size;
491  odp_pool_t pool = global->pool;
492  odp_packet_t pkt[max_num];
493 
494  thr = odp_thread_id();
495 
496  for (i = 0; i < max_num; i++)
497  pkt[i] = ODP_PACKET_INVALID;
498 
499  events = 0;
500  frees = 0;
501  ret = 0;
502 
503  /* Start all workers at the same time */
504  odp_barrier_wait(&global->barrier);
505 
506  start_time = odp_time_local();
507  start_cycles = odp_cpu_cycles();
508 
509  for (rounds = 0; rounds < num_round; rounds++) {
510  num = 0;
511 
512  for (i = 0; i < num_burst; i++) {
513  ret = odp_packet_alloc_multi(pool, data_size, &pkt[num],
514  max_burst);
515  if (odp_unlikely(ret < 0)) {
516  printf("Error: Alloc failed. Round %u\n",
517  rounds);
518 
519  if (num)
520  odp_packet_free_multi(pkt, num);
521 
522  return -1;
523  }
524 
525  num += ret;
526  }
527 
528  if (odp_unlikely(num == 0))
529  continue;
530 
531  events += num;
532  num_freed = 0;
533 
534  while (num_freed < num) {
535  num_free = num - num_freed;
536  if (num_free > max_burst)
537  num_free = max_burst;
538 
539  odp_packet_free_multi(&pkt[num_freed], num_free);
540  frees++;
541  num_freed += num_free;
542  }
543  }
544 
545  record_results(&global->stat[thr], start_cycles, start_time, rounds, frees, events);
546 
547  return 0;
548 }
549 
550 static int test_packet_pool_single(void *arg)
551 {
552  int thr;
553  uint32_t num, num_freed, i, rounds;
554  uint64_t start_cycles, events, frees;
555  odp_time_t start_time;
556  test_global_t *global = arg;
557  test_options_t *test_options = &global->test_options;
558  uint32_t num_round = test_options->num_round;
559  uint32_t num_burst = test_options->num_burst;
560  uint32_t data_size = test_options->data_size;
561  odp_pool_t pool = global->pool;
562  odp_packet_t pkt[num_burst];
563 
564  thr = odp_thread_id();
565 
566  for (i = 0; i < num_burst; i++)
567  pkt[i] = ODP_PACKET_INVALID;
568 
569  events = 0;
570  frees = 0;
571 
572  /* Start all workers at the same time */
573  odp_barrier_wait(&global->barrier);
574 
575  start_time = odp_time_local();
576  start_cycles = odp_cpu_cycles();
577 
578  for (rounds = 0; rounds < num_round; rounds++) {
579  num = 0;
580 
581  for (i = 0; i < num_burst; i++) {
582  pkt[num] = odp_packet_alloc(pool, data_size);
583 
584  if (odp_unlikely(pkt[num] == ODP_PACKET_INVALID))
585  continue;
586 
587  num++;
588  }
589 
590  if (odp_unlikely(num == 0))
591  continue;
592 
593  events += num;
594  num_freed = 0;
595 
596  while (num_freed < num) {
597  odp_packet_free(pkt[num_freed]);
598  frees++;
599  num_freed++;
600  }
601  }
602 
603  record_results(&global->stat[thr], start_cycles, start_time, rounds, frees, events);
604 
605  return 0;
606 }
607 
608 static int start_workers(test_global_t *global, odp_instance_t instance)
609 {
610  odph_thread_common_param_t thr_common;
611  odph_thread_param_t thr_param;
612  test_options_t *test_options = &global->test_options;
613  int num_cpu = test_options->num_cpu;
614  int packet_pool = test_options->pool_type;
615 
616  odph_thread_common_param_init(&thr_common);
617  thr_common.instance = instance;
618  thr_common.cpumask = &global->cpumask;
619  thr_common.share_param = 1;
620 
621  odph_thread_param_init(&thr_param);
622  thr_param.arg = global;
623  thr_param.thr_type = ODP_THREAD_WORKER;
624 
625  if (test_options->max_burst == 0)
626  thr_param.start = packet_pool ? test_packet_pool_single : test_buffer_pool_single;
627  else
628  thr_param.start = packet_pool ? test_packet_pool : test_buffer_pool;
629 
630  if (odph_thread_create(global->thread_tbl, &thr_common, &thr_param,
631  num_cpu) != num_cpu)
632  return -1;
633 
634  return 0;
635 }
636 
637 static void test_stats_perf(test_global_t *global)
638 {
639  odp_pool_stats_t stats;
640  odp_time_t t1, t2;
641  uint64_t nsec;
642  int i;
643  int num_thr = global->test_options.num_cpu + 1; /* workers + main thread */
644  odp_pool_t pool = global->pool;
645  double nsec_ave = 0.0;
646  const int rounds = 1000;
647 
648  if (num_thr > ODP_POOL_MAX_THREAD_STATS)
649  num_thr = ODP_POOL_MAX_THREAD_STATS;
650 
651  memset(&stats, 0, sizeof(odp_pool_stats_t));
652  stats.thread.first = 0;
653  stats.thread.last = num_thr - 1;
654 
655  t1 = odp_time_local_strict();
656 
657  for (i = 0; i < rounds; i++) {
658  if (odp_pool_stats(pool, &stats)) {
659  printf("Error: Stats request failed on round %i\n", i);
660  break;
661  }
662  }
663 
664  t2 = odp_time_local_strict();
665  nsec = odp_time_diff_ns(t2, t1);
666 
667  if (i > 0)
668  nsec_ave = (double)nsec / i;
669 
670  printf("Pool statistics:\n");
671  printf(" odp_pool_stats() calls %i\n", i);
672  printf(" ave call latency %.2f nsec\n", nsec_ave);
673  printf(" num threads %i\n", num_thr);
674  printf(" alloc_ops %" PRIu64 "\n", stats.alloc_ops);
675  printf(" free_ops %" PRIu64 "\n", stats.free_ops);
676  printf(" total_ops %" PRIu64 "\n", stats.total_ops);
677  printf(" available %" PRIu64 "\n", stats.available);
678  printf(" cache_available %" PRIu64 "\n", stats.cache_available);
679  for (i = 0; i < num_thr; i++) {
680  printf(" thr[%2i] cache_available %" PRIu64 "\n",
681  i, stats.thread.cache_available[i]);
682  }
683 
684  printf("\n");
685 }
686 
687 static int output_results(test_global_t *global)
688 {
689  int i, num;
690  double rounds_ave, allocs_ave, frees_ave;
691  double events_ave, nsec_ave, cycles_ave;
692  test_options_t *test_options = &global->test_options;
693  int num_cpu = test_options->num_cpu;
694  uint32_t num_burst = test_options->num_burst;
695  uint64_t rounds_sum = 0;
696  uint64_t frees_sum = 0;
697  uint64_t events_sum = 0;
698  uint64_t nsec_sum = 0;
699  uint64_t cycles_sum = 0;
700 
701  /* Averages */
702  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
703  rounds_sum += global->stat[i].rounds;
704  frees_sum += global->stat[i].frees;
705  events_sum += global->stat[i].events;
706  nsec_sum += global->stat[i].nsec;
707  cycles_sum += global->stat[i].cycles;
708  }
709 
710  if (rounds_sum == 0) {
711  printf("No results.\n");
712  return 0;
713  }
714 
715  rounds_ave = rounds_sum / num_cpu;
716  allocs_ave = (num_burst * rounds_sum) / num_cpu;
717  frees_ave = frees_sum / num_cpu;
718  events_ave = events_sum / num_cpu;
719  nsec_ave = nsec_sum / num_cpu;
720  cycles_ave = cycles_sum / num_cpu;
721  num = 0;
722 
723  printf("RESULTS - per thread (Million events per sec):\n");
724  printf("----------------------------------------------\n");
725  printf(" 1 2 3 4 5 6 7 8 9 10");
726 
727  for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
728  if (global->stat[i].rounds) {
729  if ((num % 10) == 0)
730  printf("\n ");
731 
732  printf("%6.1f ", (1000.0 * global->stat[i].events) /
733  global->stat[i].nsec);
734  num++;
735  }
736  }
737  printf("\n\n");
738 
739  printf("RESULTS - average over %i threads:\n", num_cpu);
740  printf("----------------------------------\n");
741  printf(" alloc calls: %.3f\n", allocs_ave);
742  printf(" free calls: %.3f\n", frees_ave);
743  printf(" duration: %.3f msec\n", nsec_ave / 1000000);
744  printf(" num cycles: %.3f M\n", cycles_ave / 1000000);
745  printf(" cycles per round: %.3f\n",
746  cycles_ave / rounds_ave);
747  printf(" cycles per event: %.3f\n",
748  cycles_ave / events_ave);
749  printf(" ave events allocated: %.3f\n",
750  events_ave / allocs_ave);
751  printf(" allocs per sec: %.3f M\n",
752  (1000.0 * allocs_ave) / nsec_ave);
753  printf(" frees per sec: %.3f M\n",
754  (1000.0 * frees_ave) / nsec_ave);
755  printf(" events per sec: %.3f M\n\n",
756  (1000.0 * events_ave) / nsec_ave);
757 
758  printf("TOTAL events per sec: %.3f M\n\n",
759  (1000.0 * events_sum) / nsec_ave);
760 
761  if (global->common_options.is_export) {
762  if (test_common_write("alloc calls,free calls,duration (msec),"
763  "num cycles (M),cycles per round,cycles per event,"
764  "ave events allocated,allocs per sec (M),frees per sec (M),"
765  "events per sec (M),total events per sec (M)\n")) {
766  ODPH_ERR("Export failed\n");
767  test_common_write_term();
768  return -1;
769  }
770 
771  if (test_common_write("%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
772  allocs_ave, frees_ave, nsec_ave / 1000000,
773  cycles_ave / 1000000, cycles_ave / rounds_ave,
774  cycles_ave / events_ave, events_ave / allocs_ave,
775  (1000.0 * allocs_ave) / nsec_ave,
776  (1000.0 * frees_ave) / nsec_ave,
777  (1000.0 * events_ave) / nsec_ave,
778  (1000.0 * events_sum) / nsec_ave)) {
779  ODPH_ERR("Export failed\n");
780  test_common_write_term();
781  return -1;
782  }
783 
784  test_common_write_term();
785  }
786 
787  return 0;
788 }
789 
790 int main(int argc, char **argv)
791 {
792  odph_helper_options_t helper_options;
793  odp_instance_t instance;
794  odp_init_t init;
795  odp_shm_t shm;
796  test_global_t *global;
797  test_common_options_t common_options;
798 
799  /* Let helper collect its own arguments (e.g. --odph_proc) */
800  argc = odph_parse_options(argc, argv);
801  if (odph_options(&helper_options)) {
802  ODPH_ERR("Error: Reading ODP helper options failed.\n");
803  exit(EXIT_FAILURE);
804  }
805 
806  argc = test_common_parse_options(argc, argv);
807  if (test_common_options(&common_options)) {
808  ODPH_ERR("Error: Reading test options failed\n");
809  exit(EXIT_FAILURE);
810  }
811 
812  /* List features not to be used */
813  odp_init_param_init(&init);
814  init.not_used.feat.cls = 1;
815  init.not_used.feat.compress = 1;
816  init.not_used.feat.crypto = 1;
817  init.not_used.feat.ipsec = 1;
818  init.not_used.feat.schedule = 1;
819  init.not_used.feat.timer = 1;
820  init.not_used.feat.tm = 1;
821 
822  init.mem_model = helper_options.mem_model;
823 
824  /* Init ODP before calling anything else */
825  if (odp_init_global(&instance, &init, NULL)) {
826  printf("Error: Global init failed.\n");
827  return -1;
828  }
829 
830  /* Init this thread */
831  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
832  printf("Error: Local init failed.\n");
833  return -1;
834  }
835 
836  shm = odp_shm_reserve("pool_perf_global", sizeof(test_global_t), ODP_CACHE_LINE_SIZE, 0);
837  if (shm == ODP_SHM_INVALID) {
838  ODPH_ERR("Error: Shared mem reserve failed.\n");
839  exit(EXIT_FAILURE);
840  }
841 
842  global = odp_shm_addr(shm);
843  if (global == NULL) {
844  ODPH_ERR("Error: Shared mem alloc failed\n");
845  exit(EXIT_FAILURE);
846  }
847 
848  memset(global, 0, sizeof(test_global_t));
849  global->pool = ODP_POOL_INVALID;
850 
851  global->common_options = common_options;
852 
853  if (parse_options(argc, argv, &global->test_options))
854  return -1;
855 
857 
858  if (set_num_cpu(global))
859  return -1;
860 
861  if (create_pool(global))
862  return -1;
863 
864  /* Start workers */
865  start_workers(global, instance);
866 
867  /* Wait workers to exit */
868  odph_thread_join(global->thread_tbl, global->test_options.num_cpu);
869 
870  if (global->test_options.stats_mode)
871  test_stats_perf(global);
872 
873  if (output_results(global))
874  return -1;
875 
876  if (odp_pool_destroy(global->pool)) {
877  printf("Error: Pool destroy failed.\n");
878  return -1;
879  }
880 
881  if (odp_shm_free(shm)) {
882  ODPH_ERR("Error: Shared mem free failed.\n");
883  exit(EXIT_FAILURE);
884  }
885 
886  if (odp_term_local()) {
887  printf("Error: term local failed.\n");
888  return -1;
889  }
890 
891  if (odp_term_global(instance)) {
892  printf("Error: term global failed.\n");
893  return -1;
894  }
895 
896  return 0;
897 }
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.
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_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.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
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_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_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
void odp_packet_free(odp_packet_t pkt)
Free packet.
#define ODP_PACKET_INVALID
Invalid packet.
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
int odp_packet_alloc_multi(odp_pool_t pool, uint32_t len, odp_packet_t pkt[], int num)
Allocate multiple packets from a packet pool.
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_MAX_THREAD_STATS
Maximum number of per thread statistics a single odp_pool_stats() call can read.
int odp_pool_stats(odp_pool_t pool, odp_pool_stats_t *stats)
Read pool statistics.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_BUFFER
Buffer pool.
@ ODP_POOL_PACKET
Packet pool.
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.
odp_time_t odp_time_local(void)
Current local time.
odp_time_t odp_time_local_strict(void)
Current local time (strict)
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
struct odp_pool_capability_t::@133 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t min_cache_size
Minimum size of thread local cache.
uint32_t max_size
Maximum buffer data size in bytes.
odp_pool_stats_opt_t stats
Supported statistics counters.
struct odp_pool_capability_t::@132 buf
Buffer pool capabilities
uint32_t max_cache_size
Maximum size of thread local cache.
uint32_t max_len
Maximum packet data length in bytes.
Pool parameters.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@137 buf
Parameters for buffer pools.
uint32_t max_len
Maximum packet length that will be allocated from the pool.
uint32_t cache_size
Maximum number of buffers cached locally per thread.
struct odp_pool_param_t::@138 pkt
Parameters for packet pools.
uint32_t size
Minimum buffer size in bytes.
uint32_t max_num
Maximum number of packets.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
odp_pool_stats_opt_t stats
Configure statistics counters.
Pool statistics counters.
uint64_t alloc_ops
The number of alloc operations from the pool.
uint64_t available
The number of available events in the pool.
uint16_t first
First thread identifier to read counters from.
uint64_t free_ops
The number of free operations to the pool.
uint64_t total_ops
The total number of alloc and free operations.
uint64_t cache_available
The number of available events in the local caches of all threads.
uint16_t last
Last thread identifier to read counters from.
struct odp_pool_stats_t::@131 thread
Per thread counters.
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 timer
Timer APIs, e.g., odp_timer_xxx(), odp_timeout_xxx()
uint32_t cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
struct odp_feature_t::@173 feat
Individual feature bits.
uint32_t schedule
Scheduler APIs, e.g., odp_schedule_xxx()
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()
Pool statistics counters options.
uint64_t total_ops
See odp_pool_stats_t::total_ops.
uint64_t cache_available
See odp_pool_stats_t::cache_available.
struct odp_pool_stats_opt_t::@130 bit
Option flags.
uint64_t thread_cache_available
See odp_pool_stats_t::thread::cache_available.
uint64_t free_ops
See odp_pool_stats_t::free_ops.
uint64_t alloc_ops
See odp_pool_stats_t::alloc_ops.
uint64_t available
See odp_pool_stats_t::available.
uint64_t all
All bits of the bit field structure.