18 #include <odp/helper/odph_api.h>
20 #include <bench_common.h>
21 #include <export_results.h>
30 #define REPEAT_COUNT 1000
39 #define TIMER_NSEC 50000000
42 #define TEST_MAX_BENCH 20
44 #define BENCH_INFO(run_fn, max, alt_name) \
45 {.name = #run_fn, .run = run_fn, .max_rounds = max, .desc = alt_name}
80 uint64_t a1[REPEAT_COUNT];
89 double result[TEST_MAX_BENCH];
93 static gbl_args_t *gbl_args;
102 static int setup_sig_handler(
void)
104 struct sigaction action;
106 memset(&action, 0,
sizeof(action));
107 action.sa_handler = sig_handler;
111 if (sigemptyset(&action.sa_mask))
114 if (sigaction(SIGINT, &action, NULL))
120 static int timer_current_tick(
void)
124 uint64_t *a1 = gbl_args->a1;
126 for (i = 0; i < REPEAT_COUNT; i++)
132 static int timer_tick_to_ns(
void)
136 uint64_t *a1 = gbl_args->a1;
137 uint64_t tick = gbl_args->tick;
139 for (i = 0; i < REPEAT_COUNT; i++)
145 static int timer_ns_to_tick(
void)
149 uint64_t *a1 = gbl_args->a1;
150 uint64_t nsec = gbl_args->nsec;
152 for (i = 0; i < REPEAT_COUNT; i++)
158 static int timeout_to_event(
void)
164 for (i = 0; i < REPEAT_COUNT; i++)
172 static int timeout_from_event(
void)
178 for (i = 0; i < REPEAT_COUNT; i++)
186 static int timeout_timer(
void)
192 for (i = 0; i < REPEAT_COUNT; i++)
200 static int timeout_tick(
void)
204 uint64_t *a1 = gbl_args->a1;
206 for (i = 0; i < REPEAT_COUNT; i++)
212 static int timeout_user_ptr(
void)
216 uint64_t *a1 = gbl_args->a1;
218 for (i = 0; i < REPEAT_COUNT; i++)
224 static int timeout_user_area(
void)
228 uint64_t *a1 = gbl_args->a1;
230 for (i = 0; i < REPEAT_COUNT; i++)
236 static int timeout_to_u64(
void)
240 uint64_t *a1 = gbl_args->a1;
242 for (i = 0; i < REPEAT_COUNT; i++)
248 static int timer_to_u64(
void)
252 uint64_t *a1 = gbl_args->a1;
254 for (i = 0; i < REPEAT_COUNT; i++)
260 static int timer_pool_to_u64(
void)
264 uint64_t *a1 = gbl_args->a1;
266 for (i = 0; i < REPEAT_COUNT; i++)
272 static int bench_timer_export(
void *data)
274 gbl_args_t *gbl_args = data;
277 if (test_common_write(
"%s", gbl_args->opt.time ?
278 "Function name,Average nsec per function call\n" :
279 "Function name,Average CPU cycles per function call\n")) {
284 for (
int i = 0; i < gbl_args->suite.num_bench; i++) {
285 if (test_common_write(
"odp_%s,%f\n",
286 gbl_args->suite.bench[i].name,
287 gbl_args->suite.result[i])) {
294 test_common_write_term();
299 bench_info_t test_suite[] = {
300 BENCH_INFO(timer_current_tick, 0, NULL),
301 BENCH_INFO(timer_tick_to_ns, 0, NULL),
302 BENCH_INFO(timer_ns_to_tick, 0, NULL),
303 BENCH_INFO(timeout_to_event, 0, NULL),
304 BENCH_INFO(timeout_from_event, 0, NULL),
305 BENCH_INFO(timeout_timer, 0, NULL),
306 BENCH_INFO(timeout_tick, 0, NULL),
307 BENCH_INFO(timeout_user_ptr, 0, NULL),
308 BENCH_INFO(timeout_user_area, 0, NULL),
309 BENCH_INFO(timeout_to_u64, 0, NULL),
310 BENCH_INFO(timer_to_u64, 0, NULL),
311 BENCH_INFO(timer_pool_to_u64, 0, NULL),
315 "Result array is too small to hold all the results");
318 static void usage(
void)
321 "ODP timer API micro benchmarks\n"
324 " -s, --clk_src Clock source select (default 0):\n"
325 " 0: ODP_CLOCK_DEFAULT\n"
326 " 1: ODP_CLOCK_SRC_1, ...\n"
327 " -t, --time <opt> Time measurement. 0: measure CPU cycles (default), 1: measure time\n"
328 " -i, --index <idx> Benchmark index to run indefinitely.\n"
329 " -r, --rounds <num> Run each test case 'num' times (default %u).\n"
330 " -h, --help Display help and exit.\n\n"
335 static int parse_args(
int argc,
char *argv[])
338 static const struct option longopts[] = {
339 {
"clk_src", required_argument, NULL,
's'},
340 {
"time", required_argument, NULL,
't'},
341 {
"index", required_argument, NULL,
'i'},
342 {
"rounds", required_argument, NULL,
'r'},
343 {
"help", no_argument, NULL,
'h'},
347 static const char *shortopts =
"s:t:i:r:h";
350 gbl_args->opt.time = 0;
351 gbl_args->opt.bench_idx = 0;
352 gbl_args->opt.rounds = ROUNDS;
355 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
362 gbl_args->opt.clk_src = atoi(optarg);
365 gbl_args->opt.time = atoi(optarg);
368 gbl_args->opt.bench_idx = atoi(optarg);
371 gbl_args->opt.rounds = atoi(optarg);
377 ODPH_ERR(
"Bad option. Use -h for help.\n");
382 if (gbl_args->opt.rounds < 1) {
383 ODPH_ERR(
"Invalid test cycle repeat count: %u\n", gbl_args->opt.rounds);
387 if (gbl_args->opt.bench_idx < 0 ||
388 gbl_args->opt.bench_idx > (
int)ODPH_ARRAY_SIZE(test_suite)) {
389 ODPH_ERR(
"Bad bench index %i\n", gbl_args->opt.bench_idx);
399 static void print_info(
void)
404 "odp_bench_timer options\n"
405 "-----------------------\n");
407 printf(
"CPU mask: %s\n", gbl_args->cpumask_str);
408 printf(
"Clock source: %i\n", gbl_args->opt.clk_src);
409 printf(
"Measurement unit: %s\n", gbl_args->opt.time ?
"nsec" :
"CPU cycles");
410 printf(
"Test rounds: %u\n", gbl_args->opt.rounds);
411 printf(
"Timer duration: %" PRIu64
" nsec\n", gbl_args->timer_nsec);
412 printf(
"Timer tick freq: %.2f Hz\n", gbl_args->tick_hz);
416 static int create_timer(
void)
429 uint64_t t1, t2, diff, tick1, tick2;
432 ODPH_ERR(
"Pool capa failed\n");
436 clk_src = gbl_args->opt.clk_src;
438 ODPH_ERR(
"Timer capa failed\n");
452 ODPH_ERR(
"Timer pool create failed\n");
457 ODPH_ERR(
"Timer pool start failed\n");
461 gbl_args->timer_pool = tp;
463 gbl_args->timer_nsec = TIMER_NSEC;
464 if (TIMER_NSEC < tp_param.
min_tmo)
465 gbl_args->timer_nsec = tp_param.
min_tmo;
466 else if (TIMER_NSEC > tp_param.
max_tmo)
467 gbl_args->timer_nsec = tp_param.
max_tmo;
479 ODPH_ERR(
"Timeout pool create failed\n");
483 gbl_args->pool = pool;
488 ODPH_ERR(
"Timeout alloc failed\n");
492 gbl_args->timeout = tmo;
517 gbl_args->plain_queue = 1;
522 ODPH_ERR(
"Queue create failed\n");
526 gbl_args->queue = queue;
530 ODPH_ERR(
"Timer alloc failed\n");
534 gbl_args->timer = timer;
539 static int wait_timer(
void)
544 uint64_t wait_nsec = 2 * gbl_args->timer_nsec;
554 ODPH_ERR(
"Timer start failed\n");
562 if (gbl_args->plain_queue) {
571 ODPH_ERR(
"Timeout event missing\n");
576 gbl_args->event = ev;
581 ODPH_ERR(
"Timeout event missing\n");
585 gbl_args->event = ev;
589 ODPH_ERR(
"Extra timeout event\n");
595 ODPH_ERR(
"Bad event type\n");
604 int main(
int argc,
char *argv[])
606 odph_helper_options_t helper_options;
607 test_common_options_t common_options;
608 odph_thread_t worker_thread;
609 odph_thread_common_param_t thr_common;
610 odph_thread_param_t thr_param;
619 argc = odph_parse_options(argc, argv);
620 if (odph_options(&helper_options)) {
621 ODPH_ERR(
"Reading ODP helper options failed\n");
625 argc = test_common_parse_options(argc, argv);
626 if (test_common_options(&common_options)) {
627 ODPH_ERR(
"Reading test options failed\n");
632 init_param.
mem_model = helper_options.mem_model;
636 ODPH_ERR(
"Global init failed\n");
642 ODPH_ERR(
"Local init failed\n");
646 if (setup_sig_handler()) {
647 ODPH_ERR(
"Signal handler setup failed\n");
654 shm =
odp_shm_reserve(
"shm_args",
sizeof(gbl_args_t), ODP_CACHE_LINE_SIZE, 0);
656 ODPH_ERR(
"Shared mem reserve failed\n");
661 if (gbl_args == NULL) {
662 ODPH_ERR(
"Shared mem alloc failed\n");
666 memset(gbl_args, 0,
sizeof(gbl_args_t));
673 for (i = 0; i < REPEAT_COUNT; i++) {
681 ret = parse_args(argc, argv);
685 bench_suite_init(&gbl_args->suite);
686 gbl_args->suite.bench = test_suite;
687 gbl_args->suite.num_bench = ODPH_ARRAY_SIZE(test_suite);
688 gbl_args->suite.measure_time = !!gbl_args->opt.time;
689 gbl_args->suite.indef_idx = gbl_args->opt.bench_idx;
690 gbl_args->suite.rounds = gbl_args->opt.rounds;
691 gbl_args->suite.repeat_count = REPEAT_COUNT;
692 if (common_options.is_export)
693 gbl_args->suite.result = gbl_args->result;
697 ODPH_ERR(
"Unable to allocate worker thread\n");
703 sizeof(gbl_args->cpumask_str));
706 ret = create_timer();
718 memset(&worker_thread, 0,
sizeof(odph_thread_t));
726 odph_thread_common_param_init(&thr_common);
727 thr_common.instance = instance;
728 thr_common.cpumask = &cpumask;
729 thr_common.share_param = 1;
731 odph_thread_param_init(&thr_param);
732 thr_param.start = bench_run;
733 thr_param.arg = &gbl_args->suite;
736 odph_thread_create(&worker_thread, &thr_common, &thr_param, 1);
738 odph_thread_join(&worker_thread, 1);
740 ret = gbl_args->suite.retval;
742 if (ret == 0 && common_options.is_export) {
743 if (bench_timer_export(gbl_args)) {
744 ODPH_ERR(
"Error: Export failed\n");
758 ODPH_ERR(
"Timer free failed\n");
768 ODPH_ERR(
"Queue destroy failed\n");
774 ODPH_ERR(
"Shared mem free failed\n");
779 ODPH_ERR(
"Local term failed\n");
784 ODPH_ERR(
"Global term failed\n");
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
#define ODP_UNUSED
Intentionally unused variables of functions.
void odp_cpumask_set(odp_cpumask_t *mask, int cpu)
Add CPU to mask.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
void odp_cpumask_zero(odp_cpumask_t *mask)
Clear entire CPU mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
uint64_t odp_event_to_u64(odp_event_t hdl)
Get printable value for an odp_event_t.
#define ODP_EVENT_INVALID
Invalid event.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_TIMEOUT
Timeout pool.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
odp_event_t odp_queue_deq(odp_queue_t queue)
Dequeue an event from a queue.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
@ ODP_QUEUE_TYPE_PLAIN
Plain queue.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
uint64_t odp_time_global_strict_ns(void)
Current global time in nanoseconds (strict)
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_global_ns(void)
Current global time in nanoseconds.
void odp_timeout_free(odp_timeout_t tmo)
Timeout free.
uint64_t odp_timer_tick_to_ns(odp_timer_pool_t timer_pool, uint64_t ticks)
Convert timer ticks to nanoseconds.
int odp_timer_pool_start_multi(odp_timer_pool_t timer_pool[], int num)
Start timer pools.
odp_timeout_t odp_timeout_alloc(odp_pool_t pool)
Timeout alloc.
uint64_t odp_timeout_tick(odp_timeout_t tmo)
Timeout expiration tick.
int odp_timer_free(odp_timer_t timer)
Free a timer.
odp_timeout_t odp_timeout_from_event(odp_event_t ev)
Get timeout handle from a ODP_EVENT_TIMEOUT type event.
#define ODP_TIMER_POOL_INVALID
Invalid timer pool handle.
odp_timer_pool_t odp_timer_pool_create(const char *name, const odp_timer_pool_param_t *params)
Create a timer pool.
odp_timer_t odp_timeout_timer(odp_timeout_t tmo)
Return timer handle for the timeout.
uint64_t odp_timer_current_tick(odp_timer_pool_t timer_pool)
Current tick value.
int odp_timer_capability(odp_timer_clk_src_t clk_src, odp_timer_capability_t *capa)
Query timer capabilities per clock source.
void * odp_timeout_user_area(odp_timeout_t tmo)
Timeout user area.
uint64_t odp_timer_ns_to_tick(odp_timer_pool_t timer_pool, uint64_t ns)
Convert nanoseconds to timer ticks.
uint64_t odp_timeout_to_u64(odp_timeout_t tmo)
Get printable value for an odp_timeout_t.
odp_timer_clk_src_t
Clock sources for timer pools.
int odp_timer_start(odp_timer_t timer, const odp_timer_start_t *start_param)
Start a timer.
odp_event_t odp_timeout_to_event(odp_timeout_t tmo)
Convert timeout handle to event handle.
#define ODP_TIMEOUT_INVALID
Invalid timeout handle.
odp_timer_t odp_timer_alloc(odp_timer_pool_t timer_pool, odp_queue_t queue, const void *user_ptr)
Allocate a timer.
#define ODP_CLOCK_DEFAULT
The default clock source.
uint64_t odp_timer_pool_to_u64(odp_timer_pool_t timer_pool)
Get printable value for an odp_timer_pool_t.
#define ODP_TIMER_INVALID
Invalid timer handle.
uint64_t odp_timer_to_u64(odp_timer_t timer)
Get printable value for an odp_timer_t.
void odp_timer_pool_param_init(odp_timer_pool_param_t *param)
Initialize timer pool parameters.
void odp_timer_pool_destroy(odp_timer_pool_t timer_pool)
Destroy a timer pool.
void * odp_timeout_user_ptr(odp_timeout_t tmo)
Return user pointer for the timeout.
@ ODP_TIMER_SUCCESS
Timer operation succeeded.
@ ODP_TIMER_TICK_REL
Relative ticks.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
struct odp_pool_capability_t::@123 tmo
Timeout pool capabilities
uint32_t max_uarea_size
Maximum user area size in bytes.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@127 tmo
Parameters for timeout pools.
odp_pool_type_t type
Pool type.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
odp_timer_res_capability_t max_res
Maximum resolution.
odp_bool_t queue_type_sched
Scheduled queue destination support.
uint64_t res_ns
Timeout resolution in nanoseconds.
uint64_t min_tmo
Minimum relative timeout in nanoseconds.
uint32_t num_timers
Number of timers in the pool.
odp_timer_clk_src_t clk_src
Clock source for timers.
uint64_t max_tmo
Maximum relative timeout in nanoseconds.
uint64_t max_tmo
Maximum relative timeout in nanoseconds.
uint64_t min_tmo
Minimum relative timeout in nanoseconds.
uint64_t res_ns
Timeout resolution in nanoseconds.
uint64_t tick
Expiration time in ticks.
odp_event_t tmo_ev
Timeout event.
odp_timer_tick_type_t tick_type
Tick type.