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