15 #include <odp/helper/odph_api.h>
17 #include <bench_common.h>
18 #include <export_results.h>
27 #define TEST_BUF_SIZE 1024
30 #define TEST_UAREA_SIZE 8
33 #define TEST_REPEAT_COUNT 1000
36 #define TEST_ROUNDS 100u
39 #define TEST_MAX_BURST 64
42 #define TEST_DEF_BURST 8
45 #define TEST_MAX_BENCH 40
48 #define NO_PATH(file_name) (strrchr((file_name), '/') ? \
49 strrchr((file_name), '/') + 1 : (file_name))
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}
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, \
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];
100 double result[TEST_MAX_BENCH];
104 static args_t *gbl_args;
108 if (gbl_args == NULL)
113 static void allocate_test_buffers(
odp_buffer_t buf[],
int num)
117 while (num_buf < num) {
122 ODPH_ABORT(
"Allocating test buffers failed\n");
128 static void create_buffers(
void)
130 allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
133 static void create_buffers_multi(
void)
135 allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
138 static void create_events(
void)
142 allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
144 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
148 static void create_events_multi(
void)
152 allocate_test_buffers(gbl_args->buf_tbl,
153 TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
155 for (
int i = 0; i < TEST_REPEAT_COUNT * gbl_args->appl.burst_size; i++)
159 static void free_buffers(
void)
164 static void free_buffers_multi(
void)
169 static int check_uarea(
void)
171 return !!gbl_args->uarea_size;
174 static int check_flow_aware(
void)
176 return !!gbl_args->max_flow_id;
179 static int buffer_from_event(
void)
185 for (i = 0; i < TEST_REPEAT_COUNT; i++)
191 static int buffer_from_event_multi(
void)
195 int burst_size = gbl_args->appl.burst_size;
198 for (i = 0; i < TEST_REPEAT_COUNT; i++)
200 &event_tbl[i * burst_size], burst_size);
205 static int buffer_to_event(
void)
211 for (i = 0; i < TEST_REPEAT_COUNT; i++)
217 static int buffer_to_event_multi(
void)
221 int burst_size = gbl_args->appl.burst_size;
224 for (i = 0; i < TEST_REPEAT_COUNT; i++)
226 &event_tbl[i * burst_size], burst_size);
231 static int buffer_addr(
void)
234 void **ptr_tbl = gbl_args->ptr_tbl;
237 for (i = 0; i < TEST_REPEAT_COUNT; i++)
243 static int buffer_size(
void)
248 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
254 static int buffer_user_area(
void)
257 void **ptr_tbl = gbl_args->ptr_tbl;
260 for (i = 0; i < TEST_REPEAT_COUNT; i++)
266 static int buffer_pool(
void)
272 for (i = 0; i < TEST_REPEAT_COUNT; i++)
278 static int buffer_alloc(
void)
284 for (i = 0; i < TEST_REPEAT_COUNT; i++)
290 static int buffer_alloc_multi(
void)
294 int burst_size = gbl_args->appl.burst_size;
297 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
303 static int buffer_free(
void)
308 for (i = 0; i < TEST_REPEAT_COUNT; i++)
314 static int buffer_free_multi(
void)
317 int burst_size = gbl_args->appl.burst_size;
320 for (i = 0; i < TEST_REPEAT_COUNT; i++)
326 static int buffer_alloc_free(
void)
331 for (i = 0; i < TEST_REPEAT_COUNT; i++) {
342 static int buffer_alloc_free_multi(
void)
346 int burst_size = gbl_args->appl.burst_size;
349 for (i = 0; i < TEST_REPEAT_COUNT; i++) {
360 static int buffer_is_valid(
void)
365 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
371 static int event_type(
void)
377 for (i = 0; i < TEST_REPEAT_COUNT; i++)
383 static int event_subtype(
void)
389 for (i = 0; i < TEST_REPEAT_COUNT; i++)
395 static int event_types(
void)
402 for (i = 0; i < TEST_REPEAT_COUNT; i++)
403 event_type_tbl[i] =
odp_event_types(event_tbl[i], &event_subtype_tbl[i]);
408 static int event_types_multi(
void)
413 int burst_size = gbl_args->appl.burst_size;
416 for (i = 0; i < TEST_REPEAT_COUNT; i++)
418 &event_type_tbl[i * burst_size],
419 &event_subtype_tbl[i * burst_size], burst_size);
424 static int event_types_multi_no_sub(
void)
428 int burst_size = gbl_args->appl.burst_size;
431 for (i = 0; i < TEST_REPEAT_COUNT; i++)
433 &event_type_tbl[i * burst_size], NULL, burst_size);
438 static int event_type_multi(
void)
442 int burst_size = gbl_args->appl.burst_size;
445 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
452 static int event_pool(
void)
458 for (i = 0; i < TEST_REPEAT_COUNT; i++)
464 static int event_user_area(
void)
467 void **ptr_tbl = gbl_args->ptr_tbl;
470 for (i = 0; i < TEST_REPEAT_COUNT; i++)
476 static int event_user_area_and_flag(
void)
479 void **ptr_tbl = gbl_args->ptr_tbl;
483 for (
int i = 0; i < TEST_REPEAT_COUNT; i++) {
491 static int event_is_valid(
void)
497 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
503 static int event_free(
void)
509 for (i = 0; i < TEST_REPEAT_COUNT; i++)
515 static int event_free_multi(
void)
518 int burst_size = gbl_args->appl.burst_size;
521 for (i = 0; i < TEST_REPEAT_COUNT; i++)
527 static int event_free_sp(
void)
530 int burst_size = gbl_args->appl.burst_size;
533 for (i = 0; i < TEST_REPEAT_COUNT; i++)
539 static int event_flow_id(
void)
544 for (
int i = 0; i < TEST_REPEAT_COUNT; i++)
550 static int event_flow_id_set(
void)
555 for (i = 0; i < TEST_REPEAT_COUNT; i++)
564 static void usage(
char *progname)
567 "OpenDataPlane Buffer/Event API microbenchmarks.\n"
569 "Usage: %s OPTIONS\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);
589 static void parse_args(
int argc,
char *argv[], appl_args_t *appl_args)
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'},
602 static const char *shortopts =
"c:b:i:r:t:h";
604 appl_args->bench_idx = 0;
605 appl_args->burst_size = TEST_DEF_BURST;
606 appl_args->cache_size = -1;
607 appl_args->rounds = TEST_ROUNDS;
611 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
618 appl_args->cache_size = atoi(optarg);
621 appl_args->burst_size = atoi(optarg);
628 appl_args->bench_idx = atoi(optarg);
631 appl_args->rounds = atoi(optarg);
634 appl_args->time = atoi(optarg);
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);
647 if (appl_args->rounds < 1) {
648 printf(
"Invalid number test rounds: %d\n", appl_args->rounds);
658 static void print_info(
void)
663 "odp_bench_buffer options\n"
664 "------------------------\n");
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");
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);
678 static int bench_buffer_export(
void *data)
680 args_t *gbl_args = data;
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")) {
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])) {
700 test_common_write_term();
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),
743 "Result array is too small to hold all the results");
748 int main(
int argc,
char *argv[])
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;
767 argc = odph_parse_options(argc, argv);
768 if (odph_options(&helper_options)) {
769 ODPH_ERR(
"Error: reading ODP helper options failed\n");
773 argc = test_common_parse_options(argc, argv);
774 if (test_common_options(&common_options)) {
775 ODPH_ERR(
"Error: reading test options failed\n");
780 init_param.
mem_model = helper_options.mem_model;
784 ODPH_ERR(
"Error: ODP global init failed\n");
790 ODPH_ERR(
"Error: ODP local init failed\n");
795 shm =
odp_shm_reserve(
"shm_args",
sizeof(args_t), ODP_CACHE_LINE_SIZE, 0);
797 ODPH_ERR(
"Error: shared mem reserve failed\n");
802 if (gbl_args == NULL) {
803 ODPH_ERR(
"Error: shared mem alloc failed\n");
807 memset(gbl_args, 0,
sizeof(args_t));
810 parse_args(argc, argv, &gbl_args->appl);
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;
824 ODPH_ERR(
"Error: unable to allocate worker thread\n");
828 sizeof(gbl_args->cpumask_str));
831 ODPH_ERR(
"Error: schedule capability failed\n");
835 gbl_args->max_flow_id = 0;
843 ODPH_ERR(
"Error: schedule config failed\n");
846 gbl_args->max_flow_id = 1;
850 ODPH_ERR(
"Error: unable to query pool capability\n");
854 buf_num = gbl_args->appl.burst_size * TEST_REPEAT_COUNT;
857 ODPH_ERR(
"Error: pool size not supported (max %" PRIu32
")\n", capa.
buf.
max_num);
860 ODPH_ERR(
"Error: cache size not supported (max %" PRIu32
")\n",
865 gbl_args->buf_size = TEST_BUF_SIZE;
876 params.
buf.
size = gbl_args->buf_size;
879 if (gbl_args->appl.cache_size >= 0)
885 ODPH_ERR(
"Error: pool create failed\n");
891 memset(&worker_thread, 0,
sizeof(odph_thread_t));
893 signal(SIGINT, sig_handler);
901 odph_thread_common_param_init(&thr_common);
902 thr_common.instance = instance;
903 thr_common.cpumask = &cpumask;
904 thr_common.share_param = 1;
906 odph_thread_param_init(&thr_param);
907 thr_param.start = bench_run;
908 thr_param.arg = &gbl_args->suite;
911 odph_thread_create(&worker_thread, &thr_common, &thr_param, 1);
913 odph_thread_join(&worker_thread, 1);
915 ret = gbl_args->suite.retval;
917 if (ret == 0 && common_options.is_export) {
918 if (bench_buffer_export(gbl_args)) {
919 ODPH_ERR(
"Error: Export failed\n");
925 ODPH_ERR(
"Error: pool destroy\n");
930 ODPH_ERR(
"Error: shm free\n");
935 ODPH_ERR(
"Error: term local\n");
940 ODPH_ERR(
"Error: term global\n");
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.
#define ODP_UNUSED
Intentionally unused variables of functions.
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.
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.
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.
uint32_t max_flow_id
Maximum flow ID per queue.