diff options
author | Petri Savolainen <petri.savolainen@nokia.com> | 2022-11-01 11:47:09 +0200 |
---|---|---|
committer | Petri Savolainen <petri.savolainen@nokia.com> | 2022-11-04 14:34:08 +0200 |
commit | f5f469e6eb0662da11cee233e03be95df61d4b2b (patch) | |
tree | efa982ba4c7d016ea856145a60d3442ed49d6dc3 /test | |
parent | 85c52a65afa1cc1d582507e353cdfc900d8e44a3 (diff) |
test: packet_gen: add direct pktin mode option
Added -D option to select between scheduled and direct packet
input modes.
Signed-off-by: Petri Savolainen <petri.savolainen@nokia.com>
Reviewed-and-tested-by: Matias Elo <matias.elo@nokia.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/performance/odp_packet_gen.c | 155 |
1 files changed, 127 insertions, 28 deletions
diff --git a/test/performance/odp_packet_gen.c b/test/performance/odp_packet_gen.c index caa80839a..e02ffe95e 100644 --- a/test/performance/odp_packet_gen.c +++ b/test/performance/odp_packet_gen.c @@ -52,6 +52,7 @@ typedef struct test_options_t { uint32_t num_pkt; uint32_t pkt_len; uint8_t use_rand_pkt_len; + uint8_t direct_rx; uint32_t rand_pkt_len_min; uint32_t rand_pkt_len_max; uint32_t rand_pkt_len_bins; @@ -95,6 +96,9 @@ typedef struct thread_arg_t { /* pktout queue per pktio interface (per thread) */ odp_pktout_queue_t pktout[MAX_PKTIOS]; + /* In direct_rx mode, pktin queue per pktio interface (per thread) */ + odp_pktin_queue_t pktin[MAX_PKTIOS]; + } thread_arg_t; typedef struct ODP_ALIGNED_CACHE thread_stat_t { @@ -138,6 +142,7 @@ typedef struct test_global_t { odph_ethaddr_t eth_dst; odp_pktio_t pktio; odp_pktout_queue_t pktout[ODP_THREAD_COUNT_MAX]; + odp_pktin_queue_t pktin[ODP_THREAD_COUNT_MAX]; int started; } pktio[MAX_PKTIOS]; @@ -195,7 +200,10 @@ static void print_usage(void) " into the number of bins (bins >= 2). Bin value of 0 means\n" " that each packet length is used. Comma-separated (no spaces).\n" " Overrides standard packet length option.\n" - " -R, --no_pkt_refs Do not use packet references. Always allocate a\n" + " -D, --direct_rx Direct input mode (default: 0)\n" + " 0: Use scheduler for packet input\n" + " 1: Poll packet input in direct mode\n"); + printf(" -R, --no_pkt_refs Do not use packet references. Always allocate a\n" " fresh set of packets for a transmit burst. Some\n" " features may be available only with references\n" " disabled.\n" @@ -291,6 +299,7 @@ static int parse_options(int argc, char *argv[], test_global_t *global) {"num_pkt", required_argument, NULL, 'n'}, {"len", required_argument, NULL, 'l'}, {"len_range", required_argument, NULL, 'L'}, + {"direct_rx", required_argument, NULL, 'D'}, {"no_pkt_refs", no_argument, NULL, 'R'}, {"burst_size", required_argument, NULL, 'b'}, {"bursts", required_argument, NULL, 'x'}, @@ -314,7 +323,7 @@ static int parse_options(int argc, char *argv[], test_global_t *global) {NULL, 0, NULL, 0} }; - static const char *shortopts = "+i:e:r:t:n:l:L:RM:b:x:g:v:s:d:o:p:c:CAq:u:w:W:Pah"; + static const char *shortopts = "+i:e:r:t:n:l:L:D:RM:b:x:g:v:s:d:o:p:c:CAq:u:w:W:Pah"; test_options->num_pktio = 0; test_options->num_rx = 1; @@ -322,6 +331,7 @@ static int parse_options(int argc, char *argv[], test_global_t *global) test_options->num_pkt = 1000; test_options->pkt_len = 512; test_options->use_rand_pkt_len = 0; + test_options->direct_rx = 0; test_options->use_refs = 1; test_options->burst_size = 8; test_options->bursts = 1; @@ -469,6 +479,9 @@ static int parse_options(int argc, char *argv[], test_global_t *global) test_options->rand_pkt_len_bins = val; test_options->use_rand_pkt_len = 1; break; + case 'D': + test_options->direct_rx = atoi(optarg); + break; case 'R': test_options->use_refs = 0; break; @@ -694,18 +707,19 @@ static int open_pktios(test_global_t *global) uint32_t i, seg_len; int j, pktio_idx; test_options_t *test_options = &global->test_options; - uint32_t num_rx = test_options->num_rx; + int num_rx = test_options->num_rx; int num_tx = test_options->num_tx; uint32_t num_pktio = test_options->num_pktio; uint32_t num_pkt = test_options->num_pkt; uint32_t pkt_len = test_options->use_rand_pkt_len ? test_options->rand_pkt_len_max : test_options->pkt_len; odp_pktout_queue_t pktout[num_tx]; + odp_pktin_queue_t pktin[num_rx]; printf("\nODP packet generator\n"); printf(" quit test after %" PRIu64 " rounds\n", test_options->quit); - printf(" num rx threads %u\n", num_rx); + printf(" num rx threads %i\n", num_rx); printf(" num tx threads %i\n", num_tx); printf(" num packets %u\n", num_pkt); if (test_options->use_rand_pkt_len) @@ -720,6 +734,7 @@ static int open_pktios(test_global_t *global) printf("%u bytes\n", test_options->mtu); else printf("interface default\n"); + printf(" packet input mode: %s\n", test_options->direct_rx ? "direct" : "scheduler"); printf(" promisc mode: %s\n", test_options->promisc_mode ? "enabled" : "disabled"); printf(" packet references: %s\n", test_options->use_refs ? "enabled" : "disabled"); printf(" measure latency: %s\n", test_options->calc_latency ? "enabled" : "disabled"); @@ -807,7 +822,12 @@ static int open_pktios(test_global_t *global) ODPH_ERR("Warning: max pktio index (%u) is too large\n", odp_pktio_max_index()); odp_pktio_param_init(&pktio_param); - pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; + + if (test_options->direct_rx) + pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT; + else + pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; + pktio_param.out_mode = ODP_PKTOUT_MODE_DIRECT; for (i = 0; i < num_pktio; i++) @@ -839,7 +859,7 @@ static int open_pktios(test_global_t *global) return -1; } - if (num_rx > pktio_capa.max_input_queues) { + if (num_rx > (int)pktio_capa.max_input_queues) { ODPH_ERR("Error (%s): Too many RX threads. Interface supports max %u input queues.\n", name, pktio_capa.max_input_queues); return -1; @@ -912,13 +932,21 @@ static int open_pktios(test_global_t *global) odp_pktin_queue_param_init(&pktin_param); - pktin_param.queue_param.sched.prio = odp_schedule_default_prio(); - pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_PARALLEL; - pktin_param.queue_param.sched.group = ODP_SCHED_GROUP_ALL; - pktin_param.hash_enable = 1; - pktin_param.hash_proto.proto.ipv4_udp = 1; + if (test_options->direct_rx) { + pktin_param.op_mode = ODP_PKTIO_OP_MT_UNSAFE; + } else { + pktin_param.queue_param.sched.prio = odp_schedule_default_prio(); + pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_PARALLEL; + pktin_param.queue_param.sched.group = ODP_SCHED_GROUP_ALL; + } + pktin_param.num_queues = num_rx; + if (num_rx > 1) { + pktin_param.hash_enable = 1; + pktin_param.hash_proto.proto.ipv4_udp = 1; + } + if (odp_pktin_queue_config(pktio, &pktin_param)) { ODPH_ERR("Error (%s): Pktin config failed.\n", name); return -1; @@ -940,6 +968,16 @@ static int open_pktios(test_global_t *global) for (j = 0; j < num_tx; j++) global->pktio[i].pktout[j] = pktout[j]; + + if (test_options->direct_rx) { + if (odp_pktin_queue(pktio, pktin, num_rx) != num_rx) { + ODPH_ERR("Error (%s): Pktin queue request failed.\n", name); + return -1; + } + + for (j = 0; j < num_rx; j++) + global->pktio[i].pktin[j] = pktin[j]; + } } return 0; @@ -1098,9 +1136,9 @@ static int rx_thread(void *arg) uint32_t exit_test; uint64_t bytes; odp_time_t t1, t2, exit_time; - odp_packet_t pkt; thread_arg_t *thread_arg = arg; test_global_t *global = thread_arg->global; + int direct_rx = global->test_options.direct_rx; int periodic_stat = global->test_options.update_msec ? 1 : 0; uint64_t rx_timeouts = 0; uint64_t rx_packets = 0; @@ -1110,21 +1148,52 @@ static int rx_thread(void *arg) int clock_started = 0; int exit_timer_started = 0; int paused = 0; - int max_num = 32; - odp_event_t ev[max_num]; + const int max_num = 32; + int pktin = 0; + int num_pktio = global->test_options.num_pktio; + odp_pktin_queue_t pktin_queue[num_pktio]; + odp_packet_t pkt[max_num]; uint32_t ts_off = global->test_options.calc_latency ? global->test_options.hdr_len : 0; - uint64_t rx_ts; + uint64_t rx_ts = 0; rx_lat_data_t rx_lat_data = { .nsec = 0, .min = UINT64_MAX, .max = 0, .packets = 0 }; thr = odp_thread_id(); global->stat[thr].thread_type = RX_THREAD; + if (direct_rx) { + for (i = 0; i < num_pktio; i++) + pktin_queue[i] = thread_arg->pktin[i]; + } + /* Start all workers at the same time */ odp_barrier_wait(&global->barrier); while (1) { - num = odp_schedule_multi_no_wait(NULL, ev, max_num); - rx_ts = odp_time_global_ns(); + if (direct_rx) { + num = odp_pktin_recv(pktin_queue[pktin], pkt, max_num); + + if (odp_unlikely(num < 0)) { + ODPH_ERR("pktin (%i) recv failed: %i\n", pktin, num); + ret = -1; + num = 0; + break; + } + + pktin++; + if (pktin >= num_pktio) + pktin = 0; + } else { + odp_event_t ev[max_num]; + + num = odp_schedule_multi_no_wait(NULL, ev, max_num); + + if (num) + odp_packet_from_event_multi(pkt, ev, num); + } + + if (ts_off && num) + rx_ts = odp_time_global_ns(); + exit_test = odp_atomic_load_u32(&global->exit_test); if (exit_test) { /* Wait 1 second for possible in flight packets sent by the tx threads */ @@ -1134,11 +1203,11 @@ static int rx_thread(void *arg) exit_timer_started = 1; } else if (odp_time_diff_ns(odp_time_local(), exit_time) > ODP_TIME_SEC_IN_NS) { - if (paused == 0) { + if (direct_rx == 0 && paused == 0) { odp_schedule_pause(); paused = 1; } else if (num == 0) { - /* Exit schedule loop after schedule paused and no more + /* Exit main loop after (schedule paused and) no more * packets received */ break; } @@ -1152,7 +1221,9 @@ static int rx_thread(void *arg) } if (num == 0) { - rx_timeouts++; + if (direct_rx == 0) + rx_timeouts++; + continue; } @@ -1163,11 +1234,10 @@ static int rx_thread(void *arg) bytes = 0; for (i = 0; i < num; i++) { - pkt = odp_packet_from_event(ev[i]); - bytes += odp_packet_len(pkt); + bytes += odp_packet_len(pkt[i]); if (ts_off) - get_timestamp(pkt, ts_off, &rx_lat_data, rx_ts); + get_timestamp(pkt[i], ts_off, &rx_lat_data, rx_ts); } rx_packets += num; @@ -1175,7 +1245,7 @@ static int rx_thread(void *arg) if (odp_unlikely(periodic_stat)) { /* All packets from the same queue are from the same pktio interface */ - int index = odp_packet_input_index(odp_packet_from_event(ev[0])); + int index = odp_packet_input_index(pkt[0]); if (index >= 0) { int if_idx = global->if_from_pktio_idx[index]; @@ -1184,7 +1254,7 @@ static int rx_thread(void *arg) } } - odp_event_free_multi(ev, num); + odp_packet_free_multi(pkt, num); } if (clock_started) @@ -1203,7 +1273,7 @@ static int rx_thread(void *arg) return ret; } -static void drain_queues(test_global_t *global) +static void drain_scheduler(test_global_t *global) { odp_event_t ev; uint64_t wait_time = odp_schedule_wait_time(100 * ODP_TIME_MSEC_IN_NS); @@ -1214,6 +1284,26 @@ static void drain_queues(test_global_t *global) } } +static void drain_direct_input(test_global_t *global) +{ + odp_pktin_queue_t pktin; + odp_packet_t pkt; + int i, j; + int num_pktio = global->test_options.num_pktio; + int num_rx = global->test_options.num_rx; + + for (i = 0; i < num_pktio; i++) { + for (j = 0; j < num_rx; j++) { + pktin = global->pktio[i].pktin[j]; + + while (odp_pktin_recv(pktin, &pkt, 1) == 1) { + global->drained++; + odp_packet_free(pkt); + } + } + } +} + static int init_packets(test_global_t *global, int pktio, odp_packet_t packet[], uint32_t num, uint16_t seq) { @@ -1681,6 +1771,10 @@ static int start_workers(test_global_t *global, odp_instance_t instance) /* Receive threads */ for (i = 0; i < num_rx; i++) { + /* In direct mode, dedicate a pktin queue per pktio interface (per RX thread) */ + for (j = 0; test_options->direct_rx && j < num_pktio; j++) + global->thread_arg[i].pktin[j] = global->pktio[j].pktin[i]; + odph_thread_param_init(&thr_param[i]); thr_param[i].start = rx_thread; thr_param[i].arg = &global->thread_arg[i]; @@ -2029,7 +2123,9 @@ int main(int argc, char **argv) odp_sys_info_print(); - odp_schedule_config(NULL); + /* Avoid all scheduler API calls in direct input mode */ + if (global->test_options.direct_rx == 0) + odp_schedule_config(NULL); if (set_num_cpu(global)) { ret = 1; @@ -2063,7 +2159,10 @@ int main(int argc, char **argv) if (stop_pktios(global)) ret = 1; - drain_queues(global); + if (global->test_options.direct_rx) + drain_direct_input(global); + else + drain_scheduler(global); if (close_pktios(global)) ret = 1; |