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, ETHER_TYPE_IPv4, 0, 0); 239 240 pktlen = initialize_ipv4_header(&pkt_ipv4_hdr, 241 IPV4_ADDR(10, 0, 0, 1), 242 IPV4_ADDR(10, 0, 0, 2), 26); 243 printf("IPv4 pktlen %u\n", pktlen); 244 245 pktlen = initialize_udp_header(&pkt_udp_hdr, 0, 0, 18); 246 247 printf("UDP pktlen %u\n", pktlen); 248 249 return generate_packet_burst(mp, pkts_burst, &pkt_eth_hdr, 250 0, &pkt_ipv4_hdr, 1, 251 &pkt_udp_hdr, burst_size, 252 PACKET_BURST_GEN_PKT_LEN, 1); 253 } 254 255 static int 256 init_lcores(void) 257 { 258 unsigned lcore_id; 259 260 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 261 lcore_conf[lcore_id].socketid = 262 rte_lcore_to_socket_id(lcore_id); 263 if (rte_lcore_is_enabled(lcore_id) == 0) { 264 lcore_conf[lcore_id].status = LCORE_INVALID; 265 continue; 266 } else 267 lcore_conf[lcore_id].status = LCORE_AVAIL; 268 } 269 return 0; 270 } 271 272 static int 273 init_mbufpool(unsigned nb_mbuf) 274 { 275 int socketid; 276 unsigned lcore_id; 277 char s[64]; 278 279 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 280 if (rte_lcore_is_enabled(lcore_id) == 0) 281 continue; 282 283 socketid = rte_lcore_to_socket_id(lcore_id); 284 if (socketid >= NB_SOCKETS) { 285 rte_exit(EXIT_FAILURE, 286 "Socket %d of lcore %u is out of range %d\n", 287 socketid, lcore_id, NB_SOCKETS); 288 } 289 if (mbufpool[socketid] == NULL) { 290 snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); 291 mbufpool[socketid] = 292 rte_mempool_create(s, nb_mbuf, MBUF_SIZE, 293 MEMPOOL_CACHE_SIZE, 294 sizeof(struct rte_pktmbuf_pool_private), 295 rte_pktmbuf_pool_init, NULL, 296 rte_pktmbuf_init, NULL, 297 socketid, 0); 298 if (mbufpool[socketid] == NULL) 299 rte_exit(EXIT_FAILURE, 300 "Cannot init mbuf pool on socket %d\n", 301 socketid); 302 else 303 printf("Allocated mbuf pool on socket %d\n", 304 socketid); 305 } 306 } 307 return 0; 308 } 309 310 static uint16_t 311 alloc_lcore(uint16_t socketid) 312 { 313 unsigned lcore_id; 314 315 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 316 if (LCORE_AVAIL != lcore_conf[lcore_id].status || 317 lcore_conf[lcore_id].socketid != socketid || 318 lcore_id == rte_get_master_lcore()) 319 continue; 320 lcore_conf[lcore_id].status = LCORE_USED; 321 lcore_conf[lcore_id].nb_ports = 0; 322 return lcore_id; 323 } 324 325 return (uint16_t)-1; 326 } 327 328 volatile uint64_t stop; 329 uint64_t count; 330 uint64_t drop; 331 uint64_t idle; 332 333 static void 334 reset_count(void) 335 { 336 count = 0; 337 drop = 0; 338 idle = 0; 339 } 340 341 static void 342 stats_display(uint8_t port_id) 343 { 344 struct rte_eth_stats stats; 345 rte_eth_stats_get(port_id, &stats); 346 347 printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: " 348 "%-"PRIu64"\n", 349 stats.ipackets, stats.imissed, stats.ibytes); 350 printf(" RX-badcrc: %-10"PRIu64" RX-badlen: %-10"PRIu64" RX-errors: " 351 "%-"PRIu64"\n", 352 stats.ibadcrc, stats.ibadlen, stats.ierrors); 353 printf(" RX-nombuf: %-10"PRIu64"\n", 354 stats.rx_nombuf); 355 printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: " 356 "%-"PRIu64"\n", 357 stats.opackets, stats.oerrors, stats.obytes); 358 } 359 360 static void 361 signal_handler(int signum) 362 { 363 /* USR1 signal, stop testing */ 364 if (signum == SIGUSR1) { 365 printf("Force Stop!\n"); 366 stop = 1; 367 } 368 369 /* USR2 signal, print stats */ 370 if (signum == SIGUSR2) 371 stats_display(0); 372 } 373 374 struct rte_mbuf **tx_burst; 375 376 uint64_t (*do_measure)(struct lcore_conf *conf, 377 struct rte_mbuf *pkts_burst[], 378 uint64_t total_pkts); 379 380 static uint64_t 381 measure_rxtx(struct lcore_conf *conf, 382 struct rte_mbuf *pkts_burst[], 383 uint64_t total_pkts) 384 { 385 unsigned i, portid, nb_rx, nb_tx; 386 uint64_t prev_tsc, cur_tsc; 387 388 prev_tsc = rte_rdtsc(); 389 390 while (likely(!stop)) { 391 for (i = 0; i < conf->nb_ports; i++) { 392 portid = conf->portlist[i]; 393 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 394 pkts_burst, MAX_PKT_BURST); 395 if (unlikely(nb_rx == 0)) { 396 idle++; 397 continue; 398 } 399 400 count += nb_rx; 401 nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); 402 if (unlikely(nb_tx < nb_rx)) { 403 drop += (nb_rx - nb_tx); 404 do { 405 rte_pktmbuf_free(pkts_burst[nb_tx]); 406 } while (++nb_tx < nb_rx); 407 } 408 } 409 if (unlikely(count >= total_pkts)) 410 break; 411 } 412 413 cur_tsc = rte_rdtsc(); 414 415 return cur_tsc - prev_tsc; 416 } 417 418 static uint64_t 419 measure_rxonly(struct lcore_conf *conf, 420 struct rte_mbuf *pkts_burst[], 421 uint64_t total_pkts) 422 { 423 unsigned i, portid, nb_rx, nb_tx; 424 uint64_t diff_tsc, cur_tsc; 425 426 diff_tsc = 0; 427 while (likely(!stop)) { 428 for (i = 0; i < conf->nb_ports; i++) { 429 portid = conf->portlist[i]; 430 431 cur_tsc = rte_rdtsc(); 432 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 433 pkts_burst, MAX_PKT_BURST); 434 if (unlikely(nb_rx == 0)) { 435 idle++; 436 continue; 437 } 438 diff_tsc += rte_rdtsc() - cur_tsc; 439 440 count += nb_rx; 441 nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); 442 if (unlikely(nb_tx < nb_rx)) { 443 drop += (nb_rx - nb_tx); 444 do { 445 rte_pktmbuf_free(pkts_burst[nb_tx]); 446 } while (++nb_tx < nb_rx); 447 } 448 } 449 if (unlikely(count >= total_pkts)) 450 break; 451 } 452 453 return diff_tsc; 454 } 455 456 static uint64_t 457 measure_txonly(struct lcore_conf *conf, 458 struct rte_mbuf *pkts_burst[], 459 uint64_t total_pkts) 460 { 461 unsigned i, portid, nb_rx, nb_tx; 462 uint64_t diff_tsc, cur_tsc; 463 464 printf("do tx measure\n"); 465 diff_tsc = 0; 466 while (likely(!stop)) { 467 for (i = 0; i < conf->nb_ports; i++) { 468 portid = conf->portlist[i]; 469 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 470 pkts_burst, MAX_PKT_BURST); 471 if (unlikely(nb_rx == 0)) { 472 idle++; 473 continue; 474 } 475 476 count += nb_rx; 477 478 cur_tsc = rte_rdtsc(); 479 nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); 480 if (unlikely(nb_tx < nb_rx)) { 481 drop += (nb_rx - nb_tx); 482 do { 483 rte_pktmbuf_free(pkts_burst[nb_tx]); 484 } while (++nb_tx < nb_rx); 485 } 486 diff_tsc += rte_rdtsc() - cur_tsc; 487 } 488 if (unlikely(count >= total_pkts)) 489 break; 490 } 491 492 return diff_tsc; 493 } 494 495 /* main processing loop */ 496 static int 497 main_loop(__rte_unused void *args) 498 { 499 #define PACKET_SIZE 64 500 #define FRAME_GAP 12 501 #define MAC_PREAMBLE 8 502 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 503 unsigned lcore_id; 504 unsigned i, portid, nb_rx = 0, nb_tx = 0; 505 struct lcore_conf *conf; 506 int pkt_per_port; 507 uint64_t diff_tsc; 508 uint64_t packets_per_second, total_packets; 509 510 lcore_id = rte_lcore_id(); 511 conf = &lcore_conf[lcore_id]; 512 if (conf->status != LCORE_USED) 513 return 0; 514 515 pkt_per_port = MAX_TRAFFIC_BURST; 516 517 int idx = 0; 518 for (i = 0; i < conf->nb_ports; i++) { 519 int num = pkt_per_port; 520 portid = conf->portlist[i]; 521 printf("inject %d packet to port %d\n", num, portid); 522 while (num) { 523 nb_tx = RTE_MIN(MAX_PKT_BURST, num); 524 nb_tx = rte_eth_tx_burst(portid, 0, 525 &tx_burst[idx], nb_tx); 526 num -= nb_tx; 527 idx += nb_tx; 528 } 529 } 530 printf("Total packets inject to prime ports = %u\n", idx); 531 532 packets_per_second = (link_mbps * 1000 * 1000) / 533 ((PACKET_SIZE + FRAME_GAP + MAC_PREAMBLE) * CHAR_BIT); 534 printf("Each port will do %"PRIu64" packets per second\n", 535 packets_per_second); 536 537 total_packets = RTE_TEST_DURATION * conf->nb_ports * packets_per_second; 538 printf("Test will stop after at least %"PRIu64" packets received\n", 539 + total_packets); 540 541 diff_tsc = do_measure(conf, pkts_burst, total_packets); 542 543 for (i = 0; i < conf->nb_ports; i++) { 544 portid = conf->portlist[i]; 545 int nb_free = pkt_per_port; 546 do { /* dry out */ 547 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 548 pkts_burst, MAX_PKT_BURST); 549 nb_tx = 0; 550 while (nb_tx < nb_rx) 551 rte_pktmbuf_free(pkts_burst[nb_tx++]); 552 nb_free -= nb_rx; 553 } while (nb_free != 0); 554 printf("free %d mbuf left in port %u\n", pkt_per_port, portid); 555 } 556 557 if (count == 0) 558 return -1; 559 560 printf("%"PRIu64" packet, %"PRIu64" drop, %"PRIu64" idle\n", 561 count, drop, idle); 562 printf("Result: %"PRIu64" cycles per packet\n", diff_tsc / count); 563 564 return 0; 565 } 566 567 rte_atomic64_t start; 568 569 static inline int 570 poll_burst(void *args) 571 { 572 #define MAX_IDLE (10000) 573 unsigned lcore_id; 574 struct rte_mbuf **pkts_burst; 575 uint64_t diff_tsc, cur_tsc; 576 uint16_t next[RTE_MAX_ETHPORTS]; 577 struct lcore_conf *conf; 578 uint32_t pkt_per_port = *((uint32_t *)args); 579 unsigned i, portid, nb_rx = 0; 580 uint64_t total; 581 uint64_t timeout = MAX_IDLE; 582 583 lcore_id = rte_lcore_id(); 584 conf = &lcore_conf[lcore_id]; 585 if (conf->status != LCORE_USED) 586 return 0; 587 588 total = pkt_per_port * conf->nb_ports; 589 printf("start to receive total expect %"PRIu64"\n", total); 590 591 pkts_burst = (struct rte_mbuf **) 592 rte_calloc_socket("poll_burst", 593 total, sizeof(void *), 594 RTE_CACHE_LINE_SIZE, conf->socketid); 595 if (!pkts_burst) 596 return -1; 597 598 for (i = 0; i < conf->nb_ports; i++) { 599 portid = conf->portlist[i]; 600 next[portid] = i * pkt_per_port; 601 } 602 603 while (!rte_atomic64_read(&start)) 604 ; 605 606 cur_tsc = rte_rdtsc(); 607 while (total) { 608 for (i = 0; i < conf->nb_ports; i++) { 609 portid = conf->portlist[i]; 610 nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, 611 &pkts_burst[next[portid]], 612 MAX_PKT_BURST); 613 if (unlikely(nb_rx == 0)) { 614 timeout--; 615 if (unlikely(timeout == 0)) 616 goto timeout; 617 continue; 618 } 619 next[portid] += nb_rx; 620 total -= nb_rx; 621 } 622 } 623 timeout: 624 diff_tsc = rte_rdtsc() - cur_tsc; 625 626 printf("%"PRIu64" packets lost, IDLE %"PRIu64" times\n", 627 total, MAX_IDLE - timeout); 628 629 /* clean up */ 630 total = pkt_per_port * conf->nb_ports - total; 631 for (i = 0; i < total; i++) 632 rte_pktmbuf_free(pkts_burst[i]); 633 634 rte_free(pkts_burst); 635 636 return diff_tsc / total; 637 } 638 639 static int 640 exec_burst(uint32_t flags, int lcore) 641 { 642 unsigned i, portid, nb_tx = 0; 643 struct lcore_conf *conf; 644 uint32_t pkt_per_port; 645 int num, idx = 0; 646 int diff_tsc; 647 648 conf = &lcore_conf[lcore]; 649 650 pkt_per_port = MAX_TRAFFIC_BURST; 651 num = pkt_per_port; 652 653 rte_atomic64_init(&start); 654 655 /* start polling thread, but not actually poll yet */ 656 rte_eal_remote_launch(poll_burst, 657 (void *)&pkt_per_port, lcore); 658 659 /* Only when polling first */ 660 if (flags == SC_BURST_POLL_FIRST) 661 rte_atomic64_set(&start, 1); 662 663 /* start xmit */ 664 while (num) { 665 nb_tx = RTE_MIN(MAX_PKT_BURST, num); 666 for (i = 0; i < conf->nb_ports; i++) { 667 portid = conf->portlist[i]; 668 rte_eth_tx_burst(portid, 0, 669 &tx_burst[idx], nb_tx); 670 idx += nb_tx; 671 } 672 num -= nb_tx; 673 } 674 675 sleep(5); 676 677 /* only when polling second */ 678 if (flags == SC_BURST_XMIT_FIRST) 679 rte_atomic64_set(&start, 1); 680 681 /* wait for polling finished */ 682 diff_tsc = rte_eal_wait_lcore(lcore); 683 if (diff_tsc < 0) 684 return -1; 685 686 printf("Result: %d cycles per packet\n", diff_tsc); 687 688 return 0; 689 } 690 691 static int 692 test_pmd_perf(void) 693 { 694 uint16_t nb_ports, num, nb_lcores, slave_id = (uint16_t)-1; 695 uint16_t nb_rxd = MAX_TRAFFIC_BURST; 696 uint16_t nb_txd = MAX_TRAFFIC_BURST; 697 uint16_t portid; 698 uint16_t nb_rx_queue = 1, nb_tx_queue = 1; 699 int socketid = -1; 700 int ret; 701 702 printf("Start PMD RXTX cycles cost test.\n"); 703 704 signal(SIGUSR1, signal_handler); 705 signal(SIGUSR2, signal_handler); 706 707 nb_ports = rte_eth_dev_count(); 708 if (nb_ports < NB_ETHPORTS_USED) { 709 printf("At least %u port(s) used for perf. test\n", 710 NB_ETHPORTS_USED); 711 return -1; 712 } 713 714 if (nb_ports > RTE_MAX_ETHPORTS) 715 nb_ports = RTE_MAX_ETHPORTS; 716 717 nb_lcores = rte_lcore_count(); 718 719 memset(lcore_conf, 0, sizeof(lcore_conf)); 720 init_lcores(); 721 722 init_mbufpool(NB_MBUF); 723 724 if (sc_flag == SC_CONTINUOUS) { 725 nb_rxd = RTE_TEST_RX_DESC_DEFAULT; 726 nb_txd = RTE_TEST_TX_DESC_DEFAULT; 727 } 728 printf("CONFIG RXD=%d TXD=%d\n", nb_rxd, nb_txd); 729 730 reset_count(); 731 num = 0; 732 for (portid = 0; portid < nb_ports; portid++) { 733 if (socketid == -1) { 734 socketid = rte_eth_dev_socket_id(portid); 735 slave_id = alloc_lcore(socketid); 736 if (slave_id == (uint16_t)-1) { 737 printf("No avail lcore to run test\n"); 738 return -1; 739 } 740 printf("Performance test runs on lcore %u socket %u\n", 741 slave_id, socketid); 742 } 743 744 if (socketid != rte_eth_dev_socket_id(portid)) { 745 printf("Skip port %d\n", portid); 746 continue; 747 } 748 749 /* port configure */ 750 ret = rte_eth_dev_configure(portid, nb_rx_queue, 751 nb_tx_queue, &port_conf); 752 if (ret < 0) 753 rte_exit(EXIT_FAILURE, 754 "Cannot configure device: err=%d, port=%d\n", 755 ret, portid); 756 757 rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); 758 printf("Port %u ", portid); 759 print_ethaddr("Address:", &ports_eth_addr[portid]); 760 printf("\n"); 761 762 /* tx queue setup */ 763 ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, 764 socketid, &tx_conf); 765 if (ret < 0) 766 rte_exit(EXIT_FAILURE, 767 "rte_eth_tx_queue_setup: err=%d, " 768 "port=%d\n", ret, portid); 769 770 /* rx queue steup */ 771 ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, 772 socketid, &rx_conf, 773 mbufpool[socketid]); 774 if (ret < 0) 775 rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d," 776 "port=%d\n", ret, portid); 777 778 /* Start device */ 779 stop = 0; 780 ret = rte_eth_dev_start(portid); 781 if (ret < 0) 782 rte_exit(EXIT_FAILURE, 783 "rte_eth_dev_start: err=%d, port=%d\n", 784 ret, portid); 785 786 /* always eanble promiscuous */ 787 rte_eth_promiscuous_enable(portid); 788 789 lcore_conf[slave_id].portlist[num++] = portid; 790 lcore_conf[slave_id].nb_ports++; 791 } 792 check_all_ports_link_status(nb_ports, RTE_PORT_ALL); 793 794 if (tx_burst == NULL) { 795 tx_burst = (struct rte_mbuf **) 796 rte_calloc_socket("tx_buff", 797 MAX_TRAFFIC_BURST * nb_ports, 798 sizeof(void *), 799 RTE_CACHE_LINE_SIZE, socketid); 800 if (!tx_burst) 801 return -1; 802 } 803 804 init_traffic(mbufpool[socketid], 805 tx_burst, MAX_TRAFFIC_BURST * nb_ports); 806 807 printf("Generate %d packets @socket %d\n", 808 MAX_TRAFFIC_BURST * nb_ports, socketid); 809 810 if (sc_flag == SC_CONTINUOUS) { 811 /* do both rxtx by default */ 812 if (NULL == do_measure) 813 do_measure = measure_rxtx; 814 815 rte_eal_remote_launch(main_loop, NULL, slave_id); 816 817 if (rte_eal_wait_lcore(slave_id) < 0) 818 return -1; 819 } else if (sc_flag == SC_BURST_POLL_FIRST || 820 sc_flag == SC_BURST_XMIT_FIRST) 821 exec_burst(sc_flag, slave_id); 822 823 /* port tear down */ 824 for (portid = 0; portid < nb_ports; portid++) { 825 if (socketid != rte_eth_dev_socket_id(portid)) 826 continue; 827 828 rte_eth_dev_stop(portid); 829 } 830 831 return 0; 832 } 833 834 int 835 test_set_rxtx_conf(cmdline_fixed_string_t mode) 836 { 837 printf("mode switch to %s\n", mode); 838 839 if (!strcmp(mode, "vector")) { 840 /* vector rx, tx */ 841 tx_conf.txq_flags = 0xf01; 842 tx_conf.tx_rs_thresh = 32; 843 tx_conf.tx_free_thresh = 32; 844 port_conf.rxmode.hw_ip_checksum = 0; 845 port_conf.rxmode.enable_scatter = 0; 846 return 0; 847 } else if (!strcmp(mode, "scalar")) { 848 /* bulk alloc rx, simple tx */ 849 tx_conf.txq_flags = 0xf01; 850 tx_conf.tx_rs_thresh = 128; 851 tx_conf.tx_free_thresh = 128; 852 port_conf.rxmode.hw_ip_checksum = 1; 853 port_conf.rxmode.enable_scatter = 0; 854 return 0; 855 } else if (!strcmp(mode, "hybrid")) { 856 /* bulk alloc rx, vector tx 857 * when vec macro not define, 858 * using the same rx/tx as scalar 859 */ 860 tx_conf.txq_flags = 0xf01; 861 tx_conf.tx_rs_thresh = 32; 862 tx_conf.tx_free_thresh = 32; 863 port_conf.rxmode.hw_ip_checksum = 1; 864 port_conf.rxmode.enable_scatter = 0; 865 return 0; 866 } else if (!strcmp(mode, "full")) { 867 /* full feature rx,tx pair */ 868 tx_conf.txq_flags = 0x0; /* must condition */ 869 tx_conf.tx_rs_thresh = 32; 870 tx_conf.tx_free_thresh = 32; 871 port_conf.rxmode.hw_ip_checksum = 0; 872 port_conf.rxmode.enable_scatter = 1; /* must condition */ 873 return 0; 874 } 875 876 return -1; 877 } 878 879 int 880 test_set_rxtx_anchor(cmdline_fixed_string_t type) 881 { 882 printf("type switch to %s\n", type); 883 884 if (!strcmp(type, "rxtx")) { 885 do_measure = measure_rxtx; 886 return 0; 887 } else if (!strcmp(type, "rxonly")) { 888 do_measure = measure_rxonly; 889 return 0; 890 } else if (!strcmp(type, "txonly")) { 891 do_measure = measure_txonly; 892 return 0; 893 } 894 895 return -1; 896 } 897 898 int 899 test_set_rxtx_sc(cmdline_fixed_string_t type) 900 { 901 printf("stream control switch to %s\n", type); 902 903 if (!strcmp(type, "continuous")) { 904 sc_flag = SC_CONTINUOUS; 905 return 0; 906 } else if (!strcmp(type, "poll_before_xmit")) { 907 sc_flag = SC_BURST_POLL_FIRST; 908 return 0; 909 } else if (!strcmp(type, "poll_after_xmit")) { 910 sc_flag = SC_BURST_XMIT_FIRST; 911 return 0; 912 } 913 914 return -1; 915 } 916 917 static struct test_command pmd_perf_cmd = { 918 .command = "pmd_perf_autotest", 919 .callback = test_pmd_perf, 920 }; 921 REGISTER_TEST_COMMAND(pmd_perf_cmd); 922