Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : :
6 : : #include <stdio.h>
7 : : #include <inttypes.h>
8 : : #include <signal.h>
9 : : #include <unistd.h>
10 : : #include <rte_cycles.h>
11 : : #include <rte_ethdev.h>
12 : : #include <rte_byteorder.h>
13 : : #include <rte_malloc.h>
14 : : #include "packet_burst_generator.h"
15 : : #include "test.h"
16 : :
17 : : #define NB_ETHPORTS_USED (1)
18 : : #define NB_SOCKETS (2)
19 : : #define MEMPOOL_CACHE_SIZE 250
20 : : #define MAX_PKT_BURST (32)
21 : : #define RX_DESC_DEFAULT (1024)
22 : : #define TX_DESC_DEFAULT (1024)
23 : : #define RTE_PORT_ALL (~(uint16_t)0x0)
24 : :
25 : : /* how long test would take at full line rate */
26 : : #define RTE_TEST_DURATION (2)
27 : :
28 : : /*
29 : : * RX and TX Prefetch, Host, and Write-back threshold values should be
30 : : * carefully set for optimal performance. Consult the network
31 : : * controller's datasheet and supporting DPDK documentation for guidance
32 : : * on how these parameters should be set.
33 : : */
34 : : #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */
35 : : #define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */
36 : : #define RX_WTHRESH 0 /**< Default values of RX write-back threshold reg. */
37 : :
38 : : /*
39 : : * These default values are optimized for use with the Intel(R) 82599 10 GbE
40 : : * Controller and the DPDK ixgbe PMD. Consider using other values for other
41 : : * network controllers and/or network drivers.
42 : : */
43 : : #define TX_PTHRESH 32 /**< Default values of TX prefetch threshold reg. */
44 : : #define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */
45 : : #define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */
46 : :
47 : : #define MAX_TRAFFIC_BURST 2048
48 : :
49 : : #define NB_MBUF RTE_MAX( \
50 : : (unsigned)(nb_ports*nb_rx_queue*nb_rxd + \
51 : : nb_ports*nb_lcores*MAX_PKT_BURST + \
52 : : nb_ports*nb_tx_queue*nb_txd + \
53 : : nb_lcores*MEMPOOL_CACHE_SIZE + \
54 : : nb_ports*MAX_TRAFFIC_BURST), \
55 : : (unsigned)8192)
56 : :
57 : :
58 : : static struct rte_mempool *mbufpool[NB_SOCKETS];
59 : : /* ethernet addresses of ports */
60 : : static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
61 : :
62 : : static struct rte_eth_conf port_conf = {
63 : : .rxmode = {
64 : : .mq_mode = RTE_ETH_MQ_RX_NONE,
65 : : },
66 : : .txmode = {
67 : : .mq_mode = RTE_ETH_MQ_TX_NONE,
68 : : },
69 : : .lpbk_mode = 1, /* enable loopback */
70 : : };
71 : :
72 : : static struct rte_eth_rxconf rx_conf = {
73 : : .rx_thresh = {
74 : : .pthresh = RX_PTHRESH,
75 : : .hthresh = RX_HTHRESH,
76 : : .wthresh = RX_WTHRESH,
77 : : },
78 : : .rx_free_thresh = 32,
79 : : };
80 : :
81 : : static struct rte_eth_txconf tx_conf = {
82 : : .tx_thresh = {
83 : : .pthresh = TX_PTHRESH,
84 : : .hthresh = TX_HTHRESH,
85 : : .wthresh = TX_WTHRESH,
86 : : },
87 : : .tx_free_thresh = 32, /* Use PMD default values */
88 : : .tx_rs_thresh = 32, /* Use PMD default values */
89 : : };
90 : :
91 : : enum {
92 : : LCORE_INVALID = 0,
93 : : LCORE_AVAIL,
94 : : LCORE_USED,
95 : : };
96 : :
97 : : struct __rte_cache_aligned lcore_conf {
98 : : uint8_t status;
99 : : uint8_t socketid;
100 : : uint16_t nb_ports;
101 : : uint16_t portlist[RTE_MAX_ETHPORTS];
102 : : };
103 : :
104 : : struct lcore_conf lcore_conf[RTE_MAX_LCORE];
105 : :
106 : : static uint64_t link_mbps;
107 : :
108 : : enum {
109 : : SC_CONTINUOUS = 0,
110 : : SC_BURST_POLL_FIRST,
111 : : SC_BURST_XMIT_FIRST,
112 : : };
113 : :
114 : : static uint32_t sc_flag;
115 : :
116 : : /* Check the link status of all ports in up to 3s, and print them finally */
117 : : static void
118 : 0 : check_all_ports_link_status(uint16_t port_num, uint32_t port_mask)
119 : : {
120 : : #define CHECK_INTERVAL 100 /* 100ms */
121 : : #define MAX_CHECK_TIME 30 /* 3s (30 * 100ms) in total */
122 : : uint16_t portid;
123 : : uint8_t count, all_ports_up, print_flag = 0;
124 : : struct rte_eth_link link;
125 : : int ret;
126 : : char link_status[RTE_ETH_LINK_MAX_STR_LEN];
127 : :
128 : : printf("Checking link statuses...\n");
129 : 0 : fflush(stdout);
130 [ # # ]: 0 : for (count = 0; count <= MAX_CHECK_TIME; count++) {
131 : : all_ports_up = 1;
132 [ # # ]: 0 : for (portid = 0; portid < port_num; portid++) {
133 [ # # ]: 0 : if ((port_mask & (1 << portid)) == 0)
134 : 0 : continue;
135 : : memset(&link, 0, sizeof(link));
136 : 0 : ret = rte_eth_link_get_nowait(portid, &link);
137 [ # # ]: 0 : if (ret < 0) {
138 : : all_ports_up = 0;
139 [ # # ]: 0 : if (print_flag == 1)
140 : 0 : printf("Port %u link get failed: %s\n",
141 : : portid, rte_strerror(-ret));
142 : 0 : continue;
143 : : }
144 : :
145 : : /* print link status if flag set */
146 [ # # ]: 0 : if (print_flag == 1) {
147 [ # # # # ]: 0 : if (link.link_status && link_mbps == 0)
148 : 0 : link_mbps = link.link_speed;
149 : :
150 : 0 : rte_eth_link_to_str(link_status,
151 : : sizeof(link_status), &link);
152 : : printf("Port %d %s\n", portid, link_status);
153 : 0 : continue;
154 : : }
155 : : /* clear all_ports_up flag if any link down */
156 [ # # ]: 0 : if (link.link_status == RTE_ETH_LINK_DOWN) {
157 : : all_ports_up = 0;
158 : : break;
159 : : }
160 : : }
161 : : /* after finally printing all link status, get out */
162 [ # # ]: 0 : if (print_flag == 1)
163 : : break;
164 : :
165 [ # # ]: 0 : if (all_ports_up == 0) {
166 : 0 : fflush(stdout);
167 : : rte_delay_ms(CHECK_INTERVAL);
168 : : }
169 : :
170 : : /* set the print_flag if all ports up or timeout */
171 [ # # ]: 0 : if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1))
172 : : print_flag = 1;
173 : : }
174 : 0 : }
175 : :
176 : : static void
177 : 0 : print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
178 : : {
179 : : char buf[RTE_ETHER_ADDR_FMT_SIZE];
180 : 0 : rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
181 : : printf("%s%s", name, buf);
182 : 0 : }
183 : :
184 : : static int
185 : 0 : init_traffic(struct rte_mempool *mp,
186 : : struct rte_mbuf **pkts_burst, uint32_t burst_size)
187 : : {
188 : : struct rte_ether_hdr pkt_eth_hdr;
189 : : struct rte_ipv4_hdr pkt_ipv4_hdr;
190 : : struct rte_udp_hdr pkt_udp_hdr;
191 : : uint32_t pktlen;
192 : : static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF };
193 : : static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA };
194 : :
195 : :
196 : 0 : initialize_eth_header(&pkt_eth_hdr,
197 : : (struct rte_ether_addr *)src_mac,
198 : : (struct rte_ether_addr *)dst_mac, RTE_ETHER_TYPE_IPV4, 0, 0);
199 : :
200 : 0 : pktlen = initialize_ipv4_header(&pkt_ipv4_hdr,
201 : : IPV4_ADDR(10, 0, 0, 1),
202 : : IPV4_ADDR(10, 0, 0, 2), 26);
203 : : printf("IPv4 pktlen %u\n", pktlen);
204 : :
205 : 0 : pktlen = initialize_udp_header(&pkt_udp_hdr, 0, 0, 18);
206 : :
207 : : printf("UDP pktlen %u\n", pktlen);
208 : :
209 : 0 : return generate_packet_burst(mp, pkts_burst, &pkt_eth_hdr,
210 : : 0, &pkt_ipv4_hdr, 1,
211 : : &pkt_udp_hdr, burst_size,
212 : : PACKET_BURST_GEN_PKT_LEN, 1);
213 : : }
214 : :
215 : : static int
216 : 0 : init_lcores(void)
217 : : {
218 : : unsigned lcore_id;
219 : :
220 [ # # ]: 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
221 : 0 : lcore_conf[lcore_id].socketid =
222 : 0 : rte_lcore_to_socket_id(lcore_id);
223 [ # # ]: 0 : if (rte_lcore_is_enabled(lcore_id) == 0) {
224 : 0 : lcore_conf[lcore_id].status = LCORE_INVALID;
225 : 0 : continue;
226 : : } else
227 : 0 : lcore_conf[lcore_id].status = LCORE_AVAIL;
228 : : }
229 : 0 : return 0;
230 : : }
231 : :
232 : : static int
233 : 0 : init_mbufpool(unsigned nb_mbuf)
234 : : {
235 : : int socketid;
236 : : unsigned lcore_id;
237 : : char s[64];
238 : :
239 [ # # ]: 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
240 [ # # ]: 0 : if (rte_lcore_is_enabled(lcore_id) == 0)
241 : 0 : continue;
242 : :
243 : 0 : socketid = rte_lcore_to_socket_id(lcore_id);
244 [ # # ]: 0 : if (socketid >= NB_SOCKETS) {
245 : 0 : rte_exit(EXIT_FAILURE,
246 : : "Socket %d of lcore %u is out of range %d\n",
247 : : socketid, lcore_id, NB_SOCKETS);
248 : : }
249 [ # # ]: 0 : if (mbufpool[socketid] == NULL) {
250 : : snprintf(s, sizeof(s), "mbuf_pool_%d", socketid);
251 : 0 : mbufpool[socketid] =
252 : 0 : rte_pktmbuf_pool_create(s, nb_mbuf,
253 : : MEMPOOL_CACHE_SIZE, 0,
254 : : RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
255 [ # # ]: 0 : if (mbufpool[socketid] == NULL)
256 : 0 : rte_exit(EXIT_FAILURE,
257 : : "Cannot init mbuf pool on socket %d\n",
258 : : socketid);
259 : : else
260 : : printf("Allocated mbuf pool on socket %d\n",
261 : : socketid);
262 : : }
263 : : }
264 : 0 : return 0;
265 : : }
266 : :
267 : : static uint16_t
268 : 0 : alloc_lcore(int socketid)
269 : : {
270 : : unsigned lcore_id;
271 : :
272 [ # # ]: 0 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
273 [ # # # # ]: 0 : if (LCORE_AVAIL != lcore_conf[lcore_id].status ||
274 : 0 : (socketid != SOCKET_ID_ANY &&
275 [ # # # # ]: 0 : lcore_conf[lcore_id].socketid != socketid) ||
276 : 0 : lcore_id == rte_get_main_lcore())
277 : : continue;
278 : 0 : lcore_conf[lcore_id].status = LCORE_USED;
279 : 0 : lcore_conf[lcore_id].nb_ports = 0;
280 : 0 : return lcore_id;
281 : : }
282 : :
283 : : return (uint16_t)-1;
284 : : }
285 : :
286 : : static volatile uint64_t stop;
287 : : static uint64_t count;
288 : : static uint64_t drop;
289 : : static uint64_t idle;
290 : :
291 : : static void
292 : : reset_count(void)
293 : : {
294 : 0 : count = 0;
295 : 0 : drop = 0;
296 : 0 : idle = 0;
297 : : }
298 : :
299 : : #ifndef RTE_EXEC_ENV_WINDOWS
300 : : static void
301 : 0 : stats_display(uint16_t port_id)
302 : : {
303 : : struct rte_eth_stats stats;
304 : 0 : rte_eth_stats_get(port_id, &stats);
305 : :
306 : 0 : printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: "
307 : : "%-"PRIu64"\n",
308 : : stats.ipackets, stats.imissed, stats.ibytes);
309 : 0 : printf(" RX-errors: %-10"PRIu64" RX-nombuf: %-10"PRIu64"\n",
310 : : stats.ierrors, stats.rx_nombuf);
311 : 0 : printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: "
312 : : "%-"PRIu64"\n",
313 : : stats.opackets, stats.oerrors, stats.obytes);
314 : 0 : }
315 : :
316 : : static void
317 : 0 : signal_handler(int signum)
318 : : {
319 : : /* USR1 signal, stop testing */
320 [ # # ]: 0 : if (signum == SIGUSR1) {
321 : 0 : stop = 1;
322 : : }
323 : :
324 : : /* USR2 signal, print stats */
325 [ # # ]: 0 : if (signum == SIGUSR2)
326 : 0 : stats_display(0);
327 : 0 : }
328 : : #endif
329 : :
330 : : struct rte_mbuf **tx_burst;
331 : :
332 : : uint64_t (*do_measure)(struct lcore_conf *conf,
333 : : struct rte_mbuf *pkts_burst[],
334 : : uint64_t total_pkts);
335 : :
336 : : static uint64_t
337 : 0 : measure_rxtx(struct lcore_conf *conf,
338 : : struct rte_mbuf *pkts_burst[],
339 : : uint64_t total_pkts)
340 : : {
341 : : unsigned i, portid, nb_rx, nb_tx;
342 : : uint64_t prev_tsc, cur_tsc;
343 : :
344 : : prev_tsc = rte_rdtsc();
345 : :
346 [ # # ]: 0 : while (likely(!stop)) {
347 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
348 : 0 : portid = conf->portlist[i];
349 : 0 : nb_rx = rte_eth_rx_burst(portid, 0,
350 : : pkts_burst, MAX_PKT_BURST);
351 [ # # ]: 0 : if (unlikely(nb_rx == 0)) {
352 : 0 : idle++;
353 : 0 : continue;
354 : : }
355 : :
356 : 0 : count += nb_rx;
357 : 0 : nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx);
358 [ # # ]: 0 : if (unlikely(nb_tx < nb_rx)) {
359 : 0 : drop += (nb_rx - nb_tx);
360 : : do {
361 : 0 : rte_pktmbuf_free(pkts_burst[nb_tx]);
362 [ # # ]: 0 : } while (++nb_tx < nb_rx);
363 : : }
364 : : }
365 [ # # ]: 0 : if (unlikely(count >= total_pkts))
366 : : break;
367 : : }
368 : :
369 : : cur_tsc = rte_rdtsc();
370 : :
371 : 0 : return cur_tsc - prev_tsc;
372 : : }
373 : :
374 : : static uint64_t
375 : 0 : measure_rxonly(struct lcore_conf *conf,
376 : : struct rte_mbuf *pkts_burst[],
377 : : uint64_t total_pkts)
378 : : {
379 : : unsigned i, portid, nb_rx, nb_tx;
380 : : uint64_t diff_tsc, cur_tsc;
381 : :
382 : : diff_tsc = 0;
383 [ # # ]: 0 : while (likely(!stop)) {
384 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
385 : 0 : portid = conf->portlist[i];
386 : :
387 : : cur_tsc = rte_rdtsc();
388 : 0 : nb_rx = rte_eth_rx_burst(portid, 0,
389 : : pkts_burst, MAX_PKT_BURST);
390 [ # # ]: 0 : if (unlikely(nb_rx == 0)) {
391 : 0 : idle++;
392 : 0 : continue;
393 : : }
394 : 0 : diff_tsc += rte_rdtsc() - cur_tsc;
395 : :
396 : 0 : count += nb_rx;
397 : 0 : nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx);
398 [ # # ]: 0 : if (unlikely(nb_tx < nb_rx)) {
399 : 0 : drop += (nb_rx - nb_tx);
400 : : do {
401 : 0 : rte_pktmbuf_free(pkts_burst[nb_tx]);
402 [ # # ]: 0 : } while (++nb_tx < nb_rx);
403 : : }
404 : : }
405 [ # # ]: 0 : if (unlikely(count >= total_pkts))
406 : : break;
407 : : }
408 : :
409 : 0 : return diff_tsc;
410 : : }
411 : :
412 : : static uint64_t
413 : 0 : measure_txonly(struct lcore_conf *conf,
414 : : struct rte_mbuf *pkts_burst[],
415 : : uint64_t total_pkts)
416 : : {
417 : : unsigned i, portid, nb_rx, nb_tx;
418 : : uint64_t diff_tsc, cur_tsc;
419 : :
420 : : printf("do tx measure\n");
421 : : diff_tsc = 0;
422 [ # # ]: 0 : while (likely(!stop)) {
423 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
424 : 0 : portid = conf->portlist[i];
425 : 0 : nb_rx = rte_eth_rx_burst(portid, 0,
426 : : pkts_burst, MAX_PKT_BURST);
427 [ # # ]: 0 : if (unlikely(nb_rx == 0)) {
428 : 0 : idle++;
429 : 0 : continue;
430 : : }
431 : :
432 : 0 : count += nb_rx;
433 : :
434 : : cur_tsc = rte_rdtsc();
435 : 0 : nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx);
436 [ # # ]: 0 : if (unlikely(nb_tx < nb_rx)) {
437 : 0 : drop += (nb_rx - nb_tx);
438 : : do {
439 : 0 : rte_pktmbuf_free(pkts_burst[nb_tx]);
440 [ # # ]: 0 : } while (++nb_tx < nb_rx);
441 : : }
442 : 0 : diff_tsc += rte_rdtsc() - cur_tsc;
443 : : }
444 [ # # ]: 0 : if (unlikely(count >= total_pkts))
445 : : break;
446 : : }
447 : :
448 : 0 : return diff_tsc;
449 : : }
450 : :
451 : : /* main processing loop */
452 : : static int
453 [ # # ]: 0 : main_loop(__rte_unused void *args)
454 : : {
455 : : #define PACKET_SIZE 64
456 : : #define FRAME_GAP 12
457 : : #define MAC_PREAMBLE 8
458 : : #define MAX_RETRY_COUNT 5
459 : : struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
460 : : unsigned lcore_id;
461 : : unsigned i, portid, nb_rx = 0, nb_tx = 0;
462 : : struct lcore_conf *conf;
463 : : int pkt_per_port;
464 : : uint64_t diff_tsc;
465 : : uint64_t packets_per_second, total_packets;
466 : : int retry_cnt = 0;
467 : : int free_pkt = 0;
468 : :
469 : : lcore_id = rte_lcore_id();
470 : 0 : conf = &lcore_conf[lcore_id];
471 [ # # ]: 0 : if (conf->status != LCORE_USED)
472 : : return 0;
473 : :
474 : : pkt_per_port = MAX_TRAFFIC_BURST;
475 : :
476 : : int idx = 0;
477 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
478 : : int num = pkt_per_port;
479 : 0 : portid = conf->portlist[i];
480 : : printf("inject %d packet to port %d\n", num, portid);
481 [ # # ]: 0 : while (num) {
482 : 0 : nb_tx = RTE_MIN(MAX_PKT_BURST, num);
483 : 0 : nb_tx = rte_eth_tx_burst(portid, 0,
484 : 0 : &tx_burst[idx], nb_tx);
485 [ # # ]: 0 : if (nb_tx == 0)
486 : 0 : retry_cnt++;
487 : 0 : num -= nb_tx;
488 : 0 : idx += nb_tx;
489 [ # # ]: 0 : if (retry_cnt == MAX_RETRY_COUNT) {
490 : : retry_cnt = 0;
491 : : break;
492 : : }
493 : : }
494 : : }
495 [ # # ]: 0 : for (free_pkt = idx; free_pkt < (MAX_TRAFFIC_BURST * conf->nb_ports);
496 : 0 : free_pkt++)
497 : 0 : rte_pktmbuf_free(tx_burst[free_pkt]);
498 : : printf("Total packets inject to prime ports = %u\n", idx);
499 : :
500 : 0 : packets_per_second = (link_mbps * 1000 * 1000) /
501 : : ((PACKET_SIZE + FRAME_GAP + MAC_PREAMBLE) * CHAR_BIT);
502 : : printf("Each port will do %"PRIu64" packets per second\n",
503 : : packets_per_second);
504 : :
505 : 0 : total_packets = RTE_TEST_DURATION * conf->nb_ports * packets_per_second;
506 : : printf("Test will stop after at least %"PRIu64" packets received\n",
507 : : + total_packets);
508 : :
509 : 0 : diff_tsc = do_measure(conf, pkts_burst, total_packets);
510 : :
511 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
512 : 0 : portid = conf->portlist[i];
513 : : int nb_free = 0;
514 : : uint64_t timeout = 10000;
515 : : do { /* dry out */
516 : 0 : nb_rx = rte_eth_rx_burst(portid, 0,
517 : : pkts_burst, MAX_PKT_BURST);
518 : : nb_tx = 0;
519 [ # # ]: 0 : while (nb_tx < nb_rx)
520 : 0 : rte_pktmbuf_free(pkts_burst[nb_tx++]);
521 : 0 : nb_free += nb_rx;
522 : :
523 [ # # ]: 0 : if (unlikely(nb_rx == 0))
524 : 0 : timeout--;
525 [ # # ]: 0 : } while (nb_free != pkt_per_port && timeout != 0);
526 : : printf("free %d (expected %d) mbuf left in port %u\n", nb_free,
527 : : pkt_per_port, portid);
528 : : }
529 : :
530 [ # # ]: 0 : if (count == 0)
531 : : return -1;
532 : :
533 : 0 : printf("%"PRIu64" packet, %"PRIu64" drop, %"PRIu64" idle\n",
534 : : count, drop, idle);
535 : 0 : printf("Result: %"PRIu64" cycles per packet\n", diff_tsc / count);
536 : :
537 : 0 : return 0;
538 : : }
539 : :
540 : : static RTE_ATOMIC(uint64_t) start;
541 : :
542 : : static inline int
543 : 0 : poll_burst(void *args)
544 : : {
545 : : #define MAX_IDLE (10000)
546 : : unsigned lcore_id;
547 : : struct rte_mbuf **pkts_burst;
548 : : uint64_t diff_tsc, cur_tsc;
549 : : uint16_t next[RTE_MAX_ETHPORTS];
550 : : struct lcore_conf *conf;
551 [ # # ]: 0 : uint32_t pkt_per_port = *((uint32_t *)args);
552 : : unsigned i, portid, nb_rx = 0;
553 : : uint64_t total;
554 : : uint64_t timeout = MAX_IDLE;
555 : : int num[RTE_MAX_ETHPORTS];
556 : :
557 : : lcore_id = rte_lcore_id();
558 : : conf = &lcore_conf[lcore_id];
559 [ # # ]: 0 : if (conf->status != LCORE_USED)
560 : : return 0;
561 : :
562 : 0 : total = pkt_per_port * conf->nb_ports;
563 : : printf("start to receive total expect %"PRIu64"\n", total);
564 : :
565 : : pkts_burst = (struct rte_mbuf **)
566 : 0 : rte_calloc_socket("poll_burst",
567 : : total, sizeof(void *),
568 : 0 : RTE_CACHE_LINE_SIZE, conf->socketid);
569 [ # # ]: 0 : if (!pkts_burst)
570 : : return -1;
571 : :
572 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
573 : 0 : portid = conf->portlist[i];
574 : 0 : next[portid] = i * pkt_per_port;
575 : 0 : num[portid] = pkt_per_port;
576 : : }
577 : :
578 : : rte_wait_until_equal_64((uint64_t *)(uintptr_t)&start, 1, rte_memory_order_acquire);
579 : :
580 : : cur_tsc = rte_rdtsc();
581 [ # # ]: 0 : while (total) {
582 [ # # ]: 0 : for (i = 0; i < conf->nb_ports; i++) {
583 : 0 : portid = conf->portlist[i];
584 : 0 : nb_rx = rte_eth_rx_burst(portid, 0,
585 : 0 : &pkts_burst[next[portid]],
586 : 0 : RTE_MIN(MAX_PKT_BURST, num[portid]));
587 [ # # ]: 0 : if (unlikely(nb_rx == 0)) {
588 : 0 : timeout--;
589 [ # # ]: 0 : if (unlikely(timeout == 0))
590 : 0 : goto timeout;
591 : 0 : continue;
592 : : }
593 : 0 : next[portid] += nb_rx;
594 : 0 : num[portid] -= nb_rx;
595 : 0 : total -= nb_rx;
596 : : }
597 : : }
598 : 0 : timeout:
599 : 0 : diff_tsc = rte_rdtsc() - cur_tsc;
600 : :
601 : 0 : printf("%"PRIu64" packets lost, IDLE %"PRIu64" times\n",
602 : : total, MAX_IDLE - timeout);
603 : : /* clean up */
604 : 0 : total = pkt_per_port * conf->nb_ports - total;
605 [ # # ]: 0 : for (i = 0; i < total; i++)
606 : 0 : rte_pktmbuf_free(pkts_burst[i]);
607 : :
608 : 0 : rte_free(pkts_burst);
609 : :
610 [ # # ]: 0 : if (total > 0)
611 : 0 : return diff_tsc / total;
612 : : else
613 : : return -1;
614 : : }
615 : :
616 : : static int
617 : 0 : exec_burst(uint32_t flags, int lcore)
618 : : {
619 : : unsigned int portid, nb_tx = 0;
620 : : struct lcore_conf *conf;
621 : : uint32_t pkt_per_port;
622 : : int num, i, idx = 0;
623 : : int diff_tsc;
624 : :
625 : : conf = &lcore_conf[lcore];
626 : :
627 : 0 : pkt_per_port = MAX_TRAFFIC_BURST;
628 : 0 : num = pkt_per_port * conf->nb_ports;
629 : :
630 : : /* only when polling first */
631 [ # # ]: 0 : if (flags == SC_BURST_POLL_FIRST)
632 : 0 : rte_atomic_store_explicit(&start, 1, rte_memory_order_relaxed);
633 : : else
634 : 0 : rte_atomic_store_explicit(&start, 0, rte_memory_order_relaxed);
635 : :
636 : : /* start polling thread
637 : : * if in POLL_FIRST mode, poll once launched;
638 : : * otherwise, not actually poll yet
639 : : */
640 : 0 : rte_eal_remote_launch(poll_burst,
641 : : (void *)&pkt_per_port, lcore);
642 : :
643 : : /* start xmit */
644 : : i = 0;
645 [ # # ]: 0 : while (num) {
646 : 0 : nb_tx = RTE_MIN(MAX_PKT_BURST, num);
647 : 0 : portid = conf->portlist[i];
648 : 0 : nb_tx = rte_eth_tx_burst(portid, 0, &tx_burst[idx], nb_tx);
649 : 0 : idx += nb_tx;
650 : 0 : num -= nb_tx;
651 [ # # ]: 0 : i = (i >= conf->nb_ports - 1) ? 0 : (i + 1);
652 : : }
653 : :
654 : 0 : rte_delay_us(5 * US_PER_S);
655 : :
656 : : /* only when polling second */
657 [ # # ]: 0 : if (flags == SC_BURST_XMIT_FIRST)
658 : 0 : rte_atomic_store_explicit(&start, 1, rte_memory_order_release);
659 : :
660 : : /* wait for polling finished */
661 : 0 : diff_tsc = rte_eal_wait_lcore(lcore);
662 [ # # ]: 0 : if (diff_tsc < 0) {
663 : : printf("exec_burst: Failed to measure cycles per packet\n");
664 : 0 : return -1;
665 : : }
666 : :
667 : : printf("Result: %d cycles per packet\n", diff_tsc);
668 : :
669 : 0 : return 0;
670 : : }
671 : :
672 : : static int
673 : 0 : test_pmd_perf(void)
674 : : {
675 : : uint16_t nb_ports, num, nb_lcores, worker_id = (uint16_t)-1;
676 : : uint16_t nb_rxd = MAX_TRAFFIC_BURST;
677 : : uint16_t nb_txd = MAX_TRAFFIC_BURST;
678 : : uint16_t portid;
679 : : uint16_t nb_rx_queue = 1, nb_tx_queue = 1;
680 : : int socketid = -1;
681 : : int ret;
682 : :
683 : : printf("Start PMD RXTX cycles cost test.\n");
684 : :
685 : : #ifndef RTE_EXEC_ENV_WINDOWS
686 : 0 : signal(SIGUSR1, signal_handler);
687 : 0 : signal(SIGUSR2, signal_handler);
688 : : #endif
689 : :
690 : 0 : nb_ports = rte_eth_dev_count_avail();
691 [ # # ]: 0 : if (nb_ports < NB_ETHPORTS_USED) {
692 : : printf("At least %u port(s) used for perf. test\n",
693 : : NB_ETHPORTS_USED);
694 : 0 : return -1;
695 : : }
696 : :
697 : 0 : nb_lcores = rte_lcore_count();
698 : :
699 : : memset(lcore_conf, 0, sizeof(lcore_conf));
700 : 0 : init_lcores();
701 : :
702 : 0 : init_mbufpool(NB_MBUF);
703 : :
704 [ # # ]: 0 : if (sc_flag == SC_CONTINUOUS) {
705 : : nb_rxd = RX_DESC_DEFAULT;
706 : : nb_txd = TX_DESC_DEFAULT;
707 : : }
708 : 0 : printf("CONFIG RXD=%d TXD=%d\n", nb_rxd, nb_txd);
709 : :
710 : : reset_count();
711 : : num = 0;
712 [ # # ]: 0 : RTE_ETH_FOREACH_DEV(portid) {
713 [ # # ]: 0 : if (socketid == -1) {
714 : 0 : worker_id = alloc_lcore(rte_eth_dev_socket_id(portid));
715 [ # # ]: 0 : if (worker_id == (uint16_t)-1) {
716 : : printf("No avail lcore to run test\n");
717 : 0 : return -1;
718 : : }
719 : 0 : socketid = rte_lcore_to_socket_id(worker_id);
720 : 0 : printf("Performance test runs on lcore %u socket %u\n",
721 : : worker_id, socketid);
722 : : }
723 : :
724 [ # # # # ]: 0 : if (socketid != rte_eth_dev_socket_id(portid) &&
725 : 0 : rte_eth_dev_socket_id(portid) != SOCKET_ID_ANY) {
726 : : printf("Skip port %d\n", portid);
727 : 0 : continue;
728 : : }
729 : :
730 : : /* port configure */
731 : 0 : ret = rte_eth_dev_configure(portid, nb_rx_queue,
732 : : nb_tx_queue, &port_conf);
733 [ # # ]: 0 : if (ret < 0)
734 : 0 : rte_exit(EXIT_FAILURE,
735 : : "Cannot configure device: err=%d, port=%d\n",
736 : : ret, portid);
737 : :
738 : 0 : ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]);
739 [ # # ]: 0 : if (ret < 0)
740 : 0 : rte_exit(EXIT_FAILURE,
741 : : "Cannot get mac address: err=%d, port=%d\n",
742 : : ret, portid);
743 : :
744 : : printf("Port %u ", portid);
745 : 0 : print_ethaddr("Address:", &ports_eth_addr[portid]);
746 : : printf("\n");
747 : :
748 : : /* tx queue setup */
749 : 0 : ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
750 : : socketid, &tx_conf);
751 [ # # ]: 0 : if (ret < 0)
752 : 0 : rte_exit(EXIT_FAILURE,
753 : : "rte_eth_tx_queue_setup: err=%d, "
754 : : "port=%d\n", ret, portid);
755 : :
756 : : /* rx queue steup */
757 : 0 : ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
758 : : socketid, &rx_conf,
759 : : mbufpool[socketid]);
760 [ # # ]: 0 : if (ret < 0)
761 : 0 : rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d,"
762 : : "port=%d\n", ret, portid);
763 : :
764 : : /* Start device */
765 : 0 : stop = 0;
766 : 0 : ret = rte_eth_dev_start(portid);
767 [ # # ]: 0 : if (ret < 0)
768 : 0 : rte_exit(EXIT_FAILURE,
769 : : "rte_eth_dev_start: err=%d, port=%d\n",
770 : : ret, portid);
771 : :
772 : : /* always enable promiscuous */
773 : 0 : ret = rte_eth_promiscuous_enable(portid);
774 [ # # ]: 0 : if (ret != 0)
775 : 0 : rte_exit(EXIT_FAILURE,
776 : : "rte_eth_promiscuous_enable: err=%s, port=%d\n",
777 : : rte_strerror(-ret), portid);
778 : :
779 : 0 : lcore_conf[worker_id].portlist[num++] = portid;
780 : 0 : lcore_conf[worker_id].nb_ports++;
781 : : }
782 : 0 : check_all_ports_link_status(nb_ports, RTE_PORT_ALL);
783 : :
784 [ # # ]: 0 : if (tx_burst == NULL) {
785 : 0 : tx_burst = (struct rte_mbuf **)
786 : 0 : rte_calloc_socket("tx_buff",
787 : : MAX_TRAFFIC_BURST * nb_ports,
788 : : sizeof(void *),
789 : : RTE_CACHE_LINE_SIZE, socketid);
790 [ # # ]: 0 : if (!tx_burst)
791 : : return -1;
792 : : }
793 : :
794 : 0 : init_traffic(mbufpool[socketid],
795 : : tx_burst, MAX_TRAFFIC_BURST * nb_ports);
796 : :
797 : : printf("Generate %d packets @socket %d\n",
798 : : MAX_TRAFFIC_BURST * nb_ports, socketid);
799 : :
800 [ # # ]: 0 : if (sc_flag == SC_CONTINUOUS) {
801 : : /* do both rxtx by default */
802 [ # # ]: 0 : if (NULL == do_measure)
803 : 0 : do_measure = measure_rxtx;
804 : :
805 : 0 : rte_eal_remote_launch(main_loop, NULL, worker_id);
806 : :
807 [ # # ]: 0 : if (rte_eal_wait_lcore(worker_id) < 0)
808 : : return -1;
809 [ # # ]: 0 : } else if (sc_flag == SC_BURST_POLL_FIRST ||
810 : : sc_flag == SC_BURST_XMIT_FIRST)
811 [ # # ]: 0 : if (exec_burst(sc_flag, worker_id) < 0)
812 : : return -1;
813 : :
814 : : /* port tear down */
815 [ # # ]: 0 : RTE_ETH_FOREACH_DEV(portid) {
816 [ # # ]: 0 : if (socketid != rte_eth_dev_socket_id(portid))
817 : 0 : continue;
818 : :
819 : 0 : ret = rte_eth_dev_stop(portid);
820 [ # # ]: 0 : if (ret != 0)
821 : 0 : printf("rte_eth_dev_stop: err=%s, port=%u\n",
822 : : rte_strerror(-ret), portid);
823 : : }
824 : :
825 : : return 0;
826 : : }
827 : :
828 : : int
829 : 0 : test_set_rxtx_conf(cmdline_fixed_string_t mode)
830 : : {
831 : : printf("mode switch to %s\n", mode);
832 : :
833 [ # # ]: 0 : if (!strcmp(mode, "vector")) {
834 : : /* vector rx, tx */
835 : 0 : tx_conf.tx_rs_thresh = 32;
836 : 0 : tx_conf.tx_free_thresh = 32;
837 : 0 : return 0;
838 [ # # ]: 0 : } else if (!strcmp(mode, "scalar")) {
839 : : /* bulk alloc rx, full-featured tx */
840 : 0 : tx_conf.tx_rs_thresh = 32;
841 : 0 : tx_conf.tx_free_thresh = 32;
842 : 0 : port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
843 : 0 : return 0;
844 [ # # ]: 0 : } else if (!strcmp(mode, "hybrid")) {
845 : : /* bulk alloc rx, vector tx
846 : : * when vec macro not define,
847 : : * using the same rx/tx as scalar
848 : : */
849 : 0 : tx_conf.tx_rs_thresh = 32;
850 : 0 : tx_conf.tx_free_thresh = 32;
851 : 0 : port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
852 : 0 : return 0;
853 [ # # ]: 0 : } else if (!strcmp(mode, "full")) {
854 : : /* full feature rx,tx pair */
855 : 0 : tx_conf.tx_rs_thresh = 32;
856 : 0 : tx_conf.tx_free_thresh = 32;
857 : 0 : port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_SCATTER;
858 : 0 : return 0;
859 : : }
860 : :
861 : : return -1;
862 : : }
863 : :
864 : : int
865 : 0 : test_set_rxtx_anchor(cmdline_fixed_string_t type)
866 : : {
867 : : printf("type switch to %s\n", type);
868 : :
869 [ # # ]: 0 : if (!strcmp(type, "rxtx")) {
870 : 0 : do_measure = measure_rxtx;
871 : 0 : return 0;
872 [ # # ]: 0 : } else if (!strcmp(type, "rxonly")) {
873 : 0 : do_measure = measure_rxonly;
874 : 0 : return 0;
875 [ # # ]: 0 : } else if (!strcmp(type, "txonly")) {
876 : 0 : do_measure = measure_txonly;
877 : 0 : return 0;
878 : : }
879 : :
880 : : return -1;
881 : : }
882 : :
883 : : int
884 : 0 : test_set_rxtx_sc(cmdline_fixed_string_t type)
885 : : {
886 : : printf("stream control switch to %s\n", type);
887 : :
888 [ # # ]: 0 : if (!strcmp(type, "continuous")) {
889 : 0 : sc_flag = SC_CONTINUOUS;
890 : 0 : return 0;
891 [ # # ]: 0 : } else if (!strcmp(type, "poll_before_xmit")) {
892 : 0 : sc_flag = SC_BURST_POLL_FIRST;
893 : 0 : return 0;
894 [ # # ]: 0 : } else if (!strcmp(type, "poll_after_xmit")) {
895 : 0 : sc_flag = SC_BURST_XMIT_FIRST;
896 : 0 : return 0;
897 : : }
898 : :
899 : : return -1;
900 : : }
901 : :
902 : 252 : REGISTER_PERF_TEST(pmd_perf_autotest, test_pmd_perf);
|