28 #include <odp/helper/odph_api.h>
30 #define EXIT_NOT_SUP 2
31 #define PROG_NAME "odp_dmafwd"
40 #define DEF_CPY_TYPE SW_COPY
41 #define DEF_CNT 32768U
43 #define DEF_WORKERS 1U
47 #define MAX_OUT_QS 32U
49 #define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
51 #define DIV_IF(a, b) ((b) > 0U ? ((a) / (b)) : 0U)
54 ODP_STATIC_ASSERT(MAX_OUT_QS < UINT8_MAX,
"Too large maximum output queue count");
70 typedef struct prog_config_s prog_config_t;
77 uint64_t buf_alloc_errs;
78 uint64_t compl_alloc_errs;
79 uint64_t pkt_alloc_errs;
80 uint64_t trs_poll_errs;
86 uint64_t sched_rounds;
91 prog_config_t *prog_config;
102 typedef struct pktio_s {
119 odp_dma_seg_t *dst_segs, pktio_t *pktio, thread_config_t *config);
124 typedef void (*pkt_fn_t)(
odp_packet_t pkts[],
int num, pktio_t *pktio, init_fn_t init_fn,
125 start_fn_t start_fn, thread_config_t *config);
127 typedef void (*drain_fn_t)(thread_config_t *config);
129 typedef struct prog_config_s {
131 odph_thread_t thread_tbl[MAX_WORKERS];
132 thread_config_t thread_config[MAX_WORKERS];
133 pktio_t pktios[MAX_IFS];
134 dynamic_defs_t dyn_defs;
150 uint64_t inflight_obj_size;
155 uint32_t num_inflight;
156 uint32_t trs_cache_size;
157 uint32_t compl_cache_size;
158 uint32_t stash_cache_size;
173 static prog_config_t *prog_conf;
180 static void init_config(prog_config_t *config)
186 thread_config_t *thr;
188 memset(config, 0,
sizeof(*config));
192 burst_size = ODPH_MIN(burst_size, MAX_BURST);
193 config->dyn_defs.burst_size = burst_size;
197 config->dyn_defs.num_pkts = pool_capa.
pkt.
max_num > 0U ?
198 ODPH_MIN(pool_capa.
pkt.
max_num, DEF_CNT) : DEF_CNT;
199 config->dyn_defs.pkt_len = pool_capa.
pkt.
max_len > 0U ?
200 ODPH_MIN(pool_capa.
pkt.
max_len, DEF_LEN) : DEF_LEN;
208 config->burst_size = config->dyn_defs.burst_size;
209 config->num_pkts = config->dyn_defs.num_pkts;
210 config->pkt_len = config->dyn_defs.pkt_len;
211 config->cache_size = config->dyn_defs.cache_size;
212 config->time_sec = DEF_TIME;
213 config->num_thrs = DEF_WORKERS;
214 config->copy_type = DEF_CPY_TYPE;
216 for (
int i = 0; i < MAX_WORKERS; ++i) {
217 thr = &config->thread_config[i];
224 for (uint32_t i = 0U; i < MAX_IFS; ++i)
228 static void print_usage(dynamic_defs_t *dyn_defs)
231 "DMA performance tester with packet I/O. Receive and forward packets after\n"
232 "software copy or DMA offload copy.\n"
234 "Usage: " PROG_NAME
" OPTIONS\n"
236 " E.g. " PROG_NAME
" -i eth0\n"
237 " " PROG_NAME
" -i eth0 -t 0\n"
238 " " PROG_NAME
" -i eth0 -t 1 -b 15 -l 4096 -c 5\n"
240 "Mandatory OPTIONS:\n"
242 " -i, --interfaces Ethernet interfaces for packet I/O, comma-separated, no\n"
245 "Optional OPTIONS:\n"
247 " -t, --copy_type Type of copy. %u by default.\n"
249 " 1: DMA with event completion\n"
250 " 2: DMA with poll completion\n"
251 " -b, --burst_size Copy burst size. This many packets are accumulated before\n"
252 " copy. %u by default.\n"
253 " -n, --num_pkts Number of packet buffers allocated for packet I/O pool.\n"
255 " -l, --pkt_len Maximum size of packet buffers in packet I/O pool. %u by\n"
257 " -c, --worker_count Amount of workers. %u by default.\n"
258 " -C, --cache_size Maximum cache size for pools. %u by default.\n"
259 " -T, --time_sec Time in seconds to run. 0 means infinite. %u by default.\n"
260 " -s, --seg_free Use DMA source segment free offload. Disabled by default.\n"
261 " -h, --help This help.\n"
262 "\n", DEF_CPY_TYPE, dyn_defs->burst_size, dyn_defs->num_pkts, dyn_defs->pkt_len,
263 DEF_WORKERS, dyn_defs->cache_size, DEF_TIME);
266 static void parse_interfaces(prog_config_t *config,
const char *optarg)
268 char *tmp_str = strdup(optarg), *tmp;
273 tmp = strtok(tmp_str, DELIMITER);
275 while (tmp && config->num_ifs < MAX_IFS) {
276 config->pktios[config->num_ifs].name = strdup(tmp);
278 if (config->pktios[config->num_ifs].name != NULL)
281 tmp = strtok(NULL, DELIMITER);
302 static parse_result_t check_options(prog_config_t *config)
311 if (config->num_ifs == 0U) {
312 ODPH_ERR(
"Invalid number of interfaces: %u (min: 1, max: %u)\n", config->num_ifs,
317 if (config->copy_type != SW_COPY && config->copy_type != DMA_COPY_EV &&
318 config->copy_type != DMA_COPY_POLL) {
319 ODPH_ERR(
"Invalid copy type: %u\n", config->copy_type);
323 if (config->num_thrs <= 0 || config->num_thrs > MAX_WORKERS) {
324 ODPH_ERR(
"Invalid worker count: %d (min: 1, max: %d)\n", config->num_thrs,
330 ODPH_ERR(
"Error querying DMA capabilities\n");
335 ODPH_ERR(
"Unsupported source segment free by DMA\n");
339 if ((uint32_t)config->num_thrs > dma_capa.
max_sessions) {
340 ODPH_ERR(
"Unsupported DMA session count: %d (max: %u)\n", config->num_thrs,
346 burst_size = ODPH_MIN(burst_size, MAX_BURST);
348 if (config->burst_size == 0U || config->burst_size > burst_size) {
349 ODPH_ERR(
"Invalid segment count for DMA: %u (min: 1, max: %u)\n",
350 config->burst_size, burst_size);
355 ODPH_ERR(
"Invalid packet length for DMA: %u (max: %u)\n", config->pkt_len,
363 ODPH_ERR(
"Error querying pool capabilities\n");
369 ODPH_ERR(
"Invalid pool cache size: %u (min: %u, max: %u)\n", config->cache_size,
374 if (config->copy_type != SW_COPY)
375 config->trs_cache_size = ODPH_MIN(ODPH_MAX(config->cache_size,
379 if (config->copy_type == DMA_COPY_EV) {
382 ODPH_ERR(
"Unsupported DMA completion mode: event (mode support: %x, "
389 ODPH_ERR(
"Invalid amount of DMA completion pools: %d (max: %u)\n",
394 if (config->num_inflight > dma_capa.
pool.
max_num) {
395 ODPH_ERR(
"Invalid amount of DMA completion events: %u (max: %u)\n",
400 config->compl_cache_size = ODPH_MIN(ODPH_MAX(config->cache_size,
403 }
else if (config->copy_type == DMA_COPY_POLL) {
405 ODPH_ERR(
"Unsupported DMA completion mode: poll (mode support: %x)\n",
410 if (!get_stash_capa(&stash_capa, &config->stash_type)) {
411 ODPH_ERR(
"Error querying stash capabilities\n");
415 if ((uint32_t)config->num_thrs > stash_capa.
max_stashes) {
416 ODPH_ERR(
"Invalid amount of stashes: %d (max: %u)\n", config->num_thrs,
421 if (obj_size ==
sizeof(uint8_t)) {
423 }
else if (obj_size ==
sizeof(uint16_t)) {
425 }
else if (obj_size <=
sizeof(uint32_t)) {
427 }
else if (obj_size <=
sizeof(uint64_t)) {
432 ODPH_ERR(
"Invalid stash object size: %" PRIu64
"\n", obj_size);
436 if (config->num_inflight > max_num) {
437 ODPH_ERR(
"Invalid stash size: %u (max: %" PRIu64
")\n",
438 config->num_inflight, max_num);
442 config->inflight_obj_size = obj_size;
443 config->stash_cache_size = ODPH_MIN(config->cache_size, stash_capa.
max_cache_size);
446 if (config->num_pkts == 0U ||
448 ODPH_ERR(
"Invalid pool packet count: %u (min: 1, max: %u)\n", config->num_pkts,
453 if (config->pkt_len == 0U ||
455 ODPH_ERR(
"Invalid pool packet length: %u (min: 1, max: %u)\n", config->pkt_len,
460 if (config->num_inflight > pool_capa.
buf.
max_num) {
461 ODPH_ERR(
"Invalid pool buffer count: %u (max: %u)\n", config->num_inflight,
469 static parse_result_t parse_options(
int argc,
char **argv, prog_config_t *config)
473 static const struct option longopts[] = {
474 {
"interfaces", required_argument, NULL,
'i' },
475 {
"copy_type", required_argument, NULL,
't' },
476 {
"burst_size", required_argument, NULL,
'b' },
477 {
"num_pkts", required_argument, NULL,
'n' },
478 {
"pkt_len", required_argument, NULL,
'l' },
479 {
"worker_count", required_argument, NULL,
'c' },
480 {
"cache_size", required_argument, NULL,
'C' },
481 {
"time_sec", required_argument, NULL,
'T' },
482 {
"seg_free", no_argument, NULL,
's' },
483 {
"help", no_argument, NULL,
'h' },
487 static const char *shortopts =
"i:t:b:n:l:c:C:T:sh";
492 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
499 parse_interfaces(config, optarg);
502 config->copy_type = atoi(optarg);
505 config->burst_size = atoi(optarg);
508 config->num_pkts = atoi(optarg);
511 config->pkt_len = atoi(optarg);
514 config->num_thrs = atoi(optarg);
517 config->cache_size = atoi(optarg);
520 config->time_sec = atof(optarg);
523 config->seg_free = 1;
526 print_usage(&config->dyn_defs);
530 print_usage(&config->dyn_defs);
535 return check_options(config);
538 static parse_result_t setup_program(
int argc,
char **argv, prog_config_t *config)
540 struct sigaction action = { .sa_handler = terminate };
542 if (sigemptyset(&action.sa_mask) == -1 || sigaddset(&action.sa_mask, SIGINT) == -1 ||
543 sigaddset(&action.sa_mask, SIGTERM) == -1 ||
544 sigaddset(&action.sa_mask, SIGHUP) == -1 || sigaction(SIGINT, &action, NULL) == -1 ||
545 sigaction(SIGTERM, &action, NULL) == -1 || sigaction(SIGHUP, &action, NULL) == -1) {
546 ODPH_ERR(
"Error installing signal handler\n");
550 return parse_options(argc, argv, config);
558 ret = ret < 0 ? 0 : ret;
565 static void sw_copy_and_send_packets(
odp_packet_t pkts[],
int num, pktio_t *pktio,
567 thread_config_t *config)
572 int num_out_pkts = 0, num_sent;
573 stats_t *stats = &config->stats;
575 for (
int i = 0; i < num; ++i) {
580 out_pkts[num_out_pkts++] = new_pkt;
587 if (num_out_pkts > 0) {
588 num_sent = send_packets(pktio->out_qs[config->thr_idx % pktio->num_out_qs],
589 out_pkts, num_out_pkts);
590 stats->fwd_pkts += num_sent;
591 stats->discards += num_out_pkts - num_sent;
598 thread_config_t *config)
601 stats_t *stats = &config->stats;
608 ++stats->buf_alloc_errs;
621 if (config->prog_config->seg_free)
622 trs_param->
opts.seg_free = 1;
628 ++stats->compl_alloc_errs;
633 compl_param->
queue = config->compl_q;
635 memset(src_segs, 0,
sizeof(*src_segs) * MAX_BURST);
636 memset(dst_segs, 0,
sizeof(*dst_segs) * MAX_BURST);
644 thread_config_t *config)
647 stats_t *stats = &config->stats;
653 ++stats->buf_alloc_errs;
666 if (config->prog_config->seg_free)
667 trs_param->
opts.seg_free = 1;
673 ++stats->compl_alloc_errs;
678 memset(src_segs, 0,
sizeof(*src_segs) * MAX_BURST);
679 memset(dst_segs, 0,
sizeof(*dst_segs) * MAX_BURST);
711 ODPH_ABORT(
"DMA inflight transfer stash overflow, aborting");
716 static void dma_copy(
odp_packet_t pkts[],
int num, pktio_t *pktio, init_fn_t init_fn,
717 start_fn_t start_fn, thread_config_t *config)
722 transfer_t *trs = NULL;
724 uint32_t num_segs = 0U, pkt_len;
726 stats_t *stats = &config->stats;
731 for (
int i = 0; i < num; ++i) {
735 trs = init_fn(&trs_param, &compl_param, src_segs, dst_segs, pktio, config);
744 src_segs[num_segs].
packet = pkt;
745 src_segs[num_segs].
len = pkt_len;
750 ++stats->pkt_alloc_errs;
754 dst_segs[num_segs].
len = pkt_len;
755 trs->src_pkts[num_segs] = src_segs[num_segs].
packet;
756 trs->dst_pkts[num_segs] = dst_segs[num_segs].
packet;
764 if (
odp_unlikely(!start_fn(&trs_param, &compl_param, config))) {
771 static void drain_events(thread_config_t *config
ODP_UNUSED)
778 const odp_bool_t seg_free = config->prog_config->seg_free;
788 if (type == ODP_EVENT_DMA_COMPL) {
789 memset(&res, 0,
sizeof(res));
803 static void drain_polled(thread_config_t *config)
810 const odp_bool_t seg_free = config->prog_config->seg_free;
816 memset(&res, 0,
sizeof(res));
836 static odp_bool_t setup_copy(prog_config_t *config)
839 thread_config_t *thr;
852 pool_param.
pkt.
len = config->pkt_len;
853 pool_param.
pkt.
num = config->num_pkts;
859 ODPH_ERR(
"Error creating packet copy pool\n");
863 if (config->copy_type == SW_COPY) {
864 config->pkt_fn = sw_copy_and_send_packets;
866 for (
int i = 0; i < config->num_thrs; ++i)
867 config->thread_config[i].copy_pool = config->copy_pool;
872 pool_param.
buf.
num = config->num_inflight;
873 pool_param.
buf.
size =
sizeof(transfer_t);
879 ODPH_ERR(
"Error creating DMA transfer tracking pool\n");
883 for (
int i = 0; i < config->num_thrs; ++i) {
884 thr = &config->thread_config[i];
885 thr->copy_pool = config->copy_pool;
886 thr->trs_pool = config->trs_pool;
890 ODPH_ERR(
"Error creating DMA session\n");
894 if (config->copy_type == DMA_COPY_EV) {
896 compl_pool_param.
num = config->num_inflight;
897 compl_pool_param.
cache_size = config->compl_cache_size;
902 ODPH_ERR(
"Error creating DMA event completion pool\n");
913 ODPH_ERR(
"Error creating DMA completion queue\n");
917 config->init_fn = init_dma_ev_trs;
918 config->start_fn = start_dma_ev_trs;
919 config->drain_fn = drain_events;
922 stash_param.
type = config->stash_type;
925 stash_param.
num_obj = config->num_inflight;
926 stash_param.
obj_size = config->inflight_obj_size;
927 stash_param.
cache_size = config->stash_cache_size;
931 ODPH_ERR(
"Error creating DMA inflight transfer stash\n");
935 config->init_fn = init_dma_poll_trs;
936 config->start_fn = start_dma_poll_trs;
937 config->drain_fn = drain_polled;
941 config->pkt_fn = dma_copy;
946 static odp_bool_t setup_pktios(prog_config_t *config)
952 uint32_t num_input_qs, num_output_qs;
958 pool_param.
pkt.
len = config->pkt_len;
959 pool_param.
pkt.
num = config->num_pkts;
965 ODPH_ERR(
"Error creating packet I/O pool\n");
969 for (uint32_t i = 0U; i < config->num_ifs; ++i) {
970 pktio = &config->pktios[i];
974 pktio->handle =
odp_pktio_open(pktio->name, config->pktio_pool, &pktio_param);
977 ODPH_ERR(
"Error opening packet I/O (%s)\n", pktio->name);
984 ODPH_ERR(
"Error querying packet I/O capabilities (%s)\n", pktio->name);
990 num_output_qs = ODPH_MIN(num_output_qs, MAX_OUT_QS);
993 if (num_input_qs > 1) {
1002 ODPH_ERR(
"Error configuring packet I/O input queues (%s)\n", pktio->name);
1008 if (num_output_qs == (uint32_t)config->num_thrs)
1012 pktio->num_out_qs = num_output_qs;
1015 ODPH_ERR(
"Error configuring packet I/O output queues (%s)\n", pktio->name);
1020 (
int)num_output_qs) {
1021 ODPH_ERR(
"Error querying packet I/O output queues (%s)\n", pktio->name);
1026 ODPH_ERR(
"Error starting packet I/O (%s)\n", pktio->name);
1034 static inline void send_dma_poll_trs_pkts(
int burst_size, thread_config_t *config)
1036 odp_stash_t stash_handle = config->inflight_stash;
1039 odp_dma_t dma_handle = config->dma_handle;
1046 stats_t *stats = &config->stats;
1047 const odp_bool_t seg_free = config->prog_config->seg_free;
1055 for (int32_t i = 0; i < num; ++i) {
1063 ODPH_ABORT(
"DMA inflight transfer stash overflow,"
1066 ++stats->trs_polled;
1073 ++stats->trs_poll_errs;
1082 num_sent = send_packets(pktio->out_qs[config->thr_idx %
1084 trs->dst_pkts, trs->num);
1086 stats->fwd_pkts += num_sent;
1087 stats->discards += trs->num - num_sent;
1101 static inline void send_dma_ev_trs_pkts(
odp_dma_compl_t compl_ev, thread_config_t *config)
1108 stats_t *stats = &config->stats;
1109 const odp_bool_t seg_free = config->prog_config->seg_free;
1111 memset(&res, 0,
sizeof(res));
1118 num_sent = send_packets(pktio->out_qs[config->thr_idx % pktio->num_out_qs],
1119 trs->dst_pkts, trs->num);
1121 stats->fwd_pkts += num_sent;
1122 stats->discards += trs->num - num_sent;
1136 static inline void push_packet(
odp_packet_t pkt, pkt_vec_t pkt_vecs[], uint8_t *pktio_idx_map)
1139 pkt_vec_t *pkt_vec = &pkt_vecs[idx];
1141 pkt_vec->pkts[pkt_vec->num++] = pkt;
1144 static inline void pop_packets(pkt_vec_t *pkt_vec,
int num_procd)
1146 pkt_vec->num -= num_procd;
1148 for (
int i = 0, j = num_procd; i < pkt_vec->num; ++i, ++j)
1149 pkt_vec->pkts[i] = pkt_vec->pkts[j];
1152 static void free_pending_packets(pkt_vec_t pkt_vecs[], uint32_t num_ifs, stats_t *stats)
1154 for (uint32_t i = 0U; i < num_ifs; ++i) {
1155 stats->pkt_cleanup += pkt_vecs[i].num;
1160 static int process_packets(
void *args)
1162 thread_config_t *config = args;
1163 const uint8_t num_ifs = config->prog_config->num_ifs;
1164 pkt_vec_t pkt_vecs[num_ifs], *pkt_vec;
1166 uint64_t c1, c2, c3, c4, cdiff = 0U, rounds = 0U;
1167 const uint8_t copy_type = config->prog_config->copy_type;
1168 const int burst_size = config->prog_config->burst_size;
1173 uint8_t *pktio_map = config->prog_config->pktio_idx_map;
1174 stats_t *stats = &config->stats;
1175 init_fn_t init_fn = config->prog_config->init_fn;
1176 start_fn_t start_fn = config->prog_config->start_fn;
1177 pkt_fn_t pkt_fn = config->prog_config->pkt_fn;
1179 for (uint32_t i = 0U; i < num_ifs; ++i) {
1180 pkt_vecs[i].pktio = &config->prog_config->pktios[i];
1181 pkt_vecs[i].num = 0;
1195 if (copy_type == DMA_COPY_POLL)
1196 send_dma_poll_trs_pkts(burst_size, config);
1201 for (
int i = 0; i < num_evs; ++i) {
1205 if (type == ODP_EVENT_DMA_COMPL) {
1207 }
else if (type == ODP_EVENT_PACKET) {
1215 for (uint32_t i = 0U; i < num_ifs; ++i) {
1216 pkt_vec = &pkt_vecs[i];
1218 if (pkt_vec->num >= burst_size) {
1219 pkt_fn(pkt_vec->pkts, burst_size, pkt_vec->pktio, init_fn,
1221 pop_packets(pkt_vec, burst_size);
1227 stats->sched_cc = cdiff;
1229 stats->sched_rounds = rounds;
1230 free_pending_packets(pkt_vecs, num_ifs, stats);
1233 if (config->prog_config->drain_fn)
1234 config->prog_config->drain_fn(config);
1239 static odp_bool_t setup_workers(prog_config_t *config)
1243 odph_thread_common_param_t thr_common;
1244 odph_thread_param_t thr_param[config->num_thrs];
1247 odph_thread_common_param_init(&thr_common);
1248 thr_common.instance = config->odp_instance;
1249 thr_common.cpumask = &cpumask;
1251 for (
int i = 0; i < config->num_thrs; ++i) {
1252 odph_thread_param_init(&thr_param[i]);
1253 thr_param[i].start = process_packets;
1255 config->thread_config[i].prog_config = config;
1256 thr_param[i].arg = &config->thread_config[i];
1259 num_workers = odph_thread_create(config->thread_tbl, &thr_common, thr_param, num_workers);
1261 if (num_workers != config->num_thrs) {
1262 ODPH_ERR(
"Error configuring worker threads\n");
1269 static odp_bool_t setup_test(prog_config_t *config)
1274 if (!setup_copy(config))
1277 if (!setup_pktios(config))
1280 if (!setup_workers(config))
1288 static void stop_test(prog_config_t *config)
1290 for (uint32_t i = 0U; i < config->num_ifs; ++i)
1295 (void)odph_thread_join(config->thread_tbl, config->num_thrs);
1298 static void teardown(prog_config_t *config)
1300 thread_config_t *thr;
1302 for (uint32_t i = 0U; i < config->num_ifs; ++i) {
1303 free(config->pktios[i].name);
1312 for (
int i = 0; i < config->num_thrs; ++i) {
1313 thr = &config->thread_config[i];
1335 static void print_stats(
const prog_config_t *config)
1337 const stats_t *stats;
1338 const char *align1 = config->copy_type == DMA_COPY_EV ?
" " :
"";
1339 const char *align2 = config->copy_type == SW_COPY ?
" " :
1340 config->copy_type == DMA_COPY_EV ?
" " :
1343 printf(
"\n==================\n\n"
1344 "DMA forwarder done\n\n"
1347 " packet length: %u\n"
1348 " max cache size: %u\n"
1349 " use DMA source segment free: %s\n", config->copy_type == SW_COPY ?
"SW" :
1350 config->copy_type == DMA_COPY_EV ?
"DMA-event" :
"DMA-poll",
1351 config->burst_size, config->pkt_len, config->cache_size,
1352 config->seg_free ?
"yes" :
"no");
1354 for (
int i = 0; i < config->num_thrs; ++i) {
1355 stats = &config->thread_config[i].stats;
1357 printf(
"\n worker %d:\n", i);
1359 if (config->copy_type == SW_COPY) {
1360 printf(
" packet copy errors: %" PRIu64
"\n",
1363 printf(
" successful DMA transfers: %s%" PRIu64
"\n"
1364 " DMA transfer start errors: %s%" PRIu64
"\n"
1365 " DMA transfer errors: %s%" PRIu64
"\n"
1366 " transfer buffer allocation errors: %s%" PRIu64
"\n"
1367 " copy packet allocation errors: %s%" PRIu64
"\n",
1368 align1, stats->trs, align1, stats->start_errs, align1,
1369 stats->trs_errs, align1, stats->buf_alloc_errs, align1,
1370 stats->pkt_alloc_errs);
1372 if (config->copy_type == DMA_COPY_EV)
1373 printf(
" completion event allocation errors: %" PRIu64
"\n",
1374 stats->compl_alloc_errs);
1376 printf(
" transfer ID allocation errors: %" PRIu64
"\n"
1377 " transfer poll errors: %" PRIu64
"\n"
1378 " transfers polled: %" PRIu64
"\n",
1379 stats->compl_alloc_errs, stats->trs_poll_errs,
1383 printf(
" packets forwarded:%s%" PRIu64
"\n"
1384 " packets dropped: %s%" PRIu64
"\n"
1385 " packets cleanup: %s%" PRIu64
"\n"
1386 " call cycles per schedule round:\n"
1387 " total: %" PRIu64
"\n"
1388 " schedule: %" PRIu64
"\n"
1389 " rounds: %" PRIu64
"\n", align2, stats->fwd_pkts, align2,
1390 stats->discards, align2, stats->pkt_cleanup, DIV_IF(stats->tot_cc,
1391 stats->sched_rounds), DIV_IF(stats->sched_cc, stats->sched_rounds),
1392 stats->sched_rounds);
1395 printf(
"\n==================\n");
1398 int main(
int argc,
char **argv)
1400 odph_helper_options_t odph_opts;
1404 int ret = EXIT_SUCCESS;
1405 parse_result_t parse_res;
1407 argc = odph_parse_options(argc, argv);
1409 if (odph_options(&odph_opts) == -1) {
1410 ODPH_ERR(
"Error while reading ODP helper options, exiting\n");
1415 init_param.
mem_model = odph_opts.mem_model;
1418 ODPH_ERR(
"ODP global init failed, exiting\n");
1423 ODPH_ERR(
"ODP local init failed, exiting\n");
1427 shm_cfg =
odp_shm_reserve(PROG_NAME
"_cfg",
sizeof(prog_config_t), ODP_CACHE_LINE_SIZE,
1431 ODPH_ERR(
"Error reserving shared memory\n");
1438 if (prog_conf == NULL) {
1439 ODPH_ERR(
"Error resolving shared memory address\n");
1444 parse_res = setup_program(argc, argv, prog_conf);
1446 if (parse_res == PRS_NOK) {
1451 if (parse_res == PRS_TERM) {
1456 if (parse_res == PRS_NOT_SUP) {
1462 ODPH_ERR(
"Error configuring scheduler\n");
1470 if (!setup_test(prog_conf)) {
1475 if (prog_conf->time_sec > 0.001) {
1478 ts.tv_sec = prog_conf->time_sec;
1480 nanosleep(&ts, NULL);
1487 stop_test(prog_conf);
1488 print_stats(prog_conf);
1491 teardown(prog_conf);
1498 ODPH_ERR(
"ODP local terminate failed, exiting\n");
1503 ODPH_ERR(
"ODP global terminate failed, exiting\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.
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_buffer_t odp_buffer_alloc(odp_pool_t pool)
Buffer alloc.
void odp_buffer_free(odp_buffer_t buf)
Buffer free.
void * odp_buffer_addr(odp_buffer_t buf)
Buffer start address.
_odp_abi_buffer_t * odp_buffer_t
ODP buffer.
#define ODP_BUFFER_INVALID
Invalid buffer.
#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.
uint64_t odp_cpu_cycles_diff(uint64_t c2, uint64_t c1)
CPU cycle count difference.
uint64_t odp_cpu_cycles(void)
Current CPU cycle count.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
odp_dma_t odp_dma_create(const char *name, const odp_dma_param_t *param)
Create DMA session.
odp_pool_t odp_dma_pool_create(const char *name, const odp_dma_pool_param_t *pool_param)
Create DMA completion event pool.
int odp_dma_transfer_done(odp_dma_t dma, odp_dma_transfer_id_t transfer_id, odp_dma_result_t *result)
Check if DMA transfer has completed.
#define ODP_DMA_TYPE_COPY
Copy data.
void odp_dma_transfer_id_free(odp_dma_t dma, odp_dma_transfer_id_t transfer_id)
Free DMA transfer identifier.
#define ODP_DMA_COMPL_EVENT
Asynchronous transfer with completion event.
void odp_dma_transfer_param_init(odp_dma_transfer_param_t *trs_param)
Initialize DMA transfer parameters.
int odp_dma_destroy(odp_dma_t dma)
Destroy DMA session.
int odp_dma_compl_result(odp_dma_compl_t dma_compl, odp_dma_result_t *result)
Check DMA completion event.
void odp_dma_compl_param_init(odp_dma_compl_param_t *compl_param)
Initialize DMA transfer completion parameters.
#define ODP_DMA_TRANSFER_ID_INVALID
Invalid DMA transfer identifier.
#define ODP_DMA_COMPL_INVALID
Invalid DMA completion event.
odp_event_t odp_dma_compl_to_event(odp_dma_compl_t dma_compl)
Convert DMA completion event to event.
void odp_dma_pool_param_init(odp_dma_pool_param_t *pool_param)
Initialize DMA completion event pool parameters.
int odp_dma_transfer_start(odp_dma_t dma, const odp_dma_transfer_param_t *trs_param, const odp_dma_compl_param_t *compl_param)
Start DMA transfer.
uint64_t odp_dma_transfer_id_t
DMA transfer identifier.
odp_dma_compl_t odp_dma_compl_from_event(odp_event_t ev)
Convert event to DMA completion event.
#define ODP_DMA_MAIN_TO_MAIN
DMA transfer within the main memory.
int odp_dma_capability(odp_dma_capability_t *capa)
Query DMA capabilities.
odp_dma_transfer_id_t odp_dma_transfer_id_alloc(odp_dma_t dma)
Allocate DMA transfer identifier.
void odp_dma_compl_free(odp_dma_compl_t dma_compl)
Free DMA completion event.
#define ODP_DMA_INVALID
Invalid DMA session.
#define ODP_DMA_COMPL_POLL
Asynchronous transfer with completion polling.
odp_dma_compl_t odp_dma_compl_alloc(odp_pool_t pool)
Allocate DMA completion event.
@ ODP_DMA_MT_SERIAL
Application serializes operations.
@ ODP_DMA_FORMAT_PACKET
Data format is odp_packet_t.
@ ODP_DMA_ORDER_NONE
No specific ordering between transfers.
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
odp_event_type_t
Event type.
#define ODP_EVENT_INVALID
Invalid event.
int odp_instance(odp_instance_t *instance)
Get instance handle.
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.
void odp_pktin_queue_param_init(odp_pktin_queue_param_t *param)
Initialize packet input queue parameters.
void odp_pktio_param_init(odp_pktio_param_t *param)
Initialize pktio params.
int odp_pktio_close(odp_pktio_t pktio)
Close a packet IO interface.
int odp_pktout_queue(odp_pktio_t pktio, odp_pktout_queue_t queues[], int num)
Direct packet output queues.
odp_pktio_t odp_pktio_open(const char *name, odp_pool_t pool, const odp_pktio_param_t *param)
Open a packet IO interface.
int odp_pktio_start(odp_pktio_t pktio)
Start packet receive and transmit.
#define ODP_PKTIO_INVALID
Invalid packet IO handle.
void odp_pktout_queue_param_init(odp_pktout_queue_param_t *param)
Initialize packet output queue parameters.
int odp_pktio_stop(odp_pktio_t pktio)
Stop packet receive and transmit.
int odp_pktio_index(odp_pktio_t pktio)
Get pktio interface index.
int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa)
Query packet IO interface capabilities.
#define ODP_PKTIO_MAX_INDEX
Maximum packet IO interface index.
int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num)
Send packets directly to an interface output queue.
int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param)
Configure packet input queues.
int odp_pktout_queue_config(odp_pktio_t pktio, const odp_pktout_queue_param_t *param)
Configure packet output queues.
@ ODP_PKTOUT_MODE_DIRECT
Direct packet output on the interface.
@ ODP_PKTIO_OP_MT_UNSAFE
Not multithread safe operation.
@ ODP_PKTIN_MODE_SCHED
Packet input through scheduler and scheduled event queues.
int odp_packet_input_index(odp_packet_t pkt)
Packet input interface index.
odp_packet_t odp_packet_copy(odp_packet_t pkt, odp_pool_t pool)
Full copy of a packet.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
odp_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
void odp_packet_free(odp_packet_t pkt)
Free packet.
#define ODP_PACKET_INVALID
Invalid packet.
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
Free multiple packets.
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.
@ ODP_POOL_PACKET
Packet 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.
int odp_schedule_multi_no_wait(odp_queue_t *from, odp_event_t events[], int num)
Schedule, do not wait for events.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_max_prio(void)
Maximum 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.
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.
odp_stash_type_t
Stash types.
#define ODP_STASH_INVALID
Invalid stash handle.
int32_t odp_stash_put(odp_stash_t stash, const void *obj, int32_t num)
Put object handles into a stash.
void odp_stash_param_init(odp_stash_param_t *param)
Initialize stash params.
int32_t odp_stash_get(odp_stash_t stash, void *obj, int32_t num)
Get object handles from a stash.
int odp_stash_destroy(odp_stash_t stash)
Destroy a stash.
int odp_stash_capability(odp_stash_capability_t *capa, odp_stash_type_t type)
Query stash capabilities.
odp_stash_t odp_stash_create(const char *name, const odp_stash_param_t *param)
Create a stash.
@ ODP_STASH_TYPE_DEFAULT
The default stash type.
@ ODP_STASH_TYPE_FIFO
Stash type FIFO.
@ ODP_STASH_OP_LOCAL
Thread local operation.
bool odp_bool_t
Boolean type.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint32_t max_sessions
Maximum number of DMA sessions.
uint32_t max_transfers
Maximum number of transfers per DMA session.
odp_dma_pool_capability_t pool
DMA completion event pool capabilities.
uint32_t max_dst_segs
Maximum number of destination segments in a single transfer.
uint32_t max_src_segs
Maximum number of source segments in a single transfer.
odp_bool_t queue_type_sched
Scheduled queue support.
odp_dma_compl_mode_t compl_mode_mask
Supported completion modes.
uint32_t max_seg_len
Maximum segment length in bytes.
odp_bool_t src_seg_free
Source segment free support for data format ODP_DMA_FORMAT_PACKET.
DMA transfer completion parameters.
odp_dma_transfer_id_t transfer_id
Transfer identifier.
void * user_ptr
User context pointer.
odp_event_t event
Completion event.
odp_dma_compl_mode_t compl_mode
Completion mode.
odp_queue_t queue
Completion queue.
odp_dma_direction_t direction
Transfer direction.
uint32_t min_cache_size
Minimum size of thread local cache.
uint32_t max_cache_size
Maximum size of thread local cache.
uint32_t max_pools
Maximum number of DMA completion event pools.
uint32_t max_num
Maximum number of DMA completion events in a pool.
DMA completion event pool parameters.
uint32_t cache_size
Maximum number of events cached locally per thread.
uint32_t num
Number of DMA completion events in the pool.
void * user_ptr
User context pointer.
odp_bool_t success
DMA transfer success.
odp_packet_t packet
Packet handle.
uint32_t len
Segment length in bytes.
struct odp_dma_transfer_param_t::@38::@40 opts
Option bit fields.
odp_dma_seg_t * dst_seg
Table of destination segments.
odp_dma_data_format_t dst_format
Destination data format.
uint32_t num_dst
Number of destination segments.
uint32_t num_src
Number of source segments.
odp_dma_seg_t * src_seg
Table of source segments.
odp_dma_data_format_t src_format
Source data format.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
Packet input queue parameters.
uint32_t num_queues
Number of input queues to be created.
odp_queue_param_t queue_param
Queue parameters.
odp_pktin_hash_proto_t hash_proto
Protocol field selection for hashing.
odp_bool_t hash_enable
Enable flow hashing.
uint32_t max_input_queues
Maximum number of input queues.
uint32_t max_output_queues
Maximum number of output queues.
odp_pktin_mode_t in_mode
Packet input mode.
odp_pktout_mode_t out_mode
Packet output mode.
Packet output queue parameters.
odp_pktio_op_mode_t op_mode
Operation mode.
uint32_t num_queues
Number of output queues to be created.
struct odp_pool_capability_t::@133 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t min_cache_size
Minimum size of thread local cache.
struct odp_pool_capability_t::@132 buf
Buffer pool capabilities
uint32_t max_cache_size
Maximum size of thread local cache.
uint32_t max_len
Maximum packet data length in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@137 buf
Parameters for buffer pools.
uint32_t cache_size
Maximum number of buffers cached locally per thread.
struct odp_pool_param_t::@138 pkt
Parameters for packet pools.
uint32_t size
Minimum buffer size in bytes.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
Stash capabilities (per stash type)
uint64_t u16
Maximum number of 2 byte object handles.
struct odp_stash_capability_t::@169 max_num
Maximum number of object handles per stash for each object size.
uint64_t u128
Maximum number of 16 byte object handles.
uint32_t max_stashes
Maximum number of stashes of this type.
uint64_t u64
Maximum number of 8 byte object handles.
uint32_t max_cache_size
Maximum size of thread local cache.
uint64_t u32
Maximum number of 4 byte object handles.
uint64_t u8
Maximum number of 1 byte object handles.
uint32_t cache_size
Maximum number of object handles cached locally per thread.
odp_stash_op_mode_t get_mode
Get operation mode.
uint32_t obj_size
Object handle size in bytes.
odp_stash_type_t type
Stash type.
odp_stash_op_mode_t put_mode
Put operation mode.
uint64_t num_obj
Number of object handles.
128-bit unsigned integer structure
struct odp_pktin_hash_proto_t::@106 proto
Protocol header fields for hashing.
uint32_t ipv4
IPv4 addresses.