This patch support measure RX burst cycles. It stops only when all the injected packets are received. It won't repeat re-send recevied packets. Now it measures two situations, poll before/after xmit(w or w/o desc. cache conflict)
Usage Example: 1. Run unit test app in interactive mode app/test -c f -n 4 -- -i 2. Set stream control mode, by default is continuous set_rxtx_sc [continuous|poll_before_xmit|poll_after_xmit] 3. Run and wait for the result pmd_perf_autotest Signed-off-by: Cunming Liang <cunming.liang at intel.com> Acked-by: Bruce Richardson <bruce.richardson at intel.com> --- app/test/commands.c | 43 +++++++++- app/test/test.h | 1 + app/test/test_pmd_perf.c | 212 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 235 insertions(+), 21 deletions(-) diff --git a/app/test/commands.c b/app/test/commands.c index 7c5d812..92a17ed 100644 --- a/app/test/commands.c +++ b/app/test/commands.c @@ -310,8 +310,6 @@ cmdline_parse_inst_t cmd_quit = { /****************/ -/****************/ - struct cmd_set_rxtx_result { cmdline_fixed_string_t set; cmdline_fixed_string_t mode; @@ -346,8 +344,6 @@ cmdline_parse_inst_t cmd_set_rxtx = { /****************/ -/****************/ - struct cmd_set_rxtx_anchor { cmdline_fixed_string_t set; cmdline_fixed_string_t type; @@ -384,6 +380,44 @@ cmdline_parse_inst_t cmd_set_rxtx_anchor = { /****************/ +/* for stream control */ +struct cmd_set_rxtx_sc { + cmdline_fixed_string_t set; + cmdline_fixed_string_t type; +}; + +static void +cmd_set_rxtx_sc_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_set_rxtx_sc *res = parsed_result; + if (test_set_rxtx_sc(res->type) < 0) + cmdline_printf(cl, "Cannot find such stream control\n"); +} + +cmdline_parse_token_string_t cmd_set_rxtx_sc_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, set, + "set_rxtx_sc"); + +cmdline_parse_token_string_t cmd_set_rxtx_sc_type = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, type, NULL); + +cmdline_parse_inst_t cmd_set_rxtx_sc = { + .f = cmd_set_rxtx_sc_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "set rxtx stream control: " + "set_rxtx_sc <type>", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_set_rxtx_sc_set, + (void *)&cmd_set_rxtx_sc_type, + NULL, + }, +}; + +/****************/ + + cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_autotest, (cmdline_parse_inst_t *)&cmd_dump, @@ -392,6 +426,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_quit, (cmdline_parse_inst_t *)&cmd_set_rxtx, (cmdline_parse_inst_t *)&cmd_set_rxtx_anchor, + (cmdline_parse_inst_t *)&cmd_set_rxtx_sc, NULL, }; diff --git a/app/test/test.h b/app/test/test.h index 68ae4bf..bd44a7f 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -142,6 +142,7 @@ int test_mp_secondary(void); int test_ivshmem(void); int test_set_rxtx_conf(cmdline_fixed_string_t mode); int test_set_rxtx_anchor(cmdline_fixed_string_t type); +int test_set_rxtx_sc(cmdline_fixed_string_t type); typedef int (test_callback)(void); TAILQ_HEAD(test_commands_list, test_command); diff --git a/app/test/test_pmd_perf.c b/app/test/test_pmd_perf.c index a6d6ea7..f3da599 100644 --- a/app/test/test_pmd_perf.c +++ b/app/test/test_pmd_perf.c @@ -39,6 +39,8 @@ #include <rte_cycles.h> #include <rte_ethdev.h> #include <rte_byteorder.h> +#include <rte_atomic.h> +#include <rte_malloc.h> #include "packet_burst_generator.h" #include "test.h" @@ -73,13 +75,15 @@ #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ +#define MAX_TRAFFIC_BURST 2048 #define NB_MBUF RTE_MAX( \ - (unsigned)(nb_ports*nb_rx_queue*RTE_TEST_RX_DESC_DEFAULT + \ - nb_ports*nb_lcores*MAX_PKT_BURST + \ - nb_ports*nb_tx_queue*RTE_TEST_TX_DESC_DEFAULT + \ - nb_lcores*MEMPOOL_CACHE_SIZE), \ - (unsigned)8192) + (unsigned)(nb_ports*nb_rx_queue*nb_rxd + \ + nb_ports*nb_lcores*MAX_PKT_BURST + \ + nb_ports*nb_tx_queue*nb_txd + \ + nb_lcores*MEMPOOL_CACHE_SIZE + \ + nb_ports*MAX_TRAFFIC_BURST), \ + (unsigned)8192) static struct rte_mempool *mbufpool[NB_SOCKETS]; @@ -147,6 +151,14 @@ struct lcore_conf lcore_conf[RTE_MAX_LCORE]; static uint64_t link_mbps; +enum { + SC_CONTINUOUS = 0, + SC_BURST_POLL_FIRST, + SC_BURST_XMIT_FIRST, +}; + +static uint32_t sc_flag; + /* Check the link status of all ports in up to 3s, and print them finally */ static void check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) @@ -361,8 +373,7 @@ signal_handler(int signum) stats_display(0); } -#define MAX_TRAFIC_BURST (4096) -struct rte_mbuf *tx_burst[MAX_TRAFIC_BURST]; +struct rte_mbuf **tx_burst; uint64_t (*do_measure)(struct lcore_conf *conf, struct rte_mbuf *pkts_burst[], @@ -503,7 +514,7 @@ main_loop(__rte_unused void *args) if (conf->status != LCORE_USED) return 0; - pkt_per_port = MAX_TRAFIC_BURST / conf->nb_ports; + pkt_per_port = MAX_TRAFFIC_BURST; int idx = 0; for (i = 0; i < conf->nb_ports; i++) { @@ -554,12 +565,135 @@ main_loop(__rte_unused void *args) return 0; } +rte_atomic64_t start; + +static inline int +poll_burst(void *args) +{ +#define MAX_IDLE (1000) + unsigned lcore_id; + struct rte_mbuf **pkts_burst; + uint64_t diff_tsc, cur_tsc; + uint16_t next[RTE_MAX_ETHPORTS]; + struct lcore_conf *conf; + uint32_t pkt_per_port = *((uint32_t *)args); + unsigned i, portid, nb_rx = 0; + uint64_t total; + uint64_t timeout = MAX_IDLE; + + lcore_id = rte_lcore_id(); + conf = &lcore_conf[lcore_id]; + if (conf->status != LCORE_USED) + return 0; + + total = pkt_per_port * conf->nb_ports; + printf("start to receive total expect %ld\n", total); + + pkts_burst = (struct rte_mbuf **) + rte_calloc_socket("poll_burst", + total, sizeof(void *), + CACHE_LINE_SIZE, conf->socketid); + if (!pkts_burst) + return -1; + + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + next[portid] = i * pkt_per_port; + } + + while (!rte_atomic64_read(&start)) + ; + + cur_tsc = rte_rdtsc(); + while (total) { + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + &pkts_burst[next[portid]], + MAX_PKT_BURST); + if (unlikely(nb_rx == 0)) { + timeout--; + if (unlikely(timeout == 0)) + goto timeout; + continue; + } + next[portid] += nb_rx; + total -= nb_rx; + } + } +timeout: + diff_tsc = rte_rdtsc() - cur_tsc; + + printf("%ld packets lost, IDLE %ld times\n", total, MAX_IDLE - timeout); + + /* clean up */ + total = pkt_per_port * conf->nb_ports - total; + for (i = 0; i < total; i++) + rte_pktmbuf_free(pkts_burst[i]); + + rte_free(pkts_burst); + + return diff_tsc / total; +} + +static int +exec_burst(uint32_t flags, int lcore) +{ + unsigned i, portid, nb_tx = 0; + struct lcore_conf *conf; + uint32_t pkt_per_port; + int num, idx = 0; + int diff_tsc; + + conf = &lcore_conf[lcore]; + + pkt_per_port = MAX_TRAFFIC_BURST; + num = pkt_per_port; + + rte_atomic64_init(&start); + + /* start polling thread, but not actually poll yet */ + rte_eal_remote_launch(poll_burst, + (void *)&pkt_per_port, lcore); + + /* Only when polling first */ + if (flags == SC_BURST_POLL_FIRST) + rte_atomic64_set(&start, 1); + + /* start xmit */ + while (num) { + nb_tx = RTE_MIN(MAX_PKT_BURST, num); + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + rte_eth_tx_burst(portid, 0, + &tx_burst[idx], nb_tx); + idx += nb_tx; + } + num -= nb_tx; + } + + sleep(5); + + /* only when polling second */ + if (flags == SC_BURST_XMIT_FIRST) + rte_atomic64_set(&start, 1); + + /* wait for polling finished */ + diff_tsc = rte_eal_wait_lcore(lcore); + if (diff_tsc < 0) + return -1; + + printf("Result: %d cycles per packet\n", diff_tsc); + + return 0; +} + static int test_pmd_perf(void) { uint16_t nb_ports, num, nb_lcores, slave_id = (uint16_t)-1; - uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; - uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; + uint16_t nb_rxd = MAX_TRAFFIC_BURST; + uint16_t nb_txd = MAX_TRAFFIC_BURST; uint16_t portid; uint16_t nb_rx_queue = 1, nb_tx_queue = 1; int socketid = -1; @@ -587,6 +721,12 @@ test_pmd_perf(void) init_mbufpool(NB_MBUF); + if (sc_flag == SC_CONTINUOUS) { + nb_rxd = RTE_TEST_RX_DESC_DEFAULT; + nb_txd = RTE_TEST_TX_DESC_DEFAULT; + } + printf("CONFIG RXD=%d TXD=%d\n", nb_rxd, nb_txd); + reset_count(); num = 0; for (portid = 0; portid < nb_ports; portid++) { @@ -651,15 +791,34 @@ test_pmd_perf(void) } check_all_ports_link_status(nb_ports, RTE_PORT_ALL); - init_traffic(mbufpool[socketid], tx_burst, MAX_TRAFIC_BURST); + if (tx_burst == NULL) { + tx_burst = (struct rte_mbuf **) + rte_calloc_socket("tx_buff", + MAX_TRAFFIC_BURST * nb_ports, + sizeof(void *), + CACHE_LINE_SIZE, socketid); + if (!tx_burst) + return -1; + } - /* do both rxtx by default */ - if (NULL == do_measure) - do_measure = measure_rxtx; + init_traffic(mbufpool[socketid], + tx_burst, MAX_TRAFFIC_BURST * nb_ports); - rte_eal_remote_launch(main_loop, NULL, slave_id); - if (rte_eal_wait_lcore(slave_id) < 0) - return -1; + printf("Generate %d packets @socket %d\n", + MAX_TRAFFIC_BURST * nb_ports, socketid); + + if (sc_flag == SC_CONTINUOUS) { + /* do both rxtx by default */ + if (NULL == do_measure) + do_measure = measure_rxtx; + + rte_eal_remote_launch(main_loop, NULL, slave_id); + + if (rte_eal_wait_lcore(slave_id) < 0) + return -1; + } else if (sc_flag == SC_BURST_POLL_FIRST || + sc_flag == SC_BURST_XMIT_FIRST) + exec_burst(sc_flag, slave_id); /* port tear down */ for (portid = 0; portid < nb_ports; portid++) { @@ -736,6 +895,25 @@ test_set_rxtx_anchor(cmdline_fixed_string_t type) return -1; } +int +test_set_rxtx_sc(cmdline_fixed_string_t type) +{ + printf("stream control switch to %s\n", type); + + if (!strcmp(type, "continuous")) { + sc_flag = SC_CONTINUOUS; + return 0; + } else if (!strcmp(type, "poll_before_xmit")) { + sc_flag = SC_BURST_POLL_FIRST; + return 0; + } else if (!strcmp(type, "poll_after_xmit")) { + sc_flag = SC_BURST_XMIT_FIRST; + return 0; + } + + return -1; +} + static struct test_command pmd_perf_cmd = { .command = "pmd_perf_autotest", .callback = test_pmd_perf, -- 1.7.4.1