Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : * Copyright(c) 2019 Arm Limited
4 : : */
5 : :
6 : :
7 : : #include <stdio.h>
8 : : #include <inttypes.h>
9 : : #include <rte_ring.h>
10 : : #include <rte_cycles.h>
11 : : #include <rte_launch.h>
12 : : #include <rte_pause.h>
13 : : #include <string.h>
14 : :
15 : : #include "test.h"
16 : : #include "test_ring.h"
17 : :
18 : : /*
19 : : * Ring performance test cases, measures performance of various operations
20 : : * using rdtsc for legacy and 16B size ring elements.
21 : : */
22 : :
23 : : #define RING_NAME "RING_PERF"
24 : : #define RING_SIZE 4096
25 : : #define MAX_BURST 256
26 : :
27 : : /*
28 : : * the sizes to enqueue and dequeue in testing
29 : : * (marked volatile so they won't be seen as compile-time constants)
30 : : */
31 : : static const volatile unsigned int bulk_sizes[] = { 8, 32, 64, 128, 256 };
32 : :
33 : : struct lcore_pair {
34 : : unsigned c1, c2;
35 : : };
36 : :
37 : : static RTE_ATOMIC(unsigned int) lcore_count;
38 : :
39 : : static void
40 : 0 : test_ring_print_test_string(unsigned int api_type, int esize,
41 : : unsigned int bsz, double value)
42 : : {
43 [ # # ]: 0 : if (esize == -1)
44 : : printf("legacy APIs");
45 : : else
46 : : printf("elem APIs (size:%2dB)", esize);
47 : :
48 [ # # ]: 0 : if (api_type == TEST_RING_IGNORE_API_TYPE)
49 : : return;
50 : :
51 [ # # ]: 0 : if ((api_type & TEST_RING_THREAD_DEF) == TEST_RING_THREAD_DEF)
52 : : printf(" - default enqueue/dequeue");
53 [ # # ]: 0 : else if ((api_type & TEST_RING_THREAD_SPSC) == TEST_RING_THREAD_SPSC)
54 : : printf(" - SP/SC");
55 [ # # ]: 0 : else if ((api_type & TEST_RING_THREAD_MPMC) == TEST_RING_THREAD_MPMC)
56 : : printf(" - MP/MC");
57 : :
58 [ # # ]: 0 : if ((api_type & TEST_RING_ELEM_SINGLE) == TEST_RING_ELEM_SINGLE)
59 : : printf(" - single - ");
60 [ # # ]: 0 : else if ((api_type & TEST_RING_ELEM_BULK) == TEST_RING_ELEM_BULK)
61 : : printf(" - bulk (n:%-3u) - ", bsz);
62 [ # # ]: 0 : else if ((api_type & TEST_RING_ELEM_BURST) == TEST_RING_ELEM_BURST)
63 : : printf(" - burst (n:%-3u) - ", bsz);
64 [ # # ]: 0 : else if ((api_type & (TEST_RING_ELEM_BURST_ZC |
65 : : TEST_RING_ELEM_BURST_ZC_COMPRESS_PTR_16 |
66 : : TEST_RING_ELEM_BURST_ZC_COMPRESS_PTR_32)) != 0)
67 : : printf(" - burst zero copy (n:%-3u) - ", bsz);
68 : :
69 : : printf("cycles per elem: %.3F\n", value);
70 : : }
71 : :
72 : : /**** Functions to analyse our core mask to get cores for different tests ***/
73 : :
74 : : static int
75 : 0 : get_two_hyperthreads(struct lcore_pair *lcp)
76 : : {
77 : : unsigned id1, id2;
78 : : unsigned c1, c2, s1, s2;
79 [ # # ]: 0 : RTE_LCORE_FOREACH(id1) {
80 : : /* inner loop just re-reads all id's. We could skip the first few
81 : : * elements, but since number of cores is small there is little point
82 : : */
83 [ # # ]: 0 : RTE_LCORE_FOREACH(id2) {
84 [ # # ]: 0 : if (id1 == id2)
85 : 0 : continue;
86 : :
87 : 0 : c1 = rte_lcore_to_cpu_id(id1);
88 : 0 : c2 = rte_lcore_to_cpu_id(id2);
89 : 0 : s1 = rte_lcore_to_socket_id(id1);
90 : 0 : s2 = rte_lcore_to_socket_id(id2);
91 [ # # ]: 0 : if ((c1 == c2) && (s1 == s2)){
92 : 0 : lcp->c1 = id1;
93 : 0 : lcp->c2 = id2;
94 : 0 : return 0;
95 : : }
96 : : }
97 : : }
98 : : return 1;
99 : : }
100 : :
101 : : static int
102 : 0 : get_two_cores(struct lcore_pair *lcp)
103 : : {
104 : : unsigned id1, id2;
105 : : unsigned c1, c2, s1, s2;
106 [ # # ]: 0 : RTE_LCORE_FOREACH(id1) {
107 [ # # ]: 0 : RTE_LCORE_FOREACH(id2) {
108 [ # # ]: 0 : if (id1 == id2)
109 : 0 : continue;
110 : :
111 : 0 : c1 = rte_lcore_to_cpu_id(id1);
112 : 0 : c2 = rte_lcore_to_cpu_id(id2);
113 : 0 : s1 = rte_lcore_to_socket_id(id1);
114 : 0 : s2 = rte_lcore_to_socket_id(id2);
115 [ # # ]: 0 : if ((c1 != c2) && (s1 == s2)){
116 : 0 : lcp->c1 = id1;
117 : 0 : lcp->c2 = id2;
118 : 0 : return 0;
119 : : }
120 : : }
121 : : }
122 : : return 1;
123 : : }
124 : :
125 : : static int
126 : 0 : get_two_sockets(struct lcore_pair *lcp)
127 : : {
128 : : unsigned id1, id2;
129 : : unsigned s1, s2;
130 [ # # ]: 0 : RTE_LCORE_FOREACH(id1) {
131 [ # # ]: 0 : RTE_LCORE_FOREACH(id2) {
132 [ # # ]: 0 : if (id1 == id2)
133 : 0 : continue;
134 : 0 : s1 = rte_lcore_to_socket_id(id1);
135 : 0 : s2 = rte_lcore_to_socket_id(id2);
136 [ # # ]: 0 : if (s1 != s2){
137 : 0 : lcp->c1 = id1;
138 : 0 : lcp->c2 = id2;
139 : 0 : return 0;
140 : : }
141 : : }
142 : : }
143 : : return 1;
144 : : }
145 : :
146 : : /* Get cycle counts for dequeuing from an empty ring. Should be 2 or 3 cycles */
147 : : static void
148 : 0 : test_empty_dequeue(struct rte_ring *r, const int esize,
149 : : const unsigned int api_type)
150 : : {
151 : : const unsigned int iter_shift = 29;
152 : : const unsigned int iterations = 1 << iter_shift;
153 : : unsigned int i = 0;
154 : : void *burst[MAX_BURST];
155 : :
156 : 0 : const unsigned int bulk_iterations = iterations / bulk_sizes[0];
157 : : const uint64_t start = rte_rdtsc();
158 [ # # ]: 0 : for (i = 0; i < bulk_iterations; i++)
159 : 0 : test_ring_dequeue(r, burst, esize, bulk_sizes[0], api_type);
160 : : const uint64_t end = rte_rdtsc();
161 : :
162 : 0 : test_ring_print_test_string(api_type, esize, bulk_sizes[0],
163 : 0 : ((double)end - start) / iterations);
164 : 0 : }
165 : :
166 : : /* describes the ring used by the enqueue and dequeue thread */
167 : : struct ring_params {
168 : : struct rte_ring *r;
169 : : unsigned int elem_size;
170 : : unsigned int bulk_sizes_i; /* index into bulk_size array */
171 : : unsigned int ring_flags; /* flags for test_ring_enqueue/dequeue */
172 : : };
173 : :
174 : : /* Used to specify enqueue and dequeue ring operations and their results */
175 : : struct thread_params {
176 : : struct ring_params *ring_params;
177 : : double *results; /* result array size must be equal to bulk_sizes */
178 : : };
179 : :
180 : : /*
181 : : * Helper function to call bulk SP/MP enqueue functions.
182 : : * flag == 0 -> enqueue
183 : : * flag == 1 -> dequeue
184 : : */
185 : : static __rte_always_inline int
186 : : enqueue_dequeue_bulk_helper(const unsigned int flag, struct thread_params *p)
187 : : {
188 : : int ret;
189 : : const unsigned int iter_shift = 22;
190 : : const unsigned int iterations = 1 << iter_shift;
191 : : unsigned int i;
192 : : void *burst = NULL;
193 : : unsigned int n_remaining;
194 : 0 : const unsigned int bulk_n = bulk_sizes[p->ring_params->bulk_sizes_i];
195 : :
196 : 0 : if (rte_atomic_fetch_add_explicit(&lcore_count, 1, rte_memory_order_relaxed) + 1 != 2) {
197 [ # # # # ]: 0 : while (rte_atomic_load_explicit(&lcore_count, rte_memory_order_relaxed) != 2)
198 : : rte_pause();
199 : : }
200 : :
201 : 0 : burst = test_ring_calloc(MAX_BURST, p->ring_params->elem_size);
202 [ # # # # ]: 0 : if (burst == NULL)
203 : : return -1;
204 : :
205 : : const uint64_t sp_start = rte_rdtsc();
206 : 0 : const unsigned int bulk_iterations = iterations / bulk_n;
207 [ # # # # ]: 0 : for (i = 0; i < bulk_iterations; i++) {
208 : : n_remaining = bulk_n;
209 : : do {
210 : : if (flag == 0)
211 : 0 : ret = test_ring_enqueue(p->ring_params->r,
212 : : burst,
213 : 0 : p->ring_params->elem_size,
214 : : n_remaining,
215 : 0 : p->ring_params->ring_flags);
216 : : else if (flag == 1)
217 : 0 : ret = test_ring_dequeue(p->ring_params->r,
218 : : burst,
219 : 0 : p->ring_params->elem_size,
220 : : n_remaining,
221 : 0 : p->ring_params->ring_flags);
222 [ # # # # ]: 0 : if (ret == 0)
223 : : rte_pause();
224 : : else
225 : 0 : n_remaining -= ret;
226 [ # # # # ]: 0 : } while (n_remaining > 0);
227 : : }
228 : : const uint64_t sp_end = rte_rdtsc();
229 : :
230 : 0 : p->results[p->ring_params->bulk_sizes_i] =
231 : 0 : ((double)sp_end - sp_start) / iterations;
232 : :
233 : 0 : return 0;
234 : : }
235 : :
236 : : /*
237 : : * Function that uses rdtsc to measure timing for ring enqueue. Needs pair
238 : : * thread running dequeue_bulk function
239 : : */
240 : : static int
241 [ # # ]: 0 : enqueue_bulk(void *p)
242 : : {
243 : : struct thread_params *params = p;
244 : :
245 : 0 : return enqueue_dequeue_bulk_helper(0, params);
246 : : }
247 : :
248 : : /*
249 : : * Function that uses rdtsc to measure timing for ring dequeue. Needs pair
250 : : * thread running enqueue_bulk function
251 : : */
252 : : static int
253 [ # # ]: 0 : dequeue_bulk(void *p)
254 : : {
255 : : struct thread_params *params = p;
256 : :
257 : 0 : return enqueue_dequeue_bulk_helper(1, params);
258 : : }
259 : :
260 : : /*
261 : : * Function that calls the enqueue and dequeue bulk functions on pairs of cores.
262 : : * used to measure ring perf between hyperthreads, cores and sockets.
263 : : */
264 : : static int
265 : 0 : run_on_core_pair(struct lcore_pair *cores,
266 : : struct thread_params *param1, struct thread_params *param2)
267 : : {
268 : : unsigned i;
269 : 0 : struct ring_params *ring_params = param1->ring_params;
270 : :
271 [ # # ]: 0 : for (i = 0; i < RTE_DIM(bulk_sizes); i++) {
272 : 0 : rte_atomic_store_explicit(&lcore_count, 0, rte_memory_order_relaxed);
273 : 0 : ring_params->bulk_sizes_i = i;
274 [ # # ]: 0 : if (cores->c1 == rte_get_main_lcore()) {
275 : 0 : rte_eal_remote_launch(dequeue_bulk, param2, cores->c2);
276 : 0 : enqueue_bulk(param1);
277 : 0 : rte_eal_wait_lcore(cores->c2);
278 : : } else {
279 : 0 : rte_eal_remote_launch(enqueue_bulk, param1, cores->c1);
280 : 0 : rte_eal_remote_launch(dequeue_bulk, param2, cores->c2);
281 [ # # ]: 0 : if (rte_eal_wait_lcore(cores->c1) < 0)
282 : : return -1;
283 [ # # ]: 0 : if (rte_eal_wait_lcore(cores->c2) < 0)
284 : : return -1;
285 : : }
286 : 0 : test_ring_print_test_string(
287 : : ring_params->ring_flags,
288 : 0 : ring_params->elem_size,
289 : 0 : bulk_sizes[i],
290 : 0 : param1->results[i] + param2->results[i]);
291 : : }
292 : :
293 : : return 0;
294 : : }
295 : :
296 : : static RTE_ATOMIC(uint32_t) synchro;
297 : : static uint64_t queue_count[RTE_MAX_LCORE];
298 : :
299 : : #define TIME_MS 100
300 : :
301 : : static int
302 : 0 : load_loop_fn_helper(struct thread_params *p, const int esize)
303 : : {
304 : : uint64_t time_diff = 0;
305 : : uint64_t begin = 0;
306 : : uint64_t hz = rte_get_timer_hz();
307 : : uint64_t lcount = 0;
308 : : const unsigned int lcore = rte_lcore_id();
309 : 0 : struct ring_params *ring_params = p->ring_params;
310 : : void *burst = NULL;
311 : :
312 : 0 : burst = test_ring_calloc(MAX_BURST, esize);
313 [ # # ]: 0 : if (burst == NULL)
314 : : return -1;
315 : :
316 : : /* wait synchro for workers */
317 [ # # ]: 0 : if (lcore != rte_get_main_lcore())
318 : : rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1,
319 : : rte_memory_order_relaxed);
320 : :
321 : : begin = rte_get_timer_cycles();
322 [ # # ]: 0 : while (time_diff < hz * TIME_MS / 1000) {
323 : 0 : test_ring_enqueue(ring_params->r, burst, esize,
324 : : ring_params->elem_size,
325 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BULK);
326 : 0 : test_ring_dequeue(ring_params->r, burst, esize,
327 : : ring_params->elem_size,
328 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BULK);
329 : 0 : lcount++;
330 : 0 : time_diff = rte_get_timer_cycles() - begin;
331 : : }
332 : 0 : queue_count[lcore] = lcount;
333 : :
334 : 0 : rte_free(burst);
335 : :
336 : 0 : return 0;
337 : : }
338 : :
339 : : static int
340 : 0 : load_loop_fn(void *p)
341 : : {
342 : : struct thread_params *params = p;
343 : :
344 : 0 : return load_loop_fn_helper(params, -1);
345 : : }
346 : :
347 : : static int
348 : 0 : load_loop_fn_16B(void *p)
349 : : {
350 : : struct thread_params *params = p;
351 : :
352 : 0 : return load_loop_fn_helper(params, 16);
353 : : }
354 : :
355 : : static int
356 : 0 : run_on_all_cores(struct rte_ring *r, const int esize)
357 : : {
358 : : uint64_t total;
359 : 0 : struct ring_params ring_params = {0};
360 : 0 : struct thread_params params = { .ring_params = &ring_params };
361 : : lcore_function_t *lcore_f;
362 : : unsigned int i, c;
363 : :
364 [ # # ]: 0 : if (esize == -1)
365 : : lcore_f = load_loop_fn;
366 : : else
367 : : lcore_f = load_loop_fn_16B;
368 : :
369 [ # # ]: 0 : for (i = 0; i < RTE_DIM(bulk_sizes); i++) {
370 : : total = 0;
371 : 0 : printf("\nBulk enq/dequeue count on size %u\n", bulk_sizes[i]);
372 : 0 : params.ring_params->bulk_sizes_i = i;
373 : 0 : params.ring_params->r = r;
374 : :
375 : : /* clear synchro and start workers */
376 : 0 : rte_atomic_store_explicit(&synchro, 0, rte_memory_order_relaxed);
377 [ # # ]: 0 : if (rte_eal_mp_remote_launch(lcore_f, ¶ms, SKIP_MAIN) < 0)
378 : : return -1;
379 : :
380 : : /* start synchro and launch test on main */
381 : 0 : rte_atomic_store_explicit(&synchro, 1, rte_memory_order_relaxed);
382 : 0 : lcore_f(¶ms);
383 : :
384 : 0 : rte_eal_mp_wait_lcore();
385 : :
386 [ # # ]: 0 : RTE_LCORE_FOREACH(c) {
387 : 0 : printf("Core [%u] count = %"PRIu64"\n",
388 : : c, queue_count[c]);
389 : 0 : total += queue_count[c];
390 : : }
391 : :
392 : : printf("Total count (size: %u): %"PRIu64"\n",
393 : 0 : bulk_sizes[i], total);
394 : : }
395 : :
396 : : return 0;
397 : : }
398 : :
399 : : /*
400 : : * Test function that determines how long an enqueue + dequeue of a single item
401 : : * takes on a single lcore. Result is for comparison with the bulk enq+deq.
402 : : */
403 : : static int
404 : 0 : test_single_enqueue_dequeue(struct rte_ring *r, const int esize,
405 : : const unsigned int api_type)
406 : : {
407 : : const unsigned int iter_shift = 24;
408 : : const unsigned int iterations = 1 << iter_shift;
409 : : unsigned int i = 0;
410 : : void *burst = NULL;
411 : :
412 : : /* alloc dummy object pointers */
413 : 0 : burst = test_ring_calloc(1, esize);
414 [ # # ]: 0 : if (burst == NULL)
415 : : return -1;
416 : :
417 : : const uint64_t start = rte_rdtsc();
418 [ # # ]: 0 : for (i = 0; i < iterations; i++) {
419 : 0 : test_ring_enqueue(r, burst, esize, 1, api_type);
420 : 0 : test_ring_dequeue(r, burst, esize, 1, api_type);
421 : : }
422 : : const uint64_t end = rte_rdtsc();
423 : :
424 : 0 : test_ring_print_test_string(api_type, esize, 1,
425 : 0 : ((double)(end - start)) / iterations);
426 : :
427 : 0 : rte_free(burst);
428 : :
429 : 0 : return 0;
430 : : }
431 : :
432 : : /*
433 : : * Test that does both enqueue and dequeue on a core using the burst/bulk API
434 : : * calls Results should be the same as for the bulk function called on a
435 : : * single lcore.
436 : : */
437 : : static int
438 : 0 : test_burst_bulk_enqueue_dequeue(struct rte_ring *r, const int esize,
439 : : const unsigned int api_type)
440 : : {
441 : : const unsigned int iter_shift = 26;
442 : : const unsigned int iterations = 1 << iter_shift;
443 : : unsigned int sz, i;
444 : : void **burst = NULL;
445 : :
446 : 0 : burst = test_ring_calloc(MAX_BURST, esize);
447 [ # # ]: 0 : if (burst == NULL)
448 : : return -1;
449 : :
450 [ # # ]: 0 : for (sz = 0; sz < RTE_DIM(bulk_sizes); sz++) {
451 : 0 : const unsigned int n = iterations / bulk_sizes[sz];
452 : : const uint64_t start = rte_rdtsc();
453 [ # # ]: 0 : for (i = 0; i < n; i++) {
454 : 0 : test_ring_enqueue(r, burst, esize, bulk_sizes[sz],
455 : : api_type);
456 : 0 : test_ring_dequeue(r, burst, esize, bulk_sizes[sz],
457 : : api_type);
458 : : }
459 : : const uint64_t end = rte_rdtsc();
460 : :
461 : 0 : test_ring_print_test_string(api_type, esize, bulk_sizes[sz],
462 : 0 : ((double)end - start) / iterations);
463 : : }
464 : :
465 : 0 : rte_free(burst);
466 : :
467 : 0 : return 0;
468 : : }
469 : :
470 : : static __rte_always_inline int
471 : : test_ring_perf_esize_run_on_two_cores(
472 : : struct thread_params *param1, struct thread_params *param2)
473 : : {
474 : : struct lcore_pair cores;
475 : :
476 [ # # # # : 0 : if (get_two_hyperthreads(&cores) == 0) {
# # # # ]
477 : : printf("\n### Testing using two hyperthreads ###\n");
478 [ # # # # : 0 : if (run_on_core_pair(&cores, param1, param2) < 0)
# # # # ]
479 : : return -1;
480 : : }
481 [ # # # # : 0 : if (get_two_cores(&cores) == 0) {
# # # # ]
482 : : printf("\n### Testing using two physical cores ###\n");
483 [ # # # # : 0 : if (run_on_core_pair(&cores, param1, param2) < 0)
# # # # ]
484 : : return -1;
485 : : }
486 [ # # # # : 0 : if (get_two_sockets(&cores) == 0) {
# # # # ]
487 : : printf("\n### Testing using two NUMA nodes ###\n");
488 : 0 : if (run_on_core_pair(&cores, param1, param2) < 0)
489 : : return -1;
490 : : }
491 : : return 0;
492 : : }
493 : :
494 : : /* Run all tests for a given element size */
495 : : static __rte_always_inline int
496 : : test_ring_perf_esize(const int esize)
497 : : {
498 : : struct rte_ring *r = NULL;
499 : : double results_enq[RTE_DIM(bulk_sizes)];
500 : : double results_deq[RTE_DIM(bulk_sizes)];
501 : 0 : struct ring_params ring_params = {
502 : : .elem_size = esize, .ring_flags = TEST_RING_ELEM_BULK };
503 : 0 : struct thread_params param1 = {
504 : : .ring_params = &ring_params, .results = results_enq };
505 : 0 : struct thread_params param2 = {
506 : : .ring_params = &ring_params, .results = results_deq };
507 : :
508 : : /*
509 : : * Performance test for legacy/_elem APIs
510 : : * SP-SC/MP-MC, single
511 : : */
512 : 0 : r = test_ring_create(RING_NAME, esize, RING_SIZE, rte_socket_id(), 0);
513 [ # # # # ]: 0 : if (r == NULL)
514 : 0 : goto test_fail;
515 : :
516 : : printf("\n### Testing single element enq/deq ###\n");
517 [ # # # # ]: 0 : if (test_single_enqueue_dequeue(r, esize,
518 : : TEST_RING_THREAD_SPSC | TEST_RING_ELEM_SINGLE) < 0)
519 : 0 : goto test_fail;
520 [ # # # # ]: 0 : if (test_single_enqueue_dequeue(r, esize,
521 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_SINGLE) < 0)
522 : 0 : goto test_fail;
523 : :
524 : : printf("\n### Testing burst enq/deq ###\n");
525 [ # # # # ]: 0 : if (test_burst_bulk_enqueue_dequeue(r, esize,
526 : : TEST_RING_THREAD_SPSC | TEST_RING_ELEM_BURST) < 0)
527 : 0 : goto test_fail;
528 [ # # # # ]: 0 : if (test_burst_bulk_enqueue_dequeue(r, esize,
529 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BURST) < 0)
530 : 0 : goto test_fail;
531 : :
532 : : printf("\n### Testing bulk enq/deq ###\n");
533 [ # # # # ]: 0 : if (test_burst_bulk_enqueue_dequeue(r, esize,
534 : : TEST_RING_THREAD_SPSC | TEST_RING_ELEM_BULK) < 0)
535 : 0 : goto test_fail;
536 [ # # # # ]: 0 : if (test_burst_bulk_enqueue_dequeue(r, esize,
537 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BULK) < 0)
538 : 0 : goto test_fail;
539 : :
540 : : printf("\n### Testing empty bulk deq ###\n");
541 : 0 : test_empty_dequeue(r, esize,
542 : : TEST_RING_THREAD_SPSC | TEST_RING_ELEM_BULK);
543 : 0 : test_empty_dequeue(r, esize,
544 : : TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BULK);
545 : :
546 : 0 : ring_params.r = r;
547 : :
548 : 0 : ring_params.ring_flags = TEST_RING_THREAD_SPSC | TEST_RING_ELEM_BULK;
549 : : test_ring_perf_esize_run_on_two_cores(¶m1, ¶m2);
550 : :
551 : 0 : ring_params.ring_flags = TEST_RING_THREAD_MPMC | TEST_RING_ELEM_BULK;
552 : : test_ring_perf_esize_run_on_two_cores(¶m1, ¶m2);
553 : :
554 : : printf("\n### Testing using all worker nodes ###\n");
555 [ # # # # ]: 0 : if (run_on_all_cores(r, esize) < 0)
556 : 0 : goto test_fail;
557 : :
558 : 0 : rte_ring_free(r);
559 : :
560 : : return 0;
561 : :
562 : 0 : test_fail:
563 : 0 : rte_ring_free(r);
564 : :
565 : : return -1;
566 : : }
567 : :
568 : :
569 : : static __rte_always_inline int
570 : : test_ring_perf_compression(void)
571 : : {
572 : : double results1[RTE_DIM(bulk_sizes)];
573 : : double results2[RTE_DIM(bulk_sizes)];
574 : : double results1_comp[2][RTE_DIM(bulk_sizes)];
575 : : double results2_comp[2][RTE_DIM(bulk_sizes)];
576 : :
577 : : struct lcore_pair cores;
578 : : int ret = -1;
579 : : unsigned int i, j;
580 : 0 : struct ring_params ring_params = { .elem_size = sizeof(void *) };
581 : 0 : struct thread_params param1 = {
582 : : .ring_params = &ring_params, .results = results1 };
583 : 0 : struct thread_params param2 = {
584 : : .ring_params = &ring_params, .results = results2 };
585 : :
586 : : printf("\n### Testing compression gain ###");
587 : :
588 : 0 : ring_params.r = rte_ring_create_elem(
589 : : RING_NAME, sizeof(void *),
590 : 0 : RING_SIZE, rte_socket_id(),
591 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
592 : :
593 [ # # ]: 0 : if (ring_params.r == NULL)
594 : : return -1;
595 : :
596 [ # # ]: 0 : if (get_two_cores(&cores) == 0) {
597 : : printf("\n### Testing zero copy ###\n");
598 : 0 : ring_params.ring_flags = TEST_RING_ELEM_BURST_ZC;
599 : 0 : ret = run_on_core_pair(&cores, ¶m1, ¶m2);
600 : : }
601 : :
602 : 0 : rte_ring_free(ring_params.r);
603 : :
604 [ # # ]: 0 : if (ret != 0)
605 : : return ret;
606 : :
607 : : /* rings allow only multiples of 4 as sizes,
608 : : * we allocate size 4 despite only using 2 bytes
609 : : * and use half of RING_SIZE as the number of elements
610 : : */
611 : 0 : ring_params.r = rte_ring_create_elem(
612 : : RING_NAME, sizeof(uint32_t),
613 : 0 : RING_SIZE / 2, rte_socket_id(),
614 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
615 : :
616 [ # # ]: 0 : if (ring_params.r == NULL)
617 : : return -1;
618 : :
619 : 0 : param1.results = results1_comp[0];
620 : 0 : param2.results = results2_comp[0];
621 : :
622 [ # # ]: 0 : if (get_two_cores(&cores) == 0) {
623 : : printf("\n### Testing zero copy with compression (16b) ###\n");
624 : 0 : ring_params.ring_flags =
625 : : TEST_RING_ELEM_BURST_ZC_COMPRESS_PTR_16;
626 : 0 : ret = run_on_core_pair(&cores, ¶m1, ¶m2);
627 : : }
628 : :
629 : 0 : rte_ring_free(ring_params.r);
630 : :
631 [ # # ]: 0 : if (ret != 0)
632 : : return ret;
633 : :
634 : 0 : ring_params.r = rte_ring_create_elem(
635 : : RING_NAME, sizeof(uint32_t),
636 : 0 : RING_SIZE, rte_socket_id(),
637 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
638 : :
639 [ # # ]: 0 : if (ring_params.r == NULL)
640 : : return -1;
641 : :
642 : 0 : param1.results = results1_comp[1];
643 : 0 : param2.results = results2_comp[1];
644 : :
645 [ # # ]: 0 : if (get_two_cores(&cores) == 0) {
646 : : printf("\n### Testing zero copy with compression (32b) ###\n");
647 : 0 : ring_params.ring_flags =
648 : : TEST_RING_ELEM_BURST_ZC_COMPRESS_PTR_32;
649 : 0 : ret = run_on_core_pair(&cores, ¶m1, ¶m2);
650 : : }
651 : :
652 : 0 : rte_ring_free(ring_params.r);
653 : :
654 [ # # ]: 0 : for (j = 0; j < 2; j++) {
655 : 0 : printf("\n### Potential gain from compression (%d-bit offsets) "
656 : 0 : "###\n", (j + 1) * 16);
657 [ # # ]: 0 : for (i = 0; i < RTE_DIM(bulk_sizes); i++) {
658 : 0 : const double result = results1[i] + results2[i];
659 : 0 : const double result_comp = results1_comp[j][i] +
660 : 0 : results2_comp[j][i];
661 : 0 : const double gain = 100 - (result_comp / result) * 100;
662 : :
663 : : printf("Gain of %5.1F%% for burst of %-3u elems\n",
664 : 0 : gain, bulk_sizes[i]);
665 : : }
666 : : }
667 : :
668 : : return ret;
669 : : }
670 : :
671 : : static int
672 : 0 : test_ring_perf(void)
673 : : {
674 : : /* Run all the tests for different element sizes */
675 : : if (test_ring_perf_esize(-1) == -1)
676 : 0 : return -1;
677 : :
678 : : if (test_ring_perf_esize(16) == -1)
679 : 0 : return -1;
680 : :
681 : : /* Test for performance gain of compression */
682 [ # # ]: 0 : if (test_ring_perf_compression() == -1)
683 : 0 : return -1;
684 : :
685 : : return 0;
686 : : }
687 : :
688 : 252 : REGISTER_PERF_TEST(ring_perf_autotest, test_ring_perf);
|