API Reference Manual 1.51.0
Loading...
Searching...
No Matches
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
35typedef 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
48typedef 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
57typedef 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
69static 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
98static 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
184static 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
215static 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
339static 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
352static 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
422static 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
478static 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
550static 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
608static 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
637static 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)
650
651 memset(&stats, 0, sizeof(odp_pool_stats_t));
652 stats.thread.first = 0;
653 stats.thread.last = num_thr - 1;
654
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
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
687static 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
790int 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.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
#define ODP_SHM_INVALID
Invalid shared memory block.
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.
uint32_t max_num
Maximum number of buffers of any size.
uint32_t min_cache_size
Minimum size of thread local cache.
struct odp_pool_capability_t::@133 buf
Buffer pool capabilities
struct odp_pool_capability_t::@134 pkt
Packet pool capabilities
uint32_t max_size
Maximum buffer data size in bytes.
odp_pool_stats_opt_t stats
Supported statistics counters.
uint32_t max_cache_size
Maximum size of thread local cache.
uint32_t max_len
Maximum packet data length in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@139 pkt
Parameters for packet 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.
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.
struct odp_pool_param_t::@138 buf
Parameters for buffer pools.
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.
struct odp_pool_stats_t::@132 thread
Per thread counters.
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.
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::@174 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.
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.
struct odp_pool_stats_opt_t::@131 bit
Option flags.