22#include <odp/helper/odph_api.h>
24#define MODE_SCHED_OVERH 0
25#define MODE_START_CANCEL 1
26#define MODE_START_EXPIRE 2
28#define MAX_TIMER_POOLS 32
29#define MAX_TIMERS 10000
30#define START_NS (100 * ODP_TIME_MSEC_IN_NS)
32typedef struct test_options_t {
44typedef struct time_stat_t {
51typedef struct test_stat_t {
66typedef struct test_stat_tp_ctrl_t {
70 uint64_t num_tp_create;
71 uint64_t tp_create_cycles;
73 uint64_t num_tp_start;
74 uint64_t tp_start_cycles;
76 uint64_t num_timer_alloc;
77 uint64_t timer_alloc_cycles;
79 uint64_t num_timer_free;
80 uint64_t timer_free_cycles;
82 uint64_t num_tp_destroy;
83 uint64_t tp_destroy_cycles;
87typedef struct test_stat_sum_t {
105typedef struct thread_arg_t {
111typedef struct timer_ctx_t {
113 uint64_t target_tick;
120typedef struct timer_pool_t {
123 uint64_t period_tick;
127typedef struct test_global_t {
128 test_options_t test_options;
134 timer_pool_t timer_pool[MAX_TIMER_POOLS];
138 timer_ctx_t timer_ctx[MAX_TIMER_POOLS][MAX_TIMERS];
142 test_stat_sum_t stat_sum;
147test_global_t *test_global;
149static void print_usage(
void)
152 "Timer performance test\n"
154 "Usage: odp_timer_perf [options]\n"
156 " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default: 1\n"
157 " -n, --num_tp Number of timer pools. Default: 1\n"
158 " -t, --num_timer Number of timers per timer pool. Default: 10\n"
159 " -r, --res_ns Resolution in nsec. Default: 10000000\n"
160 " -p, --period_ns Timeout period in nsec. Default: 100000000\n"
161 " -s, --shared Shared vs private timer pool. Currently, modes 0-2 support private\n"
162 " pools only with single CPU. Default: 1\n"
163 " 0: Private timer pools\n"
164 " 1: Shared timer pools\n"
165 " -m, --mode Select test mode. Default: 0\n"
166 " 0: Measure odp_schedule() overhead when using timers\n"
167 " 1: Measure timer start + cancel performance\n"
168 " 2: Measure schedule and timer start overhead while continuously\n"
169 " restarting expiring timers\n"
170 " 3: Measure timer pool create/start/destroy and timer alloc/free\n"
171 " performance. Does not measure actual timer usage (start/expire).\n"
172 " Requires num timer pools (-n) >= num CPUs (-c).\n"
173 " -R, --rounds Number of test rounds. Default value is 50 for mode 3, otherwise 100000.\n"
174 " -h, --help This help\n"
178static int parse_options(
int argc,
char *argv[], test_options_t *test_options)
183 static const struct option longopts[] = {
184 {
"num_cpu", required_argument, NULL,
'c'},
185 {
"num_tp ", required_argument, NULL,
'n'},
186 {
"num_timer", required_argument, NULL,
't'},
187 {
"res_ns", required_argument, NULL,
'r'},
188 {
"period_ns", required_argument, NULL,
'p'},
189 {
"shared", required_argument, NULL,
's'},
190 {
"mode", required_argument, NULL,
'm'},
191 {
"rounds", required_argument, NULL,
'R'},
192 {
"help", no_argument, NULL,
'h'},
196 static const char *shortopts =
"+c:n:t:r:p:s:m:R:h";
198 test_options->num_cpu = 1;
199 test_options->num_tp = 1;
200 test_options->num_timer = 10;
203 test_options->shared = 1;
204 test_options->mode = 0;
205 test_options->test_rounds = 0;
208 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
215 test_options->num_cpu = atoi(optarg);
218 test_options->num_tp = atoi(optarg);
221 test_options->num_timer = atoi(optarg);
224 test_options->res_ns = atoll(optarg);
227 test_options->period_ns = atoll(optarg);
230 test_options->shared = atoi(optarg);
233 test_options->mode = atoi(optarg);
236 test_options->test_rounds = atoll(optarg);
247 if (test_options->num_timer > MAX_TIMERS) {
248 ODPH_ERR(
"Too many timers. Max %u\n", MAX_TIMERS);
252 if (test_options->mode < 0 || test_options->mode > MODE_TP_CTRL) {
253 ODPH_ERR(
"Invalid mode %i\n", test_options->mode);
257 if (test_options->test_rounds == 0) {
259 test_options->test_rounds = 100000;
261 if (test_options->mode == MODE_TP_CTRL)
262 test_options->test_rounds = 50;
268static int set_num_cpu(test_global_t *global,
int use_workers)
271 test_options_t *test_options = &global->test_options;
272 uint32_t num_cpu = test_options->num_cpu;
273 int shared = test_options->shared;
274 int mode = test_options->mode;
284 if (num_cpu && (uint32_t)ret != num_cpu) {
285 ODPH_ERR(
"Too many workers. Max supported %i\n.", ret);
289 if (shared == 0 && num_cpu != 1 && mode != MODE_TP_CTRL) {
290 ODPH_ERR(
"Private pool test supports only single CPU\n.");
297 test_options->num_cpu = num_cpu;
302 if (mode == MODE_TP_CTRL && test_options->num_tp < num_cpu) {
303 ODPH_ERR(
"Mode %i requires num timer pools (%u) >= num workers (%u)\n",
304 MODE_TP_CTRL, test_options->num_tp, num_cpu);
316static void init_global_handles(test_global_t *global)
320 for (i = 0; i < MAX_TIMER_POOLS; i++) {
325 for (j = 0; j < MAX_TIMERS; j++)
334 uint64_t max_tmo_ns, min_tmo_ns;
337 test_options_t *test_options = &global->test_options;
338 uint32_t num_cpu = test_options->num_cpu;
339 uint32_t num_tp = test_options->num_tp;
340 uint32_t num_timer = test_options->num_timer;
341 uint64_t res_ns = test_options->res_ns;
342 uint64_t period_ns = test_options->period_ns;
343 int mode = test_options->mode;
345 max_tmo_ns = START_NS + (num_timer * period_ns);
346 min_tmo_ns = START_NS / 2;
348 if (mode == MODE_START_EXPIRE) {
354 max_tmo_ns = period_ns * 3;
355 min_tmo_ns = test_options->res_ns / 2;
359 if (test_options->shared == 0)
362 printf(
"\nTimer performance test\n");
363 printf(
" mode %i\n", mode);
364 printf(
" num cpu %u\n", num_cpu);
365 printf(
" private pool %i\n", priv);
366 printf(
" num timer pool %u\n", num_tp);
367 printf(
" num timer %u\n", num_timer);
368 printf(
" resolution %" PRIu64
" nsec\n", res_ns);
369 printf(
" period %" PRIu64
" nsec\n", period_ns);
370 printf(
" max timeout %" PRIu64
" nsec\n", max_tmo_ns);
371 printf(
" min timeout %" PRIu64
" nsec\n", min_tmo_ns);
373 if (mode == MODE_SCHED_OVERH)
376 printf(
" test rounds %" PRIu64
"\n", test_options->test_rounds);
379 ODPH_ERR(
"Timer capability failed\n");
384 timer_res_capa.
res_ns = res_ns;
386 ODPH_ERR(
"Timer resolution capability failed\n");
391 ODPH_ERR(
"Too high resolution\n");
395 if (min_tmo_ns < timer_res_capa.
min_tmo) {
396 ODPH_ERR(
"Too short min timeout\n");
400 if (max_tmo_ns > timer_res_capa.
max_tmo) {
401 ODPH_ERR(
"Too long max timeout\n");
406 if (max_timers && num_timer > max_timers) {
407 ODPH_ERR(
"Too many timers (max %u)\n", max_timers);
411 if (num_tp > MAX_TIMER_POOLS || num_tp > timer_capa.
max_pools) {
412 ODPH_ERR(
"Too many timer pools (max supported %u, max capa %u)\n",
418 timer_pool_param->
res_ns = res_ns;
419 timer_pool_param->
min_tmo = min_tmo_ns;
420 timer_pool_param->
max_tmo = max_tmo_ns;
422 timer_pool_param->
priv = priv;
432 test_options_t *test_options = &global->test_options;
433 uint32_t num_tp = test_options->num_tp;
434 char tp_name[] =
"timer_pool_00";
436 for (i = 0; i < num_tp; i++) {
438 tp_name[11] =
'0' + i / 10;
439 tp_name[12] =
'0' + i % 10;
443 global->timer_pool[i].tp = tp;
445 ODPH_ERR(
"Timer pool create failed (%u)\n", i);
450 ODPH_ERR(
"Timer pool start failed (%u)\n", i);
455 test_options->period_ns);
459 printf(
" start %" PRIu64
" tick\n", global->timer_pool[0].start_tick);
460 printf(
" period %" PRIu64
" ticks\n", global->timer_pool[0].period_tick);
466static int create_event_pools(test_global_t *global)
471 test_options_t *test_options = &global->test_options;
472 uint32_t num_tp = test_options->num_tp;
473 uint32_t num_timer = test_options->num_timer;
474 char name[] =
"timer_pool_00";
478 pool_param.
tmo.
num = num_timer;
480 for (i = 0; i < num_tp; i++) {
482 name[11] =
'0' + i / 10;
483 name[12] =
'0' + i % 10;
487 global->pool[i] = pool;
489 ODPH_ERR(
"Pool create failed (%u)\n", i);
497static int create_event_queues(test_global_t *global)
502 test_options_t *test_options = &global->test_options;
503 uint32_t num_tp = test_options->num_tp;
504 char name[] =
"timer_pool_00";
512 for (i = 0; i < num_tp; i++) {
514 name[11] =
'0' + i / 10;
515 name[12] =
'0' + i % 10;
519 global->queue[i] = queue;
521 ODPH_ERR(
"Queue create failed (%u)\n", i);
529static int start_timers(test_global_t *global)
537 uint64_t tick_cur, nsec, time_ns;
540 test_options_t *test_options = &global->test_options;
541 uint32_t num_tp = test_options->num_tp;
542 uint32_t num_timer = test_options->num_timer;
543 uint64_t period_ns = test_options->period_ns;
545 max_tmo_ns = START_NS + (num_timer * period_ns);
547 for (i = 0; i < num_tp; i++) {
548 tp = global->timer_pool[i].tp;
549 pool = global->pool[i];
550 queue = global->queue[i];
557 for (j = 0; j < num_timer; j++) {
562 timer_ctx_t *ctx = &global->timer_ctx[i][j];
569 ctx->target_ns = time_ns + nsec;
577 global->timer[i][j] = timer;
580 nsec = nsec - period_ns;
583 start_param.
tick = tick_cur + tick_ns;
586 if (test_options->mode == MODE_START_EXPIRE) {
587 uint64_t offset_ns = period_ns + j * period_ns / num_timer;
589 ctx->target_ns = time_ns + offset_ns;
591 start_param.
tick = ctx->target_tick;
596 ODPH_ERR(
"Timer start %i/%i (ret %i)\n", i, j, status);
602 ODPH_ERR(
"Timer pool info failed\n");
606 printf(
"Timer pool info [%i]:\n", i);
607 printf(
" cur_timers %u\n", timer_pool_info.
cur_timers);
608 printf(
" hwm_timers %u\n", timer_pool_info.
hwm_timers);
615static int destroy_timer_pool(test_global_t *global)
622 test_options_t *test_options = &global->test_options;
623 uint32_t num_timer = test_options->num_timer;
624 uint32_t num_tp = test_options->num_tp;
626 for (i = 0; i < num_tp; i++) {
627 for (j = 0; j < num_timer; j++) {
628 timer = global->timer[i][j];
634 printf(
"Timer free failed: %i/%i\n", i, j);
637 queue = global->queue[i];
641 pool = global->pool[i];
645 tp = global->timer_pool[i].tp;
653static int sched_mode_worker(
void *arg)
659 uint64_t c2, diff, nsec, time_ns, target_ns;
661 time_stat_t before, after;
663 thread_arg_t *thread_arg = arg;
664 test_global_t *global = thread_arg->global;
665 test_options_t *test_options = &global->test_options;
666 uint32_t num_tp = test_options->num_tp;
674 memset(&before, 0,
sizeof(time_stat_t));
675 memset(&after, 0,
sizeof(time_stat_t));
713 target_ns = ctx->target_ns;
714 if (time_ns < target_ns) {
715 diff = target_ns - time_ns;
717 before.sum_ns += diff;
718 if (diff > before.max_ns)
719 before.max_ns = diff;
721 ODPH_DBG(
"before %" PRIu64
"\n", diff);
723 diff = time_ns - target_ns;
725 after.sum_ns += diff;
726 if (diff > after.max_ns)
729 ODPH_DBG(
"after %" PRIu64
"\n", time_ns - target_ns);
740 global->stat[thr].events = events;
741 global->stat[thr].cycles_0 = cycles;
742 global->stat[thr].rounds = rounds;
743 global->stat[thr].nsec = nsec;
744 global->stat[thr].before = before;
745 global->stat[thr].after = after;
750static int cancel_timers(test_global_t *global, uint32_t worker_idx)
756 test_options_t *test_options = &global->test_options;
757 uint32_t num_tp = test_options->num_tp;
758 uint32_t num_timer = test_options->num_timer;
759 uint32_t num_worker = test_options->num_cpu;
762 for (i = 0; i < num_tp; i++) {
763 for (j = worker_idx; j < num_timer; j += num_worker) {
764 timer = global->timer[i][j];
784static int start_cancel_mode_worker(
void *arg)
786 uint64_t tick, start_tick, period_tick, nsec;
789 uint32_t i, j, worker_idx;
796 thread_arg_t *thread_arg = arg;
797 test_global_t *global = thread_arg->global;
798 test_options_t *test_options = &global->test_options;
799 uint32_t num_tp = test_options->num_tp;
800 uint32_t num_timer = test_options->num_timer;
801 uint32_t num_worker = test_options->num_cpu;
804 uint64_t test_rounds = test_options->test_rounds;
805 uint64_t num_tmo = 0;
806 uint64_t num_cancel = 0;
807 uint64_t num_start = 0;
808 uint64_t cancel_cycles = 0, start_cycles = 0;
812 worker_idx = thread_arg->worker_idx;
830 timer = global->timer[i][j];
831 start_tick = global->timer_pool[i].start_tick;
832 period_tick = global->timer_pool[i].period_tick;
833 tick = start_tick + j * period_tick;
836 start_param.
tick = tick;
844 ODPH_ERR(
"Timer start (tmo) failed (ret %i)\n", status);
866 for (i = 0; i < num_tp; i++) {
867 tp = global->timer_pool[i].tp;
871 start_tick = global->timer_pool[i].start_tick;
872 period_tick = global->timer_pool[i].period_tick;
877 for (j = worker_idx; j < num_timer; j += num_worker) {
880 timer = global->timer[i][j];
890 ODPH_ERR(
"Timer (%u/%u) cancel failed (ret %i)\n", i, j,
901 for (j = worker_idx; j < num_timer; j += num_worker) {
905 timer = global->timer[i][j];
910 start_param.
tick = tick + j * period_tick;
911 start_param.
tmo_ev = ev_tbl[j];
917 ODPH_ERR(
"Timer (%u/%u) start failed (ret %i)\n", i, j,
930 if (test_rounds == 0)
939 if (cancel_timers(global, worker_idx))
940 ODPH_ERR(
"Timer cancel failed\n");
943 global->stat[thr].events = num_tmo;
944 global->stat[thr].rounds = test_options->test_rounds - test_rounds;
945 global->stat[thr].nsec = nsec;
946 global->stat[thr].cycles_0 = cancel_cycles;
947 global->stat[thr].cycles_1 = start_cycles;
949 global->stat[thr].cancels = num_cancel;
950 global->stat[thr].starts = num_start;
955static int start_expire_mode_worker(
void *arg)
958 uint32_t i, j, exit_test;
961 uint64_t c2, c3, c4, diff, nsec, time_ns, target_ns, period_tick, wait;
965 time_stat_t before, after;
967 thread_arg_t *thread_arg = arg;
968 test_global_t *global = thread_arg->global;
969 test_options_t *opt = &global->test_options;
970 uint32_t num_tp = opt->num_tp;
971 uint64_t sched_cycles = 0;
972 uint64_t start_cycles = 0;
979 memset(&before, 0,
sizeof(time_stat_t));
980 memset(&after, 0,
sizeof(time_stat_t));
989 while (events < opt->test_rounds * opt->num_timer / opt->num_cpu) {
1004 sched_cycles += diff;
1015 timer = global->timer[i][j];
1016 period_tick = global->timer_pool[i].period_tick;
1018 target_ns = ctx->target_ns;
1020 if (time_ns < target_ns) {
1021 diff = target_ns - time_ns;
1023 before.sum_ns += diff;
1024 if (diff > before.max_ns)
1025 before.max_ns = diff;
1027 ODPH_DBG(
"before %" PRIu64
"\n", diff);
1029 diff = time_ns - target_ns;
1031 after.sum_ns += diff;
1032 if (diff > after.max_ns)
1033 after.max_ns = diff;
1035 ODPH_DBG(
"after %" PRIu64
"\n", diff);
1040 ctx->target_ns += opt->period_ns;
1041 ctx->target_tick += period_tick;
1042 start_param.
tick = ctx->target_tick;
1050 start_cycles += diff;
1053 ODPH_ERR(
"Timer start (tmo) failed (ret %i)\n", status);
1063 status = cancel_timers(global, thread_arg->worker_idx);
1078 global->stat[thr].events = events;
1079 global->stat[thr].cycles_0 = sched_cycles;
1080 global->stat[thr].cycles_1 = start_cycles;
1081 global->stat[thr].rounds = rounds;
1082 global->stat[thr].nsec = nsec;
1083 global->stat[thr].before = before;
1084 global->stat[thr].after = after;
1089static int timer_pool_ctrl_mode_worker(
void *arg)
1100 thread_arg_t *thread_arg = arg;
1101 test_global_t *global = thread_arg->global;
1102 test_options_t *test_options = &global->test_options;
1104 uint32_t num_tp = test_options->num_tp;
1105 uint32_t num_timer = test_options->num_timer;
1106 uint32_t num_worker = test_options->num_cpu;
1107 uint64_t rounds = test_options->test_rounds;
1108 uint32_t worker_idx = thread_arg->worker_idx;
1109 test_stat_tp_ctrl_t *stat;
1110 char tp_name[] =
"timer_pool_00";
1115 uint32_t base = num_tp / num_worker;
1116 uint32_t extra = num_tp % num_worker;
1117 uint32_t num_tp_worker = base + (worker_idx < extra ? 1 : 0);
1118 uint32_t first_tp = (worker_idx * base) + (worker_idx < extra ? worker_idx : extra);
1121 stat = &global->stat_tp_ctrl[thr];
1122 memset(stat, 0,
sizeof(test_stat_tp_ctrl_t));
1125 for (i = 0; i < num_tp_worker; i++)
1126 queue[i] = global->queue[first_tp + i];
1133 for (round = 0; round < rounds; round++) {
1135 for (i = 0; i < num_tp_worker; i++) {
1139 tp_name[11] =
'0' + idx / 10;
1140 tp_name[12] =
'0' + idx % 10;
1148 ODPH_ERR(
"Timer pool create failed (%u)\n", idx);
1154 stat->num_tp_create++;
1158 for (i = 0; i < num_tp_worker; i++) {
1164 ODPH_ERR(
"Timer pool start failed (%u)\n", first_tp + i);
1170 stat->num_tp_start++;
1174 for (i = 0; i < num_tp_worker; i++) {
1177 for (j = 0; j < num_timer; j++) {
1182 global->timer[idx][j] = timer;
1184 ODPH_ERR(
"Timer alloc failed (%u/%u)\n", idx, j);
1190 stat->num_timer_alloc++;
1195 for (i = 0; i < num_tp_worker; i++) {
1198 for (j = 0; j < num_timer; j++) {
1199 timer = global->timer[idx][j];
1207 ODPH_ERR(
"Timer free failed (%u/%u)\n", idx, j);
1213 stat->num_timer_free++;
1218 for (i = 0; i < num_tp_worker; i++) {
1225 stat->num_tp_destroy++;
1238static int start_workers(test_global_t *global,
odp_instance_t instance)
1240 odph_thread_common_param_t thr_common;
1242 test_options_t *test_options = &global->test_options;
1243 int num_cpu = test_options->num_cpu;
1244 odph_thread_param_t thr_param[num_cpu];
1246 memset(global->thread_tbl, 0,
sizeof(global->thread_tbl));
1247 odph_thread_common_param_init(&thr_common);
1249 thr_common.instance = instance;
1250 thr_common.cpumask = &global->cpumask;
1252 for (i = 0; i < num_cpu; i++) {
1253 odph_thread_param_init(&thr_param[i]);
1255 if (test_options->mode == MODE_SCHED_OVERH)
1256 thr_param[i].start = sched_mode_worker;
1257 else if (test_options->mode == MODE_START_CANCEL)
1258 thr_param[i].start = start_cancel_mode_worker;
1259 else if (test_options->mode == MODE_TP_CTRL)
1260 thr_param[i].start = timer_pool_ctrl_mode_worker;
1262 thr_param[i].start = start_expire_mode_worker;
1264 thr_param[i].arg = &global->thread_arg[i];
1268 ret = odph_thread_create(global->thread_tbl, &thr_common, thr_param,
1271 if (ret != num_cpu) {
1272 ODPH_ERR(
"Thread create failed %i\n", ret);
1279static void sum_stat(test_global_t *global)
1282 test_stat_sum_t *sum = &global->stat_sum;
1284 memset(sum, 0,
sizeof(test_stat_sum_t));
1287 if (global->stat[i].rounds == 0)
1291 sum->events += global->stat[i].events;
1292 sum->rounds += global->stat[i].rounds;
1293 sum->cycles_0 += global->stat[i].cycles_0;
1294 sum->cycles_1 += global->stat[i].cycles_1;
1295 sum->nsec += global->stat[i].nsec;
1296 sum->cancels += global->stat[i].cancels;
1297 sum->starts += global->stat[i].starts;
1299 sum->before.num += global->stat[i].before.num;
1300 sum->before.sum_ns += global->stat[i].before.sum_ns;
1301 sum->after.num += global->stat[i].after.num;
1302 sum->after.sum_ns += global->stat[i].after.sum_ns;
1304 if (global->stat[i].before.max_ns > sum->before.max_ns)
1305 sum->before.max_ns = global->stat[i].before.max_ns;
1307 if (global->stat[i].after.max_ns > sum->after.max_ns)
1308 sum->after.max_ns = global->stat[i].after.max_ns;
1315static void print_stat_sched_mode(test_global_t *global)
1318 test_stat_sum_t *sum = &global->stat_sum;
1319 double round_ave = 0.0;
1320 double before_ave = 0.0;
1321 double after_ave = 0.0;
1325 printf(
"RESULTS - schedule() cycles per thread:\n");
1326 printf(
"----------------------------------------------\n");
1327 printf(
" 1 2 3 4 5 6 7 8 9 10");
1330 if (global->stat[i].rounds) {
1331 if ((num % 10) == 0)
1334 printf(
"%6.1f ", (
double)global->stat[i].cycles_0 / global->stat[i].rounds);
1342 round_ave = (double)sum->rounds / sum->num;
1344 if (sum->before.num)
1345 before_ave = (double)sum->before.sum_ns / sum->before.num;
1348 after_ave = (double)sum->after.sum_ns / sum->after.num;
1350 printf(
"TOTAL (%i workers)\n", sum->num);
1351 printf(
" events: %" PRIu64
"\n", sum->events);
1352 printf(
" ave time: %.2f sec\n", sum->time_ave);
1353 printf(
" ave rounds per sec: %.2fM\n", (round_ave / sum->time_ave) / 1000000.0);
1354 printf(
" num before: %" PRIu64
"\n", sum->before.num);
1355 printf(
" ave before: %.1f nsec\n", before_ave);
1356 printf(
" max before: %" PRIu64
" nsec\n", sum->before.max_ns);
1357 printf(
" num after: %" PRIu64
"\n", sum->after.num);
1358 printf(
" ave after: %.1f nsec\n", after_ave);
1359 printf(
" max after: %" PRIu64
" nsec\n", sum->after.max_ns);
1363static void print_stat_start_cancel_mode(test_global_t *global)
1366 test_stat_sum_t *sum = &global->stat_sum;
1367 double start_ave = 0.0;
1371 printf(
"RESULTS\n");
1372 printf(
"odp_timer_cancel() cycles per thread:\n");
1373 printf(
"-------------------------------------------------\n");
1374 printf(
" 1 2 3 4 5 6 7 8 9 10");
1377 const test_stat_t *si = &global->stat[i];
1380 if ((num % 10) == 0)
1383 printf(
"%6.1f ", (
double)si->cycles_0 / si->cancels);
1391 printf(
"odp_timer_start() cycles per thread:\n");
1392 printf(
"-------------------------------------------------\n");
1393 printf(
" 1 2 3 4 5 6 7 8 9 10");
1396 const test_stat_t *si = &global->stat[i];
1399 if ((num % 10) == 0)
1402 printf(
"%6.1f ", (
double)si->cycles_1 / si->starts);
1408 start_ave = (double)sum->starts / sum->num;
1411 printf(
"TOTAL (%i workers)\n", sum->num);
1412 printf(
" rounds: %" PRIu64
"\n", sum->rounds);
1413 printf(
" timeouts: %" PRIu64
"\n", sum->events);
1414 printf(
" timer cancels: %" PRIu64
"\n", sum->cancels);
1415 printf(
" cancels failed: %" PRIu64
"\n", sum->cancels - sum->starts);
1416 printf(
" timer starts: %" PRIu64
"\n", sum->starts);
1417 printf(
" ave time: %.2f sec\n", sum->time_ave);
1418 printf(
" cancel+start per cpu: %.2fM per sec\n", (start_ave / sum->time_ave) / 1000000.0);
1422static void print_stat_expire_mode(test_global_t *global)
1425 test_stat_sum_t *sum = &global->stat_sum;
1426 double round_ave = 0.0;
1427 double before_ave = 0.0;
1428 double after_ave = 0.0;
1432 printf(
"RESULTS\n");
1433 printf(
"odp_schedule() cycles per thread:\n");
1434 printf(
"-------------------------------------------------\n");
1435 printf(
" 1 2 3 4 5 6 7 8 9 10");
1438 if (global->stat[i].rounds) {
1439 if ((num % 10) == 0)
1442 printf(
"%6.1f ", (
double)global->stat[i].cycles_0 / global->stat[i].rounds);
1450 printf(
"odp_timer_start() cycles per thread:\n");
1451 printf(
"-------------------------------------------------\n");
1452 printf(
" 1 2 3 4 5 6 7 8 9 10");
1455 if (global->stat[i].events) {
1456 if ((num % 10) == 0)
1459 printf(
"%6.1f ", (
double)global->stat[i].cycles_1 / global->stat[i].events);
1467 round_ave = (double)sum->rounds / sum->num;
1469 if (sum->before.num)
1470 before_ave = (double)sum->before.sum_ns / sum->before.num;
1473 after_ave = (double)sum->after.sum_ns / sum->after.num;
1475 printf(
"TOTAL (%i workers)\n", sum->num);
1476 printf(
" events: %" PRIu64
"\n", sum->events);
1477 printf(
" ave time: %.2f sec\n", sum->time_ave);
1478 printf(
" ave rounds per sec: %.2fM\n", (round_ave / sum->time_ave) / 1000000.0);
1479 printf(
" num before: %" PRIu64
"\n", sum->before.num);
1480 printf(
" ave before: %.1f nsec\n", before_ave);
1481 printf(
" max before: %" PRIu64
" nsec\n", sum->before.max_ns);
1482 printf(
" num after: %" PRIu64
"\n", sum->after.num);
1483 printf(
" ave after: %.1f nsec\n", after_ave);
1484 printf(
" max after: %" PRIu64
" nsec\n", sum->after.max_ns);
1488static void print_stat_timer_pool_ctrl_mode(test_global_t *global)
1491 test_stat_tp_ctrl_t sum;
1492 double create_ave = 0.0, start_ave = 0.0, alloc_ave = 0.0;
1493 double free_ave = 0.0, destroy_ave = 0.0;
1494 double time_ave = 0.0;
1495 uint64_t nsec_sum = 0;
1498 memset(&sum, 0,
sizeof(sum));
1501 const test_stat_tp_ctrl_t *stat = &global->stat_tp_ctrl[i];
1503 if (stat->rounds == 0)
1507 sum.rounds = stat->rounds;
1508 sum.num_tp_create += stat->num_tp_create;
1509 sum.tp_create_cycles += stat->tp_create_cycles;
1510 sum.num_tp_start += stat->num_tp_start;
1511 sum.tp_start_cycles += stat->tp_start_cycles;
1512 sum.num_timer_alloc += stat->num_timer_alloc;
1513 sum.timer_alloc_cycles += stat->timer_alloc_cycles;
1514 sum.num_timer_free += stat->num_timer_free;
1515 sum.timer_free_cycles += stat->timer_free_cycles;
1516 sum.num_tp_destroy += stat->num_tp_destroy;
1517 sum.tp_destroy_cycles += stat->tp_destroy_cycles;
1518 nsec_sum += stat->nsec;
1521 if (sum.num_tp_create)
1522 create_ave = (double)sum.tp_create_cycles / sum.num_tp_create;
1524 if (sum.num_tp_start)
1525 start_ave = (double)sum.tp_start_cycles / sum.num_tp_start;
1527 if (sum.num_timer_alloc)
1528 alloc_ave = (double)sum.timer_alloc_cycles / sum.num_timer_alloc;
1530 if (sum.num_timer_free)
1531 free_ave = (double)sum.timer_free_cycles / sum.num_timer_free;
1533 if (sum.num_tp_destroy)
1534 destroy_ave = (double)sum.tp_destroy_cycles / sum.num_tp_destroy;
1540 printf(
"RESULTS\n");
1541 printf(
"-------------------------------------------------\n");
1542 printf(
"TOTAL (%i workers)\n", num);
1543 printf(
" rounds per worker: %" PRIu64
"\n", sum.rounds);
1544 printf(
" ave time: %.2f sec\n", time_ave);
1546 printf(
" odp_timer_pool_create()\n");
1547 printf(
" calls: %" PRIu64
"\n", sum.num_tp_create);
1548 printf(
" ave cycles per call: %.1f\n", create_ave);
1549 printf(
" odp_timer_pool_start_multi()\n");
1550 printf(
" calls: %" PRIu64
"\n", sum.num_tp_start);
1551 printf(
" ave cycles per call: %.1f\n", start_ave);
1552 printf(
" odp_timer_alloc()\n");
1553 printf(
" calls: %" PRIu64
"\n", sum.num_timer_alloc);
1554 printf(
" ave cycles per call: %.1f\n", alloc_ave);
1555 printf(
" odp_timer_free()\n");
1556 printf(
" calls: %" PRIu64
"\n", sum.num_timer_free);
1557 printf(
" ave cycles per call: %.1f\n", free_ave);
1558 printf(
" odp_timer_pool_destroy()\n");
1559 printf(
" calls: %" PRIu64
"\n", sum.num_tp_destroy);
1560 printf(
" ave cycles per call: %.1f\n", destroy_ave);
1564static void sig_handler(
int signo)
1568 if (test_global == NULL)
1573int main(
int argc,
char **argv)
1575 odph_helper_options_t helper_options;
1579 test_global_t *global;
1580 test_options_t *test_options;
1581 int i, use_workers, mode;
1583 signal(SIGINT, sig_handler);
1586 argc = odph_parse_options(argc, argv);
1587 if (odph_options(&helper_options)) {
1588 ODPH_ERR(
"Reading ODP helper options failed.\n");
1600 init.
mem_model = helper_options.mem_model;
1604 ODPH_ERR(
"Global init failed.\n");
1610 ODPH_ERR(
"Local init failed.\n");
1614 shm =
odp_shm_reserve(
"timer_perf_global",
sizeof(test_global_t), ODP_CACHE_LINE_SIZE, 0);
1616 ODPH_ERR(
"Shared mem reserve failed.\n");
1621 if (global == NULL) {
1622 ODPH_ERR(
"Shared mem alloc failed\n");
1625 test_global = global;
1627 memset(global, 0,
sizeof(test_global_t));
1632 global->thread_arg[i].global = global;
1633 global->thread_arg[i].worker_idx = i;
1636 if (parse_options(argc, argv, &global->test_options))
1639 test_options = &global->test_options;
1640 mode = test_options->mode;
1643 if (!test_options->shared && mode != MODE_TP_CTRL)
1650 if (set_num_cpu(global, use_workers))
1653 init_global_handles(global);
1655 if (prepare_timer_pool_param(global, &global->timer_pool_param))
1663 if (mode != MODE_TP_CTRL) {
1664 if (create_timer_pools(global, &global->timer_pool_param))
1667 if (create_event_pools(global))
1671 if (create_event_queues(global))
1676 start_workers(global, instance);
1688 if (mode != MODE_TP_CTRL) {
1689 if (start_timers(global))
1699 if (mode == MODE_SCHED_OVERH) {
1700 if (sched_mode_worker(&global->thread_arg[0])) {
1701 ODPH_ERR(
"Sched_mode_worker failed\n");
1704 }
else if (mode == MODE_START_CANCEL) {
1705 if (start_cancel_mode_worker(&global->thread_arg[0])) {
1706 ODPH_ERR(
"Start_cancel_mode_worker failed\n");
1710 if (start_expire_mode_worker(&global->thread_arg[0])) {
1711 ODPH_ERR(
"Start_expire_mode_worker failed\n");
1717 odph_thread_join(global->thread_tbl,
1718 global->test_options.num_cpu);
1721 if (mode == MODE_TP_CTRL) {
1722 print_stat_timer_pool_ctrl_mode(global);
1726 if (mode == MODE_SCHED_OVERH)
1727 print_stat_sched_mode(global);
1728 else if (mode == MODE_START_CANCEL)
1729 print_stat_start_cancel_mode(global);
1731 print_stat_expire_mode(global);
1734 destroy_timer_pool(global);
1737 ODPH_ERR(
"Shared mem free failed.\n");
1742 ODPH_ERR(
"Term local failed.\n");
1747 ODPH_ERR(
"Term global failed.\n");
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
void odp_atomic_add_u32(odp_atomic_u32_t *atom, uint32_t val)
Add to atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_inc_u32(odp_atomic_u32_t *atom)
Increment atomic uint32 variable.
uint32_t odp_atomic_load_acq_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable using ACQUIRE memory ordering.
void odp_atomic_store_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable using RELEASE memory ordering.
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.
#define odp_unlikely(x)
Branch unlikely taken.
#define odp_likely(x)
Branch likely taken.
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.
uint64_t odp_cpu_cycles_strict(void)
Current CPU cycle count (strict)
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
void odp_event_free(odp_event_t event)
Free event.
#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.
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.
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_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.
#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.
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.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
odp_time_t odp_time_global(void)
Current global time.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_NULL
Zero time stamp.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_global_ns(void)
Current global time in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
void odp_timeout_free(odp_timeout_t tmo)
Timeout free.
int odp_timer_pool_start_multi(odp_timer_pool_t timer_pool[], int num)
Start timer pools.
void * odp_timeout_user_ptr(odp_timeout_t tmo)
Return user pointer for the timeout.
odp_timeout_t odp_timeout_alloc(odp_pool_t pool)
Timeout alloc.
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 an 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.
int odp_timer_cancel(odp_timer_t timer, odp_event_t *tmo_ev)
Cancel a single shot timer.
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.
uint64_t odp_timer_ns_to_tick(odp_timer_pool_t timer_pool, uint64_t ns)
Convert nanoseconds to timer ticks.
int odp_timer_start(odp_timer_t timer, const odp_timer_start_t *start_param)
Start a single shot timer.
int odp_timer_res_capability(odp_timer_clk_src_t clk_src, odp_timer_res_capability_t *res_capa)
Timer resolution capability.
odp_event_t odp_timeout_to_event(odp_timeout_t tmo)
Convert timeout handle to event handle.
int odp_timer_pool_info(odp_timer_pool_t timer_pool, odp_timer_pool_info_t *info)
Query timer pool configuration and current state.
odp_timer_t odp_timer_alloc(odp_timer_pool_t timer_pool, odp_queue_t queue, const void *user_ptr)
Allocate a single shot timer.
#define ODP_CLOCK_DEFAULT
The default clock source.
#define ODP_TIMER_INVALID
Invalid timer handle.
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.
@ ODP_TIMER_SUCCESS
Timer operation succeeded.
@ ODP_TIMER_TOO_NEAR
Timer operation failed, too near to the current time.
@ ODP_TIMER_TICK_REL
Relative ticks.
@ ODP_TIMER_TICK_ABS
Absolute ticks.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
uint32_t num
Number of buffers in the pool.
odp_pool_type_t type
Pool type.
struct odp_pool_param_t::@140 tmo
Parameters for timeout pools.
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.
uint32_t max_timers
Maximum number of single shot timers in a pool.
uint32_t max_pools
Maximum number of timer pools for single shot timers (per clock source)
odp_timer_res_capability_t max_res
Maximum resolution.
ODP timer pool information and configuration.
uint32_t hwm_timers
High watermark of allocated timers.
uint32_t cur_timers
Number of currently allocated timers.
uint64_t res_ns
Timeout resolution in nanoseconds.
int priv
Thread private timer pool.
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.
Timer resolution capability.
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.
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 cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
struct odp_feature_t::@174 feat
Individual feature bits.
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()