004882af179d827c57189a393b06e9ed0bc8923d
[dpdk.git] / test / test / test_pmd_ring_perf.c
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], NULL);
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, NULL);
102                 rte_ring_dequeue_bulk(r, &burst, 1, NULL);
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,
135                                         bulk_sizes[sz], NULL);
136                         rte_ring_sc_dequeue_bulk(r, (void *)burst,
137                                         bulk_sizes[sz], NULL);
138                 }
139                 const uint64_t sc_end = rte_rdtsc();
140
141                 const uint64_t eth_start = rte_rdtsc_precise();
142                 rte_compiler_barrier();
143                 for (i = 0; i < iterations; i++) {
144                         rte_eth_tx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]);
145                         rte_eth_rx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]);
146                 }
147                 const uint64_t eth_end = rte_rdtsc_precise();
148                 rte_compiler_barrier();
149
150                 double sc_avg = ((double)(sc_end-sc_start) /
151                                 (iterations * bulk_sizes[sz]));
152                 double eth_avg = ((double)(eth_end-eth_start) /
153                                 (iterations * bulk_sizes[sz]));
154
155                 printf("ring bulk enq/deq (size: %u) : %.1F\n", bulk_sizes[sz],
156                                 sc_avg);
157                 printf("ethdev bulk enq/deq (size:%u): %.1F\n", bulk_sizes[sz],
158                                 eth_avg);
159
160                 printf("\n");
161         }
162 }
163
164 static int
165 test_ring_pmd_perf(void)
166 {
167         r = rte_ring_create(RING_NAME, RING_SIZE, rte_socket_id(),
168                         RING_F_SP_ENQ|RING_F_SC_DEQ);
169         if (r == NULL && (r = rte_ring_lookup(RING_NAME)) == NULL)
170                 return -1;
171
172         ring_ethdev_port = rte_eth_from_ring(r);
173
174         printf("\n### Testing const single element enq/deq ###\n");
175         test_single_enqueue_dequeue();
176
177         printf("\n### Testing empty dequeue ###\n");
178         test_empty_dequeue();
179
180         printf("\n### Testing using a single lcore ###\n");
181         test_bulk_enqueue_dequeue();
182
183         return 0;
184 }
185
186 REGISTER_TEST_COMMAND(ring_pmd_perf_autotest, test_ring_pmd_perf);