Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2018 Arm Limited
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdbool.h>
7 : : #include <inttypes.h>
8 : : #include <rte_pause.h>
9 : : #include <rte_rcu_qsbr.h>
10 : : #include <rte_hash.h>
11 : : #include <rte_hash_crc.h>
12 : : #include <rte_malloc.h>
13 : : #include <rte_cycles.h>
14 : : #include <unistd.h>
15 : :
16 : : #include "test.h"
17 : :
18 : : /* Check condition and return an error if true. */
19 : : static uint16_t enabled_core_ids[RTE_MAX_LCORE];
20 : : static unsigned int num_cores;
21 : :
22 : : static uint32_t *keys;
23 : : #define TOTAL_ENTRY (1024 * 8)
24 : : #define COUNTER_VALUE 4096
25 : : static uint32_t *hash_data[TOTAL_ENTRY];
26 : : static volatile uint8_t writer_done;
27 : : static volatile uint8_t all_registered;
28 : : static volatile RTE_ATOMIC(uint32_t) thr_id;
29 : :
30 : : static struct rte_rcu_qsbr *t[RTE_MAX_LCORE];
31 : : static struct rte_hash *h;
32 : : static char hash_name[8];
33 : : static RTE_ATOMIC(uint64_t) updates;
34 : : static RTE_ATOMIC(uint64_t) checks;
35 : : static RTE_ATOMIC(uint64_t) update_cycles;
36 : : static RTE_ATOMIC(uint64_t) check_cycles;
37 : :
38 : : /* Scale down results to 1000 operations to support lower
39 : : * granularity clocks.
40 : : */
41 : : #define RCU_SCALE_DOWN 1000
42 : :
43 : : /* Simple way to allocate thread ids in 0 to RTE_MAX_LCORE space */
44 : : static inline uint32_t
45 : 0 : alloc_thread_id(void)
46 : : {
47 : : uint32_t tmp_thr_id;
48 : :
49 : 0 : tmp_thr_id = rte_atomic_fetch_add_explicit(&thr_id, 1, rte_memory_order_relaxed);
50 [ # # ]: 0 : if (tmp_thr_id >= RTE_MAX_LCORE)
51 : : printf("Invalid thread id %u\n", tmp_thr_id);
52 : :
53 : 0 : return tmp_thr_id;
54 : : }
55 : :
56 : : static int
57 : 0 : test_rcu_qsbr_reader_perf(void *arg)
58 : : {
59 : : bool writer_present = (bool)arg;
60 : 0 : uint32_t thread_id = alloc_thread_id();
61 : : uint64_t loop_cnt = 0;
62 : : uint64_t begin, cycles;
63 : :
64 : : /* Register for report QS */
65 : 0 : rte_rcu_qsbr_thread_register(t[0], thread_id);
66 : : /* Make the thread online */
67 : 0 : rte_rcu_qsbr_thread_online(t[0], thread_id);
68 : :
69 : : begin = rte_rdtsc_precise();
70 : :
71 [ # # ]: 0 : if (writer_present) {
72 [ # # ]: 0 : while (!writer_done) {
73 : : /* Update quiescent state counter */
74 [ # # ]: 0 : rte_rcu_qsbr_quiescent(t[0], thread_id);
75 : 0 : loop_cnt++;
76 : : }
77 : : } else {
78 [ # # ]: 0 : while (loop_cnt < 100000000) {
79 : : /* Update quiescent state counter */
80 [ # # ]: 0 : rte_rcu_qsbr_quiescent(t[0], thread_id);
81 : 0 : loop_cnt++;
82 : : }
83 : : }
84 : :
85 : 0 : cycles = rte_rdtsc_precise() - begin;
86 : 0 : rte_atomic_fetch_add_explicit(&update_cycles, cycles, rte_memory_order_relaxed);
87 : 0 : rte_atomic_fetch_add_explicit(&updates, loop_cnt, rte_memory_order_relaxed);
88 : :
89 : : /* Make the thread offline */
90 : 0 : rte_rcu_qsbr_thread_offline(t[0], thread_id);
91 : : /* Unregister before exiting to avoid writer from waiting */
92 : 0 : rte_rcu_qsbr_thread_unregister(t[0], thread_id);
93 : :
94 : 0 : return 0;
95 : : }
96 : :
97 : : static int
98 : 0 : test_rcu_qsbr_writer_perf(void *arg)
99 : : {
100 : : bool wait = (bool)arg;
101 : : uint64_t token = 0;
102 : : uint64_t loop_cnt = 0;
103 : : uint64_t begin, cycles;
104 : :
105 : : begin = rte_rdtsc_precise();
106 : :
107 : : do {
108 : : /* Start the quiescent state query process */
109 [ # # ]: 0 : if (wait)
110 : 0 : token = rte_rcu_qsbr_start(t[0]);
111 : :
112 : : /* Check quiescent state status */
113 [ # # ]: 0 : rte_rcu_qsbr_check(t[0], token, wait);
114 : 0 : loop_cnt++;
115 [ # # ]: 0 : } while (loop_cnt < 20000000);
116 : :
117 : 0 : cycles = rte_rdtsc_precise() - begin;
118 : 0 : rte_atomic_fetch_add_explicit(&check_cycles, cycles, rte_memory_order_relaxed);
119 : 0 : rte_atomic_fetch_add_explicit(&checks, loop_cnt, rte_memory_order_relaxed);
120 : 0 : return 0;
121 : : }
122 : :
123 : : /*
124 : : * Perf test: Reader/writer
125 : : * Single writer, Multiple Readers, Single QS var, Non-Blocking rcu_qsbr_check
126 : : */
127 : : static int
128 : 0 : test_rcu_qsbr_perf(void)
129 : : {
130 : : size_t sz;
131 : : unsigned int i, tmp_num_cores;
132 : :
133 : 0 : writer_done = 0;
134 : :
135 : 0 : rte_atomic_store_explicit(&updates, 0, rte_memory_order_relaxed);
136 : 0 : rte_atomic_store_explicit(&update_cycles, 0, rte_memory_order_relaxed);
137 : 0 : rte_atomic_store_explicit(&checks, 0, rte_memory_order_relaxed);
138 : 0 : rte_atomic_store_explicit(&check_cycles, 0, rte_memory_order_relaxed);
139 : :
140 : 0 : printf("\nPerf Test: %d Readers/1 Writer('wait' in qsbr_check == true)\n",
141 : : num_cores - 1);
142 : :
143 : 0 : rte_atomic_store_explicit(&thr_id, 0, rte_memory_order_seq_cst);
144 : :
145 [ # # ]: 0 : if (all_registered == 1)
146 : 0 : tmp_num_cores = num_cores - 1;
147 : : else
148 : : tmp_num_cores = RTE_MAX_LCORE;
149 : :
150 : 0 : sz = rte_rcu_qsbr_get_memsize(tmp_num_cores);
151 : 0 : t[0] = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
152 : : RTE_CACHE_LINE_SIZE);
153 : : /* QS variable is initialized */
154 : 0 : rte_rcu_qsbr_init(t[0], tmp_num_cores);
155 : :
156 : : /* Reader threads are launched */
157 [ # # ]: 0 : for (i = 0; i < num_cores - 1; i++)
158 : 0 : rte_eal_remote_launch(test_rcu_qsbr_reader_perf, (void *)1,
159 : 0 : enabled_core_ids[i]);
160 : :
161 : : /* Writer thread is launched */
162 : 0 : rte_eal_remote_launch(test_rcu_qsbr_writer_perf,
163 : 0 : (void *)1, enabled_core_ids[i]);
164 : :
165 : : /* Wait for the writer thread */
166 : 0 : rte_eal_wait_lcore(enabled_core_ids[i]);
167 : 0 : writer_done = 1;
168 : :
169 : : /* Wait until all readers have exited */
170 : 0 : rte_eal_mp_wait_lcore();
171 : :
172 : 0 : printf("Total quiescent state updates = %"PRIi64"\n",
173 : : rte_atomic_load_explicit(&updates, rte_memory_order_relaxed));
174 : 0 : printf("Cycles per %d quiescent state updates: %"PRIi64"\n",
175 : : RCU_SCALE_DOWN,
176 : 0 : rte_atomic_load_explicit(&update_cycles, rte_memory_order_relaxed) /
177 : 0 : (rte_atomic_load_explicit(&updates, rte_memory_order_relaxed) / RCU_SCALE_DOWN));
178 : 0 : printf("Total RCU checks = %"PRIi64"\n", rte_atomic_load_explicit(&checks,
179 : : rte_memory_order_relaxed));
180 : 0 : printf("Cycles per %d checks: %"PRIi64"\n", RCU_SCALE_DOWN,
181 : 0 : rte_atomic_load_explicit(&check_cycles, rte_memory_order_relaxed) /
182 : 0 : (rte_atomic_load_explicit(&checks, rte_memory_order_relaxed) / RCU_SCALE_DOWN));
183 : :
184 : 0 : rte_free(t[0]);
185 : :
186 : 0 : return 0;
187 : : }
188 : :
189 : : /*
190 : : * Perf test: Readers
191 : : * Single writer, Multiple readers, Single QS variable
192 : : */
193 : : static int
194 : 0 : test_rcu_qsbr_rperf(void)
195 : : {
196 : : size_t sz;
197 : : unsigned int i, tmp_num_cores;
198 : :
199 : 0 : rte_atomic_store_explicit(&updates, 0, rte_memory_order_relaxed);
200 : 0 : rte_atomic_store_explicit(&update_cycles, 0, rte_memory_order_relaxed);
201 : :
202 : 0 : rte_atomic_store_explicit(&thr_id, 0, rte_memory_order_seq_cst);
203 : :
204 : 0 : printf("\nPerf Test: %d Readers\n", num_cores);
205 : :
206 [ # # ]: 0 : if (all_registered == 1)
207 : 0 : tmp_num_cores = num_cores;
208 : : else
209 : : tmp_num_cores = RTE_MAX_LCORE;
210 : :
211 : 0 : sz = rte_rcu_qsbr_get_memsize(tmp_num_cores);
212 : 0 : t[0] = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
213 : : RTE_CACHE_LINE_SIZE);
214 : : /* QS variable is initialized */
215 : 0 : rte_rcu_qsbr_init(t[0], tmp_num_cores);
216 : :
217 : : /* Reader threads are launched */
218 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
219 : 0 : rte_eal_remote_launch(test_rcu_qsbr_reader_perf, NULL,
220 : 0 : enabled_core_ids[i]);
221 : :
222 : : /* Wait until all readers have exited */
223 : 0 : rte_eal_mp_wait_lcore();
224 : :
225 : 0 : printf("Total quiescent state updates = %"PRIi64"\n",
226 : : rte_atomic_load_explicit(&updates, rte_memory_order_relaxed));
227 : 0 : printf("Cycles per %d quiescent state updates: %"PRIi64"\n",
228 : : RCU_SCALE_DOWN,
229 : 0 : rte_atomic_load_explicit(&update_cycles, rte_memory_order_relaxed) /
230 : 0 : (rte_atomic_load_explicit(&updates, rte_memory_order_relaxed) / RCU_SCALE_DOWN));
231 : :
232 : 0 : rte_free(t[0]);
233 : :
234 : 0 : return 0;
235 : : }
236 : :
237 : : /*
238 : : * Perf test:
239 : : * Multiple writer, Single QS variable, Non-blocking rcu_qsbr_check
240 : : */
241 : : static int
242 : 0 : test_rcu_qsbr_wperf(void)
243 : : {
244 : : size_t sz;
245 : : unsigned int i;
246 : :
247 : 0 : rte_atomic_store_explicit(&checks, 0, rte_memory_order_relaxed);
248 : 0 : rte_atomic_store_explicit(&check_cycles, 0, rte_memory_order_relaxed);
249 : :
250 : 0 : rte_atomic_store_explicit(&thr_id, 0, rte_memory_order_seq_cst);
251 : :
252 : 0 : printf("\nPerf test: %d Writers ('wait' in qsbr_check == false)\n",
253 : : num_cores);
254 : :
255 : : /* Number of readers does not matter for QS variable in this test
256 : : * case as no reader will be registered.
257 : : */
258 : 0 : sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
259 : 0 : t[0] = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
260 : : RTE_CACHE_LINE_SIZE);
261 : : /* QS variable is initialized */
262 : 0 : rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
263 : :
264 : : /* Writer threads are launched */
265 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
266 : 0 : rte_eal_remote_launch(test_rcu_qsbr_writer_perf,
267 : 0 : (void *)0, enabled_core_ids[i]);
268 : :
269 : : /* Wait until all readers have exited */
270 : 0 : rte_eal_mp_wait_lcore();
271 : :
272 : 0 : printf("Total RCU checks = %"PRIi64"\n", rte_atomic_load_explicit(&checks,
273 : : rte_memory_order_relaxed));
274 : 0 : printf("Cycles per %d checks: %"PRIi64"\n", RCU_SCALE_DOWN,
275 : 0 : rte_atomic_load_explicit(&check_cycles, rte_memory_order_relaxed) /
276 : 0 : (rte_atomic_load_explicit(&checks, rte_memory_order_relaxed) / RCU_SCALE_DOWN));
277 : :
278 : 0 : rte_free(t[0]);
279 : :
280 : 0 : return 0;
281 : : }
282 : :
283 : : /*
284 : : * RCU test cases using rte_hash data structure.
285 : : */
286 : : static int
287 : 0 : test_rcu_qsbr_hash_reader(void *arg)
288 : : {
289 : : struct rte_rcu_qsbr *temp;
290 : : struct rte_hash *hash = NULL;
291 : : int i;
292 : : uint64_t loop_cnt = 0;
293 : : uint64_t begin, cycles;
294 : 0 : uint32_t thread_id = alloc_thread_id();
295 : 0 : uint8_t read_type = (uint8_t)((uintptr_t)arg);
296 : : uint32_t *pdata;
297 : :
298 : 0 : temp = t[read_type];
299 : 0 : hash = h;
300 : :
301 : 0 : rte_rcu_qsbr_thread_register(temp, thread_id);
302 : :
303 : : begin = rte_rdtsc_precise();
304 : :
305 : : do {
306 : : rte_rcu_qsbr_thread_online(temp, thread_id);
307 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++) {
308 : : rte_rcu_qsbr_lock(temp, thread_id);
309 [ # # ]: 0 : if (rte_hash_lookup_data(hash, keys + i,
310 : : (void **)&pdata) != -ENOENT) {
311 : 0 : pdata[thread_id] = 0;
312 [ # # ]: 0 : while (pdata[thread_id] < COUNTER_VALUE)
313 : 0 : pdata[thread_id]++;
314 : : }
315 : : rte_rcu_qsbr_unlock(temp, thread_id);
316 : : }
317 : : /* Update quiescent state counter */
318 : : rte_rcu_qsbr_quiescent(temp, thread_id);
319 : : rte_rcu_qsbr_thread_offline(temp, thread_id);
320 : 0 : loop_cnt++;
321 [ # # ]: 0 : } while (!writer_done);
322 : :
323 : 0 : cycles = rte_rdtsc_precise() - begin;
324 : 0 : rte_atomic_fetch_add_explicit(&update_cycles, cycles, rte_memory_order_relaxed);
325 : 0 : rte_atomic_fetch_add_explicit(&updates, loop_cnt, rte_memory_order_relaxed);
326 : :
327 : 0 : rte_rcu_qsbr_thread_unregister(temp, thread_id);
328 : :
329 : 0 : return 0;
330 : : }
331 : :
332 : 0 : static struct rte_hash *init_hash(void)
333 : : {
334 : : int i;
335 : : struct rte_hash *hash = NULL;
336 : :
337 : : snprintf(hash_name, 8, "hash");
338 : 0 : struct rte_hash_parameters hash_params = {
339 : : .entries = TOTAL_ENTRY,
340 : : .key_len = sizeof(uint32_t),
341 : : .hash_func_init_val = 0,
342 : 0 : .socket_id = rte_socket_id(),
343 : : .hash_func = rte_hash_crc,
344 : : .extra_flag =
345 : : RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
346 : : .name = hash_name,
347 : : };
348 : :
349 : 0 : hash = rte_hash_create(&hash_params);
350 [ # # ]: 0 : if (hash == NULL) {
351 : : printf("Hash create Failed\n");
352 : 0 : return NULL;
353 : : }
354 : :
355 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++) {
356 : 0 : hash_data[i] = rte_zmalloc(NULL,
357 : : sizeof(uint32_t) * RTE_MAX_LCORE, 0);
358 [ # # ]: 0 : if (hash_data[i] == NULL) {
359 : : printf("No memory\n");
360 : 0 : return NULL;
361 : : }
362 : : }
363 : 0 : keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
364 [ # # ]: 0 : if (keys == NULL) {
365 : : printf("No memory\n");
366 : 0 : return NULL;
367 : : }
368 : :
369 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++)
370 : 0 : keys[i] = i;
371 : :
372 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++) {
373 [ # # ]: 0 : if (rte_hash_add_key_data(hash, keys + i,
374 : 0 : (void *)((uintptr_t)hash_data[i])) < 0) {
375 : : printf("Hash key add Failed #%d\n", i);
376 : 0 : return NULL;
377 : : }
378 : : }
379 : : return hash;
380 : : }
381 : :
382 : : /*
383 : : * Functional test:
384 : : * Single writer, Single QS variable Single QSBR query, Blocking rcu_qsbr_check
385 : : */
386 : : static int
387 : 0 : test_rcu_qsbr_sw_sv_1qs(void)
388 : : {
389 : : uint64_t token, begin, cycles;
390 : : size_t sz;
391 : : unsigned int i, j, tmp_num_cores;
392 : : int32_t pos;
393 : :
394 : 0 : writer_done = 0;
395 : :
396 : 0 : rte_atomic_store_explicit(&updates, 0, rte_memory_order_relaxed);
397 : 0 : rte_atomic_store_explicit(&update_cycles, 0, rte_memory_order_relaxed);
398 : 0 : rte_atomic_store_explicit(&checks, 0, rte_memory_order_relaxed);
399 : 0 : rte_atomic_store_explicit(&check_cycles, 0, rte_memory_order_relaxed);
400 : :
401 : 0 : rte_atomic_store_explicit(&thr_id, 0, rte_memory_order_seq_cst);
402 : :
403 : 0 : printf("\nPerf test: 1 writer, %d readers, 1 QSBR variable, 1 QSBR Query, Blocking QSBR Check\n", num_cores);
404 : :
405 [ # # ]: 0 : if (all_registered == 1)
406 : 0 : tmp_num_cores = num_cores;
407 : : else
408 : : tmp_num_cores = RTE_MAX_LCORE;
409 : :
410 : 0 : sz = rte_rcu_qsbr_get_memsize(tmp_num_cores);
411 : 0 : t[0] = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
412 : : RTE_CACHE_LINE_SIZE);
413 : : /* QS variable is initialized */
414 : 0 : rte_rcu_qsbr_init(t[0], tmp_num_cores);
415 : :
416 : : /* Shared data structure created */
417 : 0 : h = init_hash();
418 [ # # ]: 0 : if (h == NULL) {
419 : : printf("Hash init failed\n");
420 : 0 : goto error;
421 : : }
422 : :
423 : : /* Reader threads are launched */
424 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
425 : 0 : rte_eal_remote_launch(test_rcu_qsbr_hash_reader, NULL,
426 : 0 : enabled_core_ids[i]);
427 : :
428 : : begin = rte_rdtsc_precise();
429 : :
430 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++) {
431 : : /* Delete elements from the shared data structure */
432 : 0 : pos = rte_hash_del_key(h, keys + i);
433 [ # # ]: 0 : if (pos < 0) {
434 : 0 : printf("Delete key failed #%d\n", keys[i]);
435 : 0 : goto error;
436 : : }
437 : : /* Start the quiescent state query process */
438 [ # # ]: 0 : token = rte_rcu_qsbr_start(t[0]);
439 : :
440 : : /* Check the quiescent state status */
441 [ # # ]: 0 : rte_rcu_qsbr_check(t[0], token, true);
442 [ # # ]: 0 : for (j = 0; j < tmp_num_cores; j++) {
443 [ # # ]: 0 : if (hash_data[i][j] != COUNTER_VALUE &&
444 : : hash_data[i][j] != 0) {
445 : : printf("Reader thread ID %u did not complete #%d = %d\n",
446 : : j, i, hash_data[i][j]);
447 : 0 : goto error;
448 : : }
449 : : }
450 : :
451 [ # # ]: 0 : if (rte_hash_free_key_with_position(h, pos) < 0) {
452 : 0 : printf("Failed to free the key #%d\n", keys[i]);
453 : 0 : goto error;
454 : : }
455 : 0 : rte_free(hash_data[i]);
456 : 0 : hash_data[i] = NULL;
457 : : }
458 : :
459 : 0 : cycles = rte_rdtsc_precise() - begin;
460 : 0 : rte_atomic_fetch_add_explicit(&check_cycles, cycles, rte_memory_order_relaxed);
461 : 0 : rte_atomic_fetch_add_explicit(&checks, i, rte_memory_order_relaxed);
462 : :
463 : 0 : writer_done = 1;
464 : :
465 : : /* Wait and check return value from reader threads */
466 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
467 [ # # ]: 0 : if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
468 : 0 : goto error;
469 : 0 : rte_hash_free(h);
470 : 0 : rte_free(keys);
471 : :
472 : : printf("Following numbers include calls to rte_hash functions\n");
473 : 0 : printf("Cycles per 1 quiescent state update(online/update/offline): %"PRIi64"\n",
474 : 0 : rte_atomic_load_explicit(&update_cycles, rte_memory_order_relaxed) /
475 : 0 : rte_atomic_load_explicit(&updates, rte_memory_order_relaxed));
476 : :
477 : 0 : printf("Cycles per 1 check(start, check): %"PRIi64"\n\n",
478 : 0 : rte_atomic_load_explicit(&check_cycles, rte_memory_order_relaxed) /
479 : 0 : rte_atomic_load_explicit(&checks, rte_memory_order_relaxed));
480 : :
481 : 0 : rte_free(t[0]);
482 : :
483 : 0 : return 0;
484 : :
485 : 0 : error:
486 : 0 : writer_done = 1;
487 : : /* Wait until all readers have exited */
488 : 0 : rte_eal_mp_wait_lcore();
489 : :
490 : 0 : rte_hash_free(h);
491 : 0 : rte_free(keys);
492 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++)
493 : 0 : rte_free(hash_data[i]);
494 : :
495 : 0 : rte_free(t[0]);
496 : :
497 : 0 : return -1;
498 : : }
499 : :
500 : : /*
501 : : * Functional test:
502 : : * Single writer, Single QS variable, Single QSBR query,
503 : : * Non-blocking rcu_qsbr_check
504 : : */
505 : : static int
506 : 0 : test_rcu_qsbr_sw_sv_1qs_non_blocking(void)
507 : : {
508 : : uint64_t token, begin, cycles;
509 : : int ret;
510 : : size_t sz;
511 : : unsigned int i, j, tmp_num_cores;
512 : : int32_t pos;
513 : :
514 : 0 : writer_done = 0;
515 : :
516 : 0 : printf("Perf test: 1 writer, %d readers, 1 QSBR variable, 1 QSBR Query, Non-Blocking QSBR check\n", num_cores);
517 : :
518 : 0 : rte_atomic_store_explicit(&thr_id, 0, rte_memory_order_relaxed);
519 : :
520 [ # # ]: 0 : if (all_registered == 1)
521 : 0 : tmp_num_cores = num_cores;
522 : : else
523 : : tmp_num_cores = RTE_MAX_LCORE;
524 : :
525 : 0 : sz = rte_rcu_qsbr_get_memsize(tmp_num_cores);
526 : 0 : t[0] = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
527 : : RTE_CACHE_LINE_SIZE);
528 : : /* QS variable is initialized */
529 : 0 : rte_rcu_qsbr_init(t[0], tmp_num_cores);
530 : :
531 : : /* Shared data structure created */
532 : 0 : h = init_hash();
533 [ # # ]: 0 : if (h == NULL) {
534 : : printf("Hash init failed\n");
535 : 0 : goto error;
536 : : }
537 : :
538 : : /* Reader threads are launched */
539 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
540 : 0 : rte_eal_remote_launch(test_rcu_qsbr_hash_reader, NULL,
541 : 0 : enabled_core_ids[i]);
542 : :
543 : : begin = rte_rdtsc_precise();
544 : :
545 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++) {
546 : : /* Delete elements from the shared data structure */
547 : 0 : pos = rte_hash_del_key(h, keys + i);
548 [ # # ]: 0 : if (pos < 0) {
549 : 0 : printf("Delete key failed #%d\n", keys[i]);
550 : 0 : goto error;
551 : : }
552 : : /* Start the quiescent state query process */
553 : 0 : token = rte_rcu_qsbr_start(t[0]);
554 : :
555 : : /* Check the quiescent state status */
556 : : do {
557 [ # # ]: 0 : ret = rte_rcu_qsbr_check(t[0], token, false);
558 : : } while (ret == 0);
559 [ # # ]: 0 : for (j = 0; j < tmp_num_cores; j++) {
560 [ # # ]: 0 : if (hash_data[i][j] != COUNTER_VALUE &&
561 : : hash_data[i][j] != 0) {
562 : : printf("Reader thread ID %u did not complete #%d = %d\n",
563 : : j, i, hash_data[i][j]);
564 : 0 : goto error;
565 : : }
566 : : }
567 : :
568 [ # # ]: 0 : if (rte_hash_free_key_with_position(h, pos) < 0) {
569 : 0 : printf("Failed to free the key #%d\n", keys[i]);
570 : 0 : goto error;
571 : : }
572 : 0 : rte_free(hash_data[i]);
573 : 0 : hash_data[i] = NULL;
574 : : }
575 : :
576 : 0 : cycles = rte_rdtsc_precise() - begin;
577 : 0 : rte_atomic_fetch_add_explicit(&check_cycles, cycles, rte_memory_order_relaxed);
578 : 0 : rte_atomic_fetch_add_explicit(&checks, i, rte_memory_order_relaxed);
579 : :
580 : 0 : writer_done = 1;
581 : : /* Wait and check return value from reader threads */
582 [ # # ]: 0 : for (i = 0; i < num_cores; i++)
583 [ # # ]: 0 : if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
584 : 0 : goto error;
585 : 0 : rte_hash_free(h);
586 : 0 : rte_free(keys);
587 : :
588 : : printf("Following numbers include calls to rte_hash functions\n");
589 : 0 : printf("Cycles per 1 quiescent state update(online/update/offline): %"PRIi64"\n",
590 : 0 : rte_atomic_load_explicit(&update_cycles, rte_memory_order_relaxed) /
591 : 0 : rte_atomic_load_explicit(&updates, rte_memory_order_relaxed));
592 : :
593 : 0 : printf("Cycles per 1 check(start, check): %"PRIi64"\n\n",
594 : 0 : rte_atomic_load_explicit(&check_cycles, rte_memory_order_relaxed) /
595 : 0 : rte_atomic_load_explicit(&checks, rte_memory_order_relaxed));
596 : :
597 : 0 : rte_free(t[0]);
598 : :
599 : 0 : return 0;
600 : :
601 : 0 : error:
602 : 0 : writer_done = 1;
603 : : /* Wait until all readers have exited */
604 : 0 : rte_eal_mp_wait_lcore();
605 : :
606 : 0 : rte_hash_free(h);
607 : 0 : rte_free(keys);
608 [ # # ]: 0 : for (i = 0; i < TOTAL_ENTRY; i++)
609 : 0 : rte_free(hash_data[i]);
610 : :
611 : 0 : rte_free(t[0]);
612 : :
613 : 0 : return -1;
614 : : }
615 : :
616 : : static int
617 : 0 : test_rcu_qsbr_main(void)
618 : : {
619 : : uint16_t core_id;
620 : :
621 : : if (RTE_EXEC_ENV_IS_WINDOWS)
622 : : return TEST_SKIPPED;
623 : :
624 [ # # ]: 0 : if (rte_lcore_count() < 3) {
625 : : printf("Not enough cores for rcu_qsbr_perf_autotest, expecting at least 3\n");
626 : 0 : return TEST_SKIPPED;
627 : : }
628 : :
629 : 0 : rte_atomic_store_explicit(&updates, 0, rte_memory_order_relaxed);
630 : 0 : rte_atomic_store_explicit(&update_cycles, 0, rte_memory_order_relaxed);
631 : 0 : rte_atomic_store_explicit(&checks, 0, rte_memory_order_relaxed);
632 : 0 : rte_atomic_store_explicit(&check_cycles, 0, rte_memory_order_relaxed);
633 : :
634 : 0 : num_cores = 0;
635 [ # # ]: 0 : RTE_LCORE_FOREACH_WORKER(core_id) {
636 : 0 : enabled_core_ids[num_cores] = core_id;
637 : 0 : num_cores++;
638 : : }
639 : :
640 : 0 : printf("Number of cores provided = %d\n", num_cores);
641 : : printf("Perf test with all reader threads registered\n");
642 : : printf("--------------------------------------------\n");
643 : 0 : all_registered = 1;
644 : :
645 [ # # ]: 0 : if (test_rcu_qsbr_perf() < 0)
646 : 0 : goto test_fail;
647 : :
648 [ # # ]: 0 : if (test_rcu_qsbr_rperf() < 0)
649 : 0 : goto test_fail;
650 : :
651 [ # # ]: 0 : if (test_rcu_qsbr_wperf() < 0)
652 : 0 : goto test_fail;
653 : :
654 [ # # ]: 0 : if (test_rcu_qsbr_sw_sv_1qs() < 0)
655 : 0 : goto test_fail;
656 : :
657 [ # # ]: 0 : if (test_rcu_qsbr_sw_sv_1qs_non_blocking() < 0)
658 : 0 : goto test_fail;
659 : :
660 : : /* Make sure the actual number of cores provided is less than
661 : : * RTE_MAX_LCORE. This will allow for some threads not
662 : : * to be registered on the QS variable.
663 : : */
664 [ # # ]: 0 : if (num_cores >= RTE_MAX_LCORE) {
665 : : printf("Test failed! number of cores provided should be less than %d\n",
666 : : RTE_MAX_LCORE);
667 : 0 : goto test_fail;
668 : : }
669 : :
670 : : printf("Perf test with some of reader threads registered\n");
671 : : printf("------------------------------------------------\n");
672 : 0 : all_registered = 0;
673 : :
674 [ # # ]: 0 : if (test_rcu_qsbr_perf() < 0)
675 : 0 : goto test_fail;
676 : :
677 [ # # ]: 0 : if (test_rcu_qsbr_rperf() < 0)
678 : 0 : goto test_fail;
679 : :
680 [ # # ]: 0 : if (test_rcu_qsbr_wperf() < 0)
681 : 0 : goto test_fail;
682 : :
683 [ # # ]: 0 : if (test_rcu_qsbr_sw_sv_1qs() < 0)
684 : 0 : goto test_fail;
685 : :
686 [ # # ]: 0 : if (test_rcu_qsbr_sw_sv_1qs_non_blocking() < 0)
687 : 0 : goto test_fail;
688 : :
689 : : printf("\n");
690 : :
691 : 0 : return 0;
692 : :
693 : : test_fail:
694 : : return -1;
695 : : }
696 : :
697 : 252 : REGISTER_PERF_TEST(rcu_qsbr_perf_autotest, test_rcu_qsbr_main);
|