22#include <odp/helper/odph_api.h>
25#include <export_results.h>
30#define MAX_QUEUES 4096
32#define EVENT_POOL_SIZE (1024 * 1024)
41#define EVENT_FORWARD_RAND 0
42#define EVENT_FORWARD_INC 1
43#define EVENT_FORWARD_NONE 2
45#define MAX_BURST_SIZE 64
59 int src_idx[NUM_PRIOS];
74 unsigned int cpu_count;
105 test_stat_t prio[NUM_PRIOS];
116 test_common_options_t common_options;
117 test_track_t track[NUM_PRIOS];
128static void clear_sched_queues(test_globals_t *globals)
139 ODPH_ABORT(
"Buffer alloc failed.\n");
142 event->type = COOL_DOWN;
145 for (i = 0; i < NUM_PRIOS; i++) {
146 for (j = 0; j < globals->args.prio[i].queues; j++) {
149 ODPH_ABORT(
"Queue enqueue failed.\n");
157 if (event->type == COOL_DOWN)
170 ODPH_ABORT(
"Queue %" PRIu64
" not empty.\n",
188static int enqueue_events(
int prio,
int num_queues,
int num_events,
190 test_globals_t *globals)
198 int events_per_queue;
202 tot_events = num_events + num_samples;
204 if (!num_queues || !tot_events)
207 events_per_queue = tot_events;
209 events_per_queue = (tot_events + num_queues - 1) / num_queues;
211 for (i = 0; i < num_queues; i++) {
212 queue = globals->queue[prio][i];
216 if (ret != events_per_queue) {
217 ODPH_ERR(
"Buffer alloc failed. Try increasing EVENT_POOL_SIZE.\n");
218 ret = ret < 0 ? 0 : ret;
222 for (j = 0; j < events_per_queue; j++) {
224 ODPH_ERR(
"Buffer alloc failed\n");
230 memset(event, 0,
sizeof(test_event_t));
234 if (num_samples > 0) {
235 event->type = WARM_UP;
236 event->warm_up_rounds = 0;
239 event->type = TRAFFIC;
241 event->src_idx[prio] = i;
252 ODPH_ERR(
"Queue enqueue failed.\n");
256 }
while (enq_events < events_per_queue);
258 rdy_events += events_per_queue;
259 if (div_events && rdy_events >= tot_events)
270static int output_results(test_globals_t *globals)
279 args = &globals->args;
280 stype = globals->args.sync_type;
282 printf(
"\n%s queue scheduling latency\n",
286 printf(
" Forwarding mode: %s\n",
287 (args->forward_mode == EVENT_FORWARD_RAND) ?
"random" :
288 ((args->forward_mode == EVENT_FORWARD_INC) ?
"incremental" :
291 printf(
" Scheduling mode: %s\n", args->burst_size ?
"burst" :
"single");
292 if (args->burst_size)
293 printf(
" Burst size: %d\n", args->burst_size);
295 printf(
" LO_PRIO queues: %i\n", args->prio[LO_PRIO].queues);
296 if (args->prio[LO_PRIO].events_per_queue)
297 printf(
" LO_PRIO event per queue: %i\n",
298 args->prio[LO_PRIO].events);
300 printf(
" LO_PRIO events: %i\n", args->prio[LO_PRIO].events);
302 printf(
" LO_PRIO sample events: %i\n", args->prio[LO_PRIO].samples);
304 printf(
" HI_PRIO queues: %i\n", args->prio[HI_PRIO].queues);
305 if (args->prio[HI_PRIO].events_per_queue)
306 printf(
" HI_PRIO event per queue: %i\n\n",
307 args->prio[HI_PRIO].events);
309 printf(
" HI_PRIO events: %i\n", args->prio[HI_PRIO].events);
311 printf(
" HI_PRIO sample events: %i\n\n", args->prio[HI_PRIO].samples);
313 if (globals->common_options.is_export) {
314 if (test_common_write(
"high priority avg (ns),high priority min (ns),"
315 "high priority max (ns),low priority avg (ns),"
316 "low priority min (ns),low priority max (ns)\n")) {
317 ODPH_ERR(
"Export failed\n");
318 test_common_write_term();
323 for (i = 0; i < NUM_PRIOS; i++) {
324 memset(&total, 0,
sizeof(test_stat_t));
329 printf(
"%s priority\n"
330 "Thread Avg[ns] Min[ns] Max[ns] Samples Total Max idx\n"
331 "-----------------------------------------------------------------------\n",
332 i == HI_PRIO ?
"HIGH" :
"LOW");
333 for (j = 1; j <= args->cpu_count; j++) {
334 lat = &globals->core_stat[j].prio[i];
336 if (lat->samples == 0) {
337 printf(
"%-8d N/A\n", j);
342 total.max = lat->max;
344 total.min = lat->min;
346 total.samples += lat->samples;
347 total.events += lat->events;
350 printf(
"%-8d %-10" PRIu64
" %-10" PRIu64
" "
351 "%-10" PRIu64
" %-10" PRIu64
" %-10" PRIu64
" %-10" PRIu64
"\n",
353 lat->samples, lat->events, lat->max_idx);
355 printf(
"-----------------------------------------------------------------------\n");
356 if (total.samples == 0) {
357 printf(
"Total N/A\n\n");
361 avg = total.samples ?
odp_time_to_ns(total.tot) / total.samples : 0;
362 printf(
"Total %-10" PRIu64
" %-10" PRIu64
" %-10" PRIu64
" "
363 "%-10" PRIu64
" %-10" PRIu64
"\n\n", avg,
odp_time_to_ns(total.min),
366 if (globals->common_options.is_export) {
367 if (test_common_write(
"%" PRIu64
",%" PRIu64
",%" PRIu64
"%s",
370 ODPH_ERR(
"Export failed\n");
371 test_common_write_term();
377 if (globals->common_options.is_export)
378 test_common_write_term();
383static int join_groups(test_globals_t *globals,
int thr)
388 int num_group = globals->args.num_group;
394 if (globals->args.isolate)
400 for (i = 0; i < num; i++) {
401 if (globals->args.isolate)
402 group = globals->group[i % 2][i / 2];
404 group = globals->group[0][i];
407 ODPH_ERR(
"Group join failed %i (thr %i)\n", i, thr);
424 stats->max = latency;
425 stats->max_idx = stats->samples;
429 stats->min = latency;
435static inline int get_dst_idx(
const test_args_t *args,
const test_event_t *event)
439 if (args->forward_mode != EVENT_FORWARD_NONE)
440 dst_idx =
event->src_idx[
event->prio] + 1;
442 dst_idx =
event->src_idx[
event->prio];
444 if (dst_idx >= args->prio[event->prio].queues)
450static int test_schedule_single(
int thr, test_globals_t *globals)
452 const int warm_up_rounds = globals->args.warm_up_rounds;
453 const uint64_t test_rounds = globals->args.test_rounds * (uint64_t)1000000;
454 const uint64_t wait_ns = globals->args.wait_ns;
464 for (i = 0; i < test_rounds; i++) {
473 stats = &globals->core_stat[thr].prio[
event->prio];
475 if (event->type == SAMPLE) {
476 record_stats(stats, time, event->time_stamp);
479 if (!globals->args.sample_per_prio &&
480 globals->args.prio[!event->prio].queues)
481 event->prio = !
event->prio;
485 event->warm_up_rounds++;
486 if (event->warm_up_rounds >= warm_up_rounds)
487 event->type = SAMPLE;
493 dst_idx = get_dst_idx(&globals->args, event);
494 event->src_idx[
event->prio] = dst_idx;
495 dst_queue = globals->queue[
event->prio][dst_idx];
497 if (event->type == SAMPLE)
501 ODPH_ERR(
"[%i] Queue enqueue failed.\n", thr);
525static inline int enq_burst(
int thr, test_globals_t *globals,
odp_event_t burst_array[],
528 const test_args_t *args = &globals->args;
529 test_track_t *track = globals->track;
533 int num_enq, new_prio;
538 if (event->type == SAMPLE) {
540 if (!args->sample_per_prio && args->prio[!event->prio].queues) {
541 new_prio = !
event->prio;
542 event->prio = new_prio;
544 new_prio =
event->prio;
547 dst_idx = get_dst_idx(&globals->args, event);
548 dst_queue = globals->queue[
event->prio][dst_idx];
550 for (i = 0; i < burst_size; i++) {
552 event->prio = new_prio;
553 event->src_idx[
event->prio] = dst_idx;
558 dst_idx = get_dst_idx(&globals->args, event);
559 dst_queue = globals->queue[
event->prio][dst_idx];
561 for (i = 0; i < burst_size; i++) {
563 event->src_idx[
event->prio] = dst_idx;
570 ODPH_ERR(
"[%i] Queue enqueue failed.\n", thr);
575 }
while (enq < (
int)burst_size);
580static inline int collect_enq_sample(
int thr, test_globals_t *globals,
odp_event_t ev,
583 const uint32_t burst_size = globals->args.burst_size;
584 test_stat_t *stats = &globals->core_stat[thr].prio[prio];
585 test_track_t *track = &globals->track[prio];
588 odp_event_t *sample_collector = track->sample_collector;
593 sample_collector[idx] = ev;
596 if (idx == burst_size - 1) {
600 record_stats(stats, time, track->enq_time);
603 for (i = 0; i < burst_size; i++)
604 local_collector[i] = sample_collector[i];
609 if (enq_burst(thr, globals, local_collector, burst_size))
616static int test_schedule_burst(
int thr, test_globals_t *globals)
618 const int warm_up_rounds = globals->args.warm_up_rounds;
619 const uint64_t test_rounds = globals->args.test_rounds * (uint64_t)1000000;
620 const uint32_t burst_size = globals->args.burst_size;
621 const uint64_t wait_ns = globals->args.wait_ns;
622 uint32_t num_sched_ev;
629 uint32_t traffic_idx = 0;
633 for (i = 0; i < test_rounds; i++) {
635 ev_burst, burst_size);
641 for (j = 0; j < num_sched_ev; j++) {
644 stats = &globals->core_stat[thr].prio[
event->prio];
647 event->warm_up_rounds++;
648 if (event->warm_up_rounds >= warm_up_rounds)
649 event->type = SAMPLE;
655 if (event->type == SAMPLE) {
656 if (
odp_unlikely(collect_enq_sample(thr, globals, ev, time,
660 traffic_collector[traffic_idx++] = ev;
665 if (
odp_unlikely(enq_burst(thr, globals, traffic_collector,
691static int test_schedule(
int thr, test_globals_t *globals)
706 if (globals->args.burst_size) {
707 if (test_schedule_burst(thr, globals))
710 if (test_schedule_single(thr, globals))
726 ODPH_ERR(
"[%i] Queue enqueue failed.\n", thr);
734 if (thr == MAIN_THREAD) {
735 if (globals->args.burst_size) {
736 for (
int i = 0; i < NUM_PRIOS; i++) {
737 track = &globals->track[i];
748 clear_sched_queues(globals);
749 if (output_results(globals))
767 test_globals_t *globals;
776 if (globals == NULL) {
777 ODPH_ERR(
"Shared mem lookup failed\n");
781 if (join_groups(globals, thr))
784 if (thr == MAIN_THREAD) {
785 args = &globals->args;
787 if (enqueue_events(HI_PRIO, args->prio[HI_PRIO].queues,
788 args->prio[HI_PRIO].events, args->prio[HI_PRIO].samples,
789 !args->prio[HI_PRIO].events_per_queue,
793 if (enqueue_events(LO_PRIO, args->prio[LO_PRIO].queues,
794 args->prio[LO_PRIO].events, args->prio[LO_PRIO].samples,
795 !args->prio[LO_PRIO].events_per_queue,
800 if (test_schedule(thr, globals))
809static void usage(
void)
812 "OpenDataPlane scheduler latency benchmark application.\n"
814 "Usage: ./odp_sched_latency [options]\n"
815 "Optional OPTIONS:\n"
816 " -c, --count <number> CPU count, 0=all available, default=1\n"
817 " -b, --burst <num> Test burst size. Latency is measured over whole bursts.\n"
818 " -d, --duration <number> Test duration in scheduling rounds (millions), default=10, min=1\n"
819 " -f, --forward-mode <mode> Selection of target queue\n"
820 " 0: Random (default)\n"
822 " 2: Use source queue\n"
823 " -g, --num_group <num> Number of schedule groups. Round robins queues into groups.\n"
824 " -1: SCHED_GROUP_WORKER\n"
825 " 0: SCHED_GROUP_ALL (default)\n"
826 " -i, --isolate <mode> Select if shared or isolated groups are used. Ignored when num_group <= 0.\n"
827 " 0: All queues share groups (default)\n"
828 " 1: Separate groups for high and low priority queues. Creates 2xnum_group groups.\n"
829 " -l, --lo-prio-queues <number> Number of low priority scheduled queues (default=64)\n"
830 " -t, --hi-prio-queues <number> Number of high priority scheduled queues (default=16)\n"
831 " -m, --lo-prio-events-per-queue <number> Number of events per low priority queue (default=32).\n"
832 " Does not include sample event.\n"
833 " -n, --hi-prio-events-per-queue <number> Number of events per high priority queues (default=0)\n"
834 " Does not include sample event.\n"
835 " -o, --lo-prio-events <number> Total number of low priority events. Overrides the\n"
836 " number of events per queue, does not include sample event.\n"
837 " -p, --hi-prio-events <number> Total number of high priority events. Overrides the\n"
838 " number of events per queue, does not include sample event.\n"
839 " -r --sample-per-prio Allocate a separate sample event for each priority. By default\n"
840 " a single sample event is used and its priority is changed after\n"
841 " each processing round.\n"
842 " -s, --sync Scheduled queues' sync type\n"
843 " 0: ODP_SCHED_SYNC_PARALLEL (default)\n"
844 " 1: ODP_SCHED_SYNC_ATOMIC\n"
845 " 2: ODP_SCHED_SYNC_ORDERED\n"
846 " -w, --warm-up <number> Number of warm-up rounds, default=100, min=1\n"
847 " -W, --wait-ns <number> Number of nsec to wait per schedule round to simulate work (default=0)\n"
848 " -h, --help Display help and exit.\n\n");
858static void parse_args(
int argc,
char *argv[], test_args_t *args)
863 static const struct option longopts[] = {
864 {
"count", required_argument, NULL,
'c'},
865 {
"burst", required_argument, NULL,
'b'},
866 {
"duration", required_argument, NULL,
'd'},
867 {
"forward-mode", required_argument, NULL,
'f'},
868 {
"num_group", required_argument, NULL,
'g'},
869 {
"isolate", required_argument, NULL,
'i'},
870 {
"lo-prio-queues", required_argument, NULL,
'l'},
871 {
"hi-prio-queues", required_argument, NULL,
't'},
872 {
"lo-prio-events-per-queue", required_argument, NULL,
'm'},
873 {
"hi-prio-events-per-queue", required_argument, NULL,
'n'},
874 {
"lo-prio-events", required_argument, NULL,
'o'},
875 {
"hi-prio-events", required_argument, NULL,
'p'},
876 {
"sync", required_argument, NULL,
's'},
877 {
"warm-up", required_argument, NULL,
'w'},
878 {
"wait-ns", required_argument, NULL,
'W'},
879 {
"sample-per-prio", no_argument, NULL,
'r'},
880 {
"help", no_argument, NULL,
'h'},
884 static const char *shortopts =
"+c:b:d:f:g:i:l:t:m:n:o:p:s:w:W:rh";
887 args->forward_mode = EVENT_FORWARD_RAND;
890 args->test_rounds = 10;
891 args->warm_up_rounds = 100;
893 args->sample_per_prio = 0;
894 args->prio[LO_PRIO].queues = 64;
895 args->prio[HI_PRIO].queues = 16;
896 args->prio[LO_PRIO].events = 32;
897 args->prio[HI_PRIO].events = 0;
898 args->prio[LO_PRIO].events_per_queue = 1;
899 args->prio[HI_PRIO].events_per_queue = 0;
900 args->prio[LO_PRIO].samples = 0;
901 args->prio[HI_PRIO].samples = 1;
904 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
911 args->cpu_count = atoi(optarg);
914 args->test_rounds = atoi(optarg);
917 args->forward_mode = atoi(optarg);
920 args->num_group = atoi(optarg);
923 args->isolate = atoi(optarg);
926 args->prio[LO_PRIO].queues = atoi(optarg);
929 args->prio[HI_PRIO].queues = atoi(optarg);
932 args->prio[LO_PRIO].events = atoi(optarg);
933 args->prio[LO_PRIO].events_per_queue = 1;
936 args->prio[HI_PRIO].events = atoi(optarg);
937 args->prio[HI_PRIO].events_per_queue = 1;
940 args->prio[LO_PRIO].events = atoi(optarg);
941 args->prio[LO_PRIO].events_per_queue = 0;
944 args->prio[HI_PRIO].events = atoi(optarg);
945 args->prio[HI_PRIO].events_per_queue = 0;
957 args->sample_per_prio = 1;
960 args->warm_up_rounds = atoi(optarg);
963 args->wait_ns = atoll(optarg);
966 args->burst_size = atoi(optarg);
982 if (args->prio[LO_PRIO].queues > MAX_QUEUES)
983 args->prio[LO_PRIO].queues = MAX_QUEUES;
984 if (args->prio[HI_PRIO].queues > MAX_QUEUES)
985 args->prio[HI_PRIO].queues = MAX_QUEUES;
986 if (args->test_rounds < 1)
987 args->test_rounds = 1;
988 if (!args->prio[HI_PRIO].queues && !args->prio[LO_PRIO].queues) {
989 printf(
"No queues configured\n");
993 if (args->forward_mode > EVENT_FORWARD_NONE ||
994 args->forward_mode < EVENT_FORWARD_RAND) {
995 printf(
"Invalid forwarding mode\n");
1000 if (args->num_group > MAX_GROUPS) {
1001 ODPH_ERR(
"Too many groups. Max supported %i.\n", MAX_GROUPS);
1005 if (args->prio[HI_PRIO].queues == 0 || args->sample_per_prio)
1006 args->prio[LO_PRIO].samples = 1;
1008 if (args->burst_size < 0 || args->burst_size > MAX_BURST_SIZE) {
1009 ODPH_ERR(
"Invalid burst size %i, min 0, max %i\n",
1010 args->burst_size, MAX_BURST_SIZE);
1014 if (args->burst_size) {
1015 args->prio[HI_PRIO].samples = args->burst_size;
1016 if (args->sample_per_prio)
1017 args->prio[LO_PRIO].samples = args->burst_size;
1021static void randomize_queues(
odp_queue_t queues[], uint32_t num, uint64_t *seed)
1025 for (i = 0; i < num; i++) {
1032 new_index = new_index % num;
1033 swap_queue = queues[new_index];
1035 queues[new_index] = cur_queue;
1036 queues[i] = swap_queue;
1050 ODPH_ERR(
"Schedule capability failed\n");
1056 printf(
"Too many schedule groups %i (max %u)\n", num, max);
1060 for (i = 0; i < NUM_PRIOS; i++)
1061 for (j = 0; j < MAX_GROUPS; j++)
1066 for (i = 0; i < num; i++) {
1070 ODPH_ERR(
"Group create failed %i\n", i);
1074 if (globals->args.isolate) {
1075 globals->group[i % 2][i / 2] = group[i];
1077 globals->group[0][i] = group[i];
1078 globals->group[1][i] = group[i];
1092 for (i = 0; i < num; i++) {
1094 ODPH_ERR(
"Group destroy failed %i\n", i);
1102static int calc_queue_sizes(test_globals_t *globals, uint32_t queue_size[])
1105 test_args_t *args = &globals->args;
1106 const uint32_t min_queue_size = 256;
1107 uint32_t tot_queues = 0;
1110 ODPH_ERR(
"Schedule capability failed\n");
1114 for (
int i = 0; i < NUM_PRIOS; i++) {
1115 uint32_t events = args->prio[i].events;
1116 int queues = args->prio[i].queues;
1118 if (!args->prio[i].events_per_queue && queues)
1119 events = (events + queues - 1) / queues;
1122 if (args->forward_mode != EVENT_FORWARD_NONE)
1128 queue_size[i] = ODPH_MAX(events, min_queue_size);
1131 ODPH_ERR(
"Warn: queues may not be able to store all events (required size "
1132 "%" PRIu32
", max supported %" PRIu32
")\n", queue_size[i],
1136 tot_queues += queues;
1140 ODPH_ERR(
"Requested %" PRIu32
" queues, max %" PRIu32
" supported\n",
1148static int create_queues(test_globals_t *globals)
1151 test_args_t *args = &globals->args;
1152 int num_group = args->num_group;
1153 uint32_t queue_size[NUM_PRIOS];
1155 if (calc_queue_sizes(globals, queue_size))
1162 for (
int i = 0; i < NUM_PRIOS; i++) {
1163 char name[] =
"sched_XX_YY";
1171 param.
size = queue_size[i];
1174 name[6] =
'0' + (prio / 10);
1175 name[7] =
'0' + prio - (10 * (prio / 10));
1177 for (
int j = 0; j < args->prio[i].queues; j++) {
1178 name[9] =
'0' + j / 10;
1179 name[10] =
'0' + j - 10 * (j / 10);
1183 grp = globals->group[i][j % num_group];
1190 ODPH_ERR(
"Scheduled queue create failed\n");
1194 globals->queue[i][j] = queue;
1196 if (args->forward_mode == EVENT_FORWARD_RAND) {
1199 randomize_queues(globals->queue[i], args->prio[i].queues, &seed);
1205static void init_global_data(test_globals_t *globals, test_args_t *args,
1206 test_common_options_t common_options)
1208 memset(globals, 0,
sizeof(test_globals_t));
1209 memcpy(&globals->args, args,
sizeof(test_args_t));
1211 globals->common_options = common_options;
1216 for (
int i = 0; i < NUM_PRIOS; i++) {
1217 for (
int j = 0; j < MAX_GROUPS; j++) {
1231int main(
int argc,
char *argv[])
1235 odph_helper_options_t helper_options;
1236 odph_thread_common_param_t thr_common;
1237 odph_thread_param_t thr_param;
1241 test_globals_t *globals;
1246 int num_group, tot_group;
1250 int num_workers = 0;
1253 test_common_options_t common_options;
1255 printf(
"\nODP scheduling latency benchmark starts\n\n");
1258 argc = odph_parse_options(argc, argv);
1259 if (odph_options(&helper_options)) {
1260 ODPH_ERR(
"Error: reading ODP helper options failed.\n");
1264 argc = test_common_parse_options(argc, argv);
1265 if (test_common_options(&common_options)) {
1266 ODPH_ERR(
"Error: reading test options failed\n");
1271 init_param.
mem_model = helper_options.mem_model;
1273 memset(&args, 0,
sizeof(args));
1274 parse_args(argc, argv, &args);
1278 ODPH_ERR(
"ODP global init failed.\n");
1287 ODPH_ERR(
"ODP global init failed.\n");
1293 num_group = args.num_group;
1297 tot_group = args.isolate ? 2 * num_group : num_group;
1301 num_workers = args.cpu_count;
1304 args.cpu_count = num_workers;
1308 printf(
"Test options:\n");
1309 printf(
" Worker threads: %i\n", num_workers);
1311 printf(
" CPU mask: %s\n", cpumaskstr);
1312 printf(
" Test rounds: %iM\n", args.test_rounds);
1313 printf(
" Warm-up rounds: %i\n", args.warm_up_rounds);
1314 printf(
" Wait nsec: %" PRIu64
"\n", args.wait_ns);
1315 printf(
" Isolated groups: %i\n", args.isolate);
1316 printf(
" Number of groups: %i\n", num_group);
1317 printf(
" Created groups: %i\n", tot_group);
1320 shm =
odp_shm_reserve(
"test_globals",
sizeof(test_globals_t), ODP_CACHE_LINE_SIZE, 0);
1322 ODPH_ERR(
"Shared memory reserve failed.\n");
1328 init_global_data(globals, &args, common_options);
1335 ODPH_ERR(
"pool capa failed\n");
1340 pool_size = EVENT_POOL_SIZE;
1345 params.
buf.
size =
sizeof(test_event_t);
1347 params.
buf.
num = pool_size;
1353 ODPH_ERR(
"Pool create failed.\n");
1357 globals->pool = pool;
1360 ret = create_groups(globals, group, tot_group);
1361 if (ret != tot_group) {
1362 ODPH_ERR(
"Group create failed.\n");
1368 if (create_queues(globals)) {
1369 ODPH_ERR(
"Creating test queues failed.\n");
1375 memset(thread_tbl, 0,
sizeof(thread_tbl));
1377 odph_thread_common_param_init(&thr_common);
1378 thr_common.instance = instance;
1379 thr_common.cpumask = &cpumask;
1380 thr_common.share_param = 1;
1382 odph_thread_param_init(&thr_param);
1383 thr_param.start = run_thread;
1384 thr_param.arg = NULL;
1387 odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
1390 if (odph_thread_join(thread_tbl, num_workers) != num_workers)
1393 printf(
"ODP scheduling latency test complete\n\n");
1395 for (i = 0; i < NUM_PRIOS; i++) {
1399 num_queues = args.prio[i].queues;
1401 for (j = 0; j < num_queues; j++) {
1402 queue = globals->queue[i][j];
1404 ODPH_ERR(
"Queue destroy failed [%i][%i]\n", i, j);
1412 if (destroy_groups(group, tot_group)) {
1413 ODPH_ERR(
"Group destroy failed\n");
1419 ODPH_ERR(
"Pool destroy failed\n");
1426 ODPH_ERR(
"SHM destroy failed\n");
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *atom)
Fetch and 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_add_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Add to atomic uint32 variable using RELEASE memory ordering.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
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_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.
int odp_buffer_is_valid(odp_buffer_t buf)
Check that buffer is valid.
odp_buffer_t odp_buffer_from_event(odp_event_t ev)
Get buffer handle from event.
void * odp_buffer_addr(odp_buffer_t buf)
Buffer start address.
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_ALIGNED_CACHE
Defines type/struct/variable to be cache line size aligned.
#define odp_unlikely(x)
Branch unlikely taken.
#define ODP_UNUSED
Intentionally unused variables of functions.
void odp_cpu_pause(void)
Pause CPU execution for a short while.
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.
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_multi(const odp_event_t event[], int num)
Free multiple events.
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.
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_BUFFER
Buffer pool.
int odp_queue_enq_multi(odp_queue_t queue, const odp_event_t events[], int num)
Enqueue multiple events to a queue.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to 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.
uint64_t odp_queue_to_u64(odp_queue_t hdl)
Get printable value for an odp_queue_t.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
Generate repeatable random data for testing purposes.
int odp_schedule_sync_t
Scheduler synchronization method.
#define ODP_SCHED_WAIT
Wait infinitely.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
int odp_schedule_group_t
Scheduler thread group.
int odp_schedule_group_join(odp_schedule_group_t group, const odp_thrmask_t *mask)
Join a schedule group.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_SYNC_ORDERED
Ordered queue synchronization.
int odp_schedule_min_prio(void)
Minimum scheduling priority level.
#define ODP_SCHED_GROUP_WORKER
Group of all worker threads.
int odp_schedule_group_destroy(odp_schedule_group_t group)
Schedule group destroy.
#define ODP_SCHED_GROUP_INVALID
Invalid scheduler group.
#define ODP_SCHED_NO_WAIT
Do not wait.
void odp_schedule_pause(void)
Pause scheduling.
int odp_schedule_max_prio(void)
Maximum scheduling priority level.
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.
odp_schedule_group_t odp_schedule_group_create(const char *name, const odp_thrmask_t *mask)
Schedule group create.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
void odp_schedule_resume(void)
Resume scheduling.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
odp_shm_t odp_shm_lookup(const char *name)
Lookup for a block of shared memory.
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.
bool odp_bool_t
Boolean type.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
void odp_thrmask_set(odp_thrmask_t *mask, int thr)
Add thread to mask.
int odp_thread_id(void)
Get thread identifier.
void odp_thrmask_zero(odp_thrmask_t *mask)
Clear entire thread mask.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
odp_time_t odp_time_diff(odp_time_t t2, odp_time_t t1)
Time difference.
odp_time_t odp_time_sum(odp_time_t t1, odp_time_t t2)
Time sum.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
#define ODP_TIME_NULL
Zero time stamp.
odp_time_t odp_time_global_strict(void)
Current global time (strict)
int odp_time_cmp(odp_time_t t2, odp_time_t t1)
Compare two times.
odp_time_t odp_time_global_from_ns(uint64_t ns)
Convert nanoseconds to global time.
#define ODP_TIME_HOUR_IN_NS
An hour in nanoseconds.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
uint32_t max_num
Maximum number of buffers of any size.
struct odp_pool_capability_t::@133 buf
Buffer pool capabilities
uint32_t num
Number of buffers in the pool.
uint32_t align
Minimum buffer alignment in bytes.
uint32_t size
Minimum buffer size in bytes.
odp_pool_type_t type
Pool type.
struct odp_pool_param_t::@138 buf
Parameters for buffer pools.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
uint32_t max_groups
Maximum number of scheduling groups.
uint32_t max_queues
Maximum number of scheduled (ODP_BLOCKING) queues of the default size.
uint32_t max_queue_size
Maximum number of events a scheduled (ODP_BLOCKING) queue can store simultaneously.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.