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