1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2015 Intel Corporation 3 */ 4 5 6 #include <stdio.h> 7 #include <inttypes.h> 8 #include <rte_ring.h> 9 #include <rte_cycles.h> 10 #include <rte_launch.h> 11 #include <rte_ethdev.h> 12 #include <rte_eth_ring.h> 13 #include <rte_bus_vdev.h> 14 15 #include "test.h" 16 17 #define RING_NAME "RING_PERF" 18 #define RING_SIZE 4096 19 #define MAX_BURST 32 20 21 /* 22 * the sizes to enqueue and dequeue in testing 23 * (marked volatile so they won't be seen as compile-time constants) 24 */ 25 static const volatile unsigned bulk_sizes[] = { 1, 8, 32 }; 26 27 /* The ring structure used for tests */ 28 static struct rte_ring *r; 29 static uint16_t ring_ethdev_port; 30 31 /* Get cycle counts for dequeuing from an empty ring. Should be 2 or 3 cycles */ 32 static void 33 test_empty_dequeue(void) 34 { 35 const unsigned iter_shift = 26; 36 const unsigned iterations = 1 << iter_shift; 37 unsigned i = 0; 38 void *burst[MAX_BURST]; 39 40 const uint64_t sc_start = rte_rdtsc(); 41 for (i = 0; i < iterations; i++) 42 rte_ring_sc_dequeue_bulk(r, burst, bulk_sizes[0], NULL); 43 const uint64_t sc_end = rte_rdtsc(); 44 45 const uint64_t eth_start = rte_rdtsc(); 46 for (i = 0; i < iterations; i++) 47 rte_eth_rx_burst(ring_ethdev_port, 0, (void *)burst, 48 bulk_sizes[0]); 49 const uint64_t eth_end = rte_rdtsc(); 50 51 printf("Ring empty dequeue : %.1F\n", 52 (double)(sc_end - sc_start) / iterations); 53 printf("Ethdev empty dequeue: %.1F\n", 54 (double)(eth_end - eth_start) / iterations); 55 } 56 57 /* 58 * Test function that determines how long an enqueue + dequeue of a single item 59 * takes on a single lcore. Result is for comparison with the bulk enq+deq. 60 */ 61 static void 62 test_single_enqueue_dequeue(void) 63 { 64 const unsigned iter_shift = 24; 65 const unsigned iterations = 1 << iter_shift; 66 unsigned i = 0; 67 void *burst = NULL; 68 struct rte_mbuf *mburst[1] = { NULL }; 69 70 const uint64_t sc_start = rte_rdtsc_precise(); 71 rte_compiler_barrier(); 72 for (i = 0; i < iterations; i++) { 73 rte_ring_enqueue_bulk(r, &burst, 1, NULL); 74 rte_ring_dequeue_bulk(r, &burst, 1, NULL); 75 } 76 const uint64_t sc_end = rte_rdtsc_precise(); 77 rte_compiler_barrier(); 78 79 const uint64_t eth_start = rte_rdtsc_precise(); 80 rte_compiler_barrier(); 81 for (i = 0; i < iterations; i++) { 82 rte_eth_tx_burst(ring_ethdev_port, 0, mburst, 1); 83 rte_eth_rx_burst(ring_ethdev_port, 0, mburst, 1); 84 } 85 const uint64_t eth_end = rte_rdtsc_precise(); 86 rte_compiler_barrier(); 87 88 printf("Ring single enq/dequeue : %"PRIu64"\n", 89 (sc_end-sc_start) >> iter_shift); 90 printf("Ethdev single enq/dequeue: %"PRIu64"\n", 91 (eth_end-eth_start) >> iter_shift); 92 } 93 94 /* Times enqueue and dequeue on a single lcore */ 95 static void 96 test_bulk_enqueue_dequeue(void) 97 { 98 const unsigned iter_shift = 23; 99 const unsigned iterations = 1 << iter_shift; 100 unsigned sz, i = 0; 101 struct rte_mbuf *burst[MAX_BURST] = {0}; 102 103 for (sz = 0; sz < RTE_DIM(bulk_sizes); sz++) { 104 const uint64_t sc_start = rte_rdtsc(); 105 for (i = 0; i < iterations; i++) { 106 rte_ring_sp_enqueue_bulk(r, (void *)burst, 107 bulk_sizes[sz], NULL); 108 rte_ring_sc_dequeue_bulk(r, (void *)burst, 109 bulk_sizes[sz], NULL); 110 } 111 const uint64_t sc_end = rte_rdtsc(); 112 113 const uint64_t eth_start = rte_rdtsc_precise(); 114 rte_compiler_barrier(); 115 for (i = 0; i < iterations; i++) { 116 rte_eth_tx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]); 117 rte_eth_rx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]); 118 } 119 const uint64_t eth_end = rte_rdtsc_precise(); 120 rte_compiler_barrier(); 121 122 double sc_avg = ((double)(sc_end-sc_start) / 123 (iterations * bulk_sizes[sz])); 124 double eth_avg = ((double)(eth_end-eth_start) / 125 (iterations * bulk_sizes[sz])); 126 127 printf("ring bulk enq/deq (size: %u) : %.1F\n", bulk_sizes[sz], 128 sc_avg); 129 printf("ethdev bulk enq/deq (size:%u): %.1F\n", bulk_sizes[sz], 130 eth_avg); 131 132 printf("\n"); 133 } 134 } 135 136 static int 137 test_ring_pmd_perf(void) 138 { 139 char name[RTE_ETH_NAME_MAX_LEN]; 140 141 r = rte_ring_create(RING_NAME, RING_SIZE, rte_socket_id(), 142 RING_F_SP_ENQ|RING_F_SC_DEQ); 143 if (r == NULL && (r = rte_ring_lookup(RING_NAME)) == NULL) 144 return -1; 145 146 ring_ethdev_port = rte_eth_from_ring(r); 147 148 printf("\n### Testing const single element enq/deq ###\n"); 149 test_single_enqueue_dequeue(); 150 151 printf("\n### Testing empty dequeue ###\n"); 152 test_empty_dequeue(); 153 154 printf("\n### Testing using a single lcore ###\n"); 155 test_bulk_enqueue_dequeue(); 156 157 /* release port and ring resources */ 158 if (rte_eth_dev_stop(ring_ethdev_port) != 0) 159 return -1; 160 rte_eth_dev_get_name_by_port(ring_ethdev_port, name); 161 rte_vdev_uninit(name); 162 rte_ring_free(r); 163 return 0; 164 } 165 166 REGISTER_TEST_COMMAND(ring_pmd_perf_autotest, test_ring_pmd_perf); 167