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