Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <inttypes.h>
6 : : #include <locale.h>
7 : :
8 : : #include <rte_cycles.h>
9 : : #include <rte_hash.h>
10 : : #include <rte_hash_crc.h>
11 : : #include <rte_jhash.h>
12 : : #include <rte_launch.h>
13 : : #include <rte_malloc.h>
14 : : #include <rte_random.h>
15 : : #include <rte_spinlock.h>
16 : :
17 : : #include "test.h"
18 : :
19 : : #define RTE_RWTEST_FAIL 0
20 : :
21 : : #define TOTAL_ENTRY (5*1024) /* must be multiplied for perf test */
22 : : #define TOTAL_INSERT_FUNC (4.5*1024)
23 : : #define TOTAL_INSERT_FUNC_EXT (5*1024)
24 : : #define PERF_MULTIPLIER 1024
25 : : #define TOTAL_INSERT (TOTAL_INSERT_FUNC * PERF_MULTIPLIER) /* only for perf */
26 : :
27 : : #define NUM_TEST 3
28 : : unsigned int core_cnt[NUM_TEST] = {2, 4, 8};
29 : :
30 : : #define OFFSET_STR_LEN 16
31 : :
32 : : unsigned int worker_core_ids[RTE_MAX_LCORE];
33 : : struct perf {
34 : : uint32_t single_read;
35 : : uint32_t single_write;
36 : : uint32_t read_only[NUM_TEST];
37 : : uint32_t write_only[NUM_TEST];
38 : : uint32_t read_write_r[NUM_TEST];
39 : : uint32_t read_write_w[NUM_TEST];
40 : : };
41 : :
42 : : static struct perf htm_results, non_htm_results;
43 : :
44 : : struct {
45 : : uint32_t *keys;
46 : : uint8_t *found;
47 : : uint32_t num_insert;
48 : : uint32_t rounded_tot_insert;
49 : : struct rte_hash *h;
50 : : } tbl_rw_test_param;
51 : :
52 : : static RTE_ATOMIC(uint64_t) gcycles;
53 : : static RTE_ATOMIC(uint64_t) ginsertions;
54 : :
55 : : static RTE_ATOMIC(uint64_t) gread_cycles;
56 : : static RTE_ATOMIC(uint64_t) gwrite_cycles;
57 : :
58 : : static RTE_ATOMIC(uint64_t) greads;
59 : : static RTE_ATOMIC(uint64_t) gwrites;
60 : :
61 : : static int
62 : 0 : test_hash_readwrite_worker(__rte_unused void *arg)
63 : : {
64 : : char offset_start[OFFSET_STR_LEN];
65 : : char offset_end[OFFSET_STR_LEN];
66 : : uint64_t i, offset;
67 : : uint32_t lcore_id = rte_lcore_id();
68 : : uint64_t begin, cycles;
69 : : int *ret;
70 : : const bool use_iec = true;
71 : : const char *unit = NULL;
72 : :
73 : 0 : ret = rte_malloc(NULL, sizeof(int) *
74 : 0 : tbl_rw_test_param.num_insert, 0);
75 [ # # ]: 0 : if (ret == NULL) {
76 : : printf("allocation failed\n");
77 : 0 : return -1;
78 : : }
79 : :
80 [ # # ]: 0 : for (i = 0; i < rte_lcore_count(); i++) {
81 [ # # ]: 0 : if (worker_core_ids[i] == lcore_id)
82 : : break;
83 : : }
84 : 0 : offset = tbl_rw_test_param.num_insert * i;
85 : :
86 : 0 : rte_size_to_str(offset_start, RTE_DIM(offset_start), offset, use_iec, unit);
87 : 0 : rte_size_to_str(offset_end, RTE_DIM(offset_end),
88 : 0 : offset + tbl_rw_test_param.num_insert - 1, use_iec, unit);
89 : :
90 : 0 : printf("Core #%u inserting and reading %u: %s - %s\n",
91 : : lcore_id, tbl_rw_test_param.num_insert,
92 : : offset_start, offset_end);
93 : :
94 : : begin = rte_rdtsc_precise();
95 : :
96 [ # # ]: 0 : for (i = offset; i < offset + tbl_rw_test_param.num_insert; i++) {
97 : :
98 [ # # ]: 0 : if (rte_hash_lookup(tbl_rw_test_param.h,
99 : 0 : tbl_rw_test_param.keys + i) > 0)
100 : : break;
101 : :
102 : 0 : ret[i - offset] = rte_hash_add_key(tbl_rw_test_param.h,
103 : 0 : tbl_rw_test_param.keys + i);
104 [ # # ]: 0 : if (ret[i - offset] < 0)
105 : : break;
106 : :
107 : : /* lookup a random key */
108 : 0 : uint32_t rand = rte_rand() % (i + 1 - offset);
109 : :
110 : 0 : if (rte_hash_lookup(tbl_rw_test_param.h,
111 [ # # ]: 0 : tbl_rw_test_param.keys + rand) != ret[rand])
112 : : break;
113 : :
114 : :
115 : 0 : if (rte_hash_del_key(tbl_rw_test_param.h,
116 [ # # ]: 0 : tbl_rw_test_param.keys + rand) != ret[rand])
117 : : break;
118 : :
119 : 0 : ret[rand] = rte_hash_add_key(tbl_rw_test_param.h,
120 : 0 : tbl_rw_test_param.keys + rand);
121 [ # # ]: 0 : if (ret[rand] < 0)
122 : : break;
123 : :
124 : 0 : if (rte_hash_lookup(tbl_rw_test_param.h,
125 [ # # ]: 0 : tbl_rw_test_param.keys + rand) != ret[rand])
126 : : break;
127 : : }
128 : :
129 : 0 : cycles = rte_rdtsc_precise() - begin;
130 : 0 : rte_atomic_fetch_add_explicit(&gcycles, cycles, rte_memory_order_relaxed);
131 : 0 : rte_atomic_fetch_add_explicit(&ginsertions, i - offset, rte_memory_order_relaxed);
132 : :
133 [ # # ]: 0 : for (; i < offset + tbl_rw_test_param.num_insert; i++)
134 : 0 : tbl_rw_test_param.keys[i] = RTE_RWTEST_FAIL;
135 : :
136 : 0 : rte_free(ret);
137 : 0 : return 0;
138 : : }
139 : :
140 : : static int
141 : 0 : init_params(int use_ext, int use_htm, int rw_lf, int use_jhash, bool perf)
142 : : {
143 : : unsigned int i;
144 : : uint32_t *keys = NULL;
145 : : uint8_t *found = NULL;
146 : : struct rte_hash *handle;
147 : :
148 : 0 : struct rte_hash_parameters hash_params = {
149 [ # # ]: 0 : .entries = TOTAL_ENTRY * (perf ? PERF_MULTIPLIER : 1),
150 : : .key_len = sizeof(uint32_t),
151 : : .hash_func_init_val = 0,
152 : 0 : .socket_id = rte_socket_id(),
153 : : };
154 [ # # ]: 0 : if (use_jhash)
155 : 0 : hash_params.hash_func = rte_jhash;
156 : : else
157 : 0 : hash_params.hash_func = rte_hash_crc;
158 : :
159 : 0 : hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
160 [ # # ]: 0 : if (use_htm)
161 : 0 : hash_params.extra_flag |=
162 : : RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT;
163 [ # # ]: 0 : if (rw_lf)
164 : 0 : hash_params.extra_flag |=
165 : : RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
166 : : else
167 : 0 : hash_params.extra_flag |=
168 : : RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY;
169 : :
170 [ # # ]: 0 : if (use_ext)
171 : 0 : hash_params.extra_flag |=
172 : : RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
173 : : else
174 : 0 : hash_params.extra_flag &=
175 : : ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
176 : :
177 : 0 : hash_params.name = "tests";
178 : :
179 : 0 : handle = rte_hash_create(&hash_params);
180 [ # # ]: 0 : if (handle == NULL) {
181 : : printf("hash creation failed\n");
182 : 0 : return -1;
183 : : }
184 : :
185 : 0 : tbl_rw_test_param.h = handle;
186 : 0 : keys = rte_malloc(NULL, sizeof(uint32_t) * hash_params.entries, 0);
187 [ # # ]: 0 : if (keys == NULL) {
188 : : printf("RTE_MALLOC failed\n");
189 : 0 : goto err;
190 : : }
191 : :
192 : 0 : found = rte_zmalloc(NULL, sizeof(uint8_t) * hash_params.entries, 0);
193 [ # # ]: 0 : if (found == NULL) {
194 : : printf("RTE_ZMALLOC failed\n");
195 : 0 : goto err;
196 : : }
197 : :
198 : 0 : tbl_rw_test_param.keys = keys;
199 : 0 : tbl_rw_test_param.found = found;
200 : :
201 [ # # ]: 0 : for (i = 0; i < hash_params.entries; i++)
202 : 0 : keys[i] = i;
203 : :
204 : : return 0;
205 : :
206 : 0 : err:
207 : 0 : rte_free(keys);
208 : 0 : rte_hash_free(handle);
209 : :
210 : 0 : return -1;
211 : : }
212 : :
213 : : static int
214 : 0 : test_hash_readwrite_functional(int use_htm, int use_rw_lf, int use_ext)
215 : : {
216 : : unsigned int i;
217 : : const void *next_key;
218 : : void *next_data;
219 : 0 : uint32_t iter = 0;
220 : :
221 : : uint32_t duplicated_keys = 0;
222 : : uint32_t lost_keys = 0;
223 : : int use_jhash = 1;
224 : 0 : int worker_cnt = rte_lcore_count() - 1;
225 : : uint32_t tot_insert = 0;
226 : :
227 : 0 : rte_atomic_store_explicit(&gcycles, 0, rte_memory_order_relaxed);
228 : 0 : rte_atomic_store_explicit(&ginsertions, 0, rte_memory_order_relaxed);
229 : :
230 [ # # ]: 0 : if (init_params(use_ext, use_htm, use_rw_lf, use_jhash, false) != 0)
231 : 0 : goto err;
232 : :
233 [ # # ]: 0 : if (use_ext)
234 : : tot_insert = TOTAL_INSERT_FUNC_EXT;
235 : : else
236 : : tot_insert = TOTAL_INSERT_FUNC;
237 : :
238 : 0 : tbl_rw_test_param.num_insert =
239 : 0 : tot_insert / worker_cnt;
240 : :
241 : 0 : tbl_rw_test_param.rounded_tot_insert =
242 : 0 : tbl_rw_test_param.num_insert * worker_cnt;
243 : :
244 : : printf("\nHTM = %d, RW-LF = %d, EXT-Table = %d\n",
245 : : use_htm, use_rw_lf, use_ext);
246 : : printf("++++++++Start function tests:+++++++++\n");
247 : :
248 : : /* Fire all threads. */
249 : 0 : rte_eal_mp_remote_launch(test_hash_readwrite_worker,
250 : : NULL, SKIP_MAIN);
251 : 0 : rte_eal_mp_wait_lcore();
252 : :
253 : 0 : while (rte_hash_iterate(tbl_rw_test_param.h, &next_key,
254 [ # # ]: 0 : &next_data, &iter) >= 0) {
255 : : /* Search for the key in the list of keys added .*/
256 : 0 : i = *(const uint32_t *)next_key;
257 : 0 : tbl_rw_test_param.found[i]++;
258 : : }
259 : :
260 [ # # ]: 0 : for (i = 0; i < tbl_rw_test_param.rounded_tot_insert; i++) {
261 [ # # ]: 0 : if (tbl_rw_test_param.keys[i] != RTE_RWTEST_FAIL) {
262 [ # # ]: 0 : if (tbl_rw_test_param.found[i] > 1) {
263 : : duplicated_keys++;
264 : : break;
265 : : }
266 [ # # ]: 0 : if (tbl_rw_test_param.found[i] == 0) {
267 : : lost_keys++;
268 : : printf("key %d is lost\n", i);
269 : : break;
270 : : }
271 : : }
272 : : }
273 : :
274 [ # # ]: 0 : if (duplicated_keys > 0) {
275 : : printf("%d key duplicated\n", duplicated_keys);
276 : 0 : goto err_free;
277 : : }
278 : :
279 [ # # ]: 0 : if (lost_keys > 0) {
280 : : printf("%d key lost\n", lost_keys);
281 : 0 : goto err_free;
282 : : }
283 : :
284 : : printf("No key corrupted during read-write test.\n");
285 : :
286 : 0 : unsigned long long int cycles_per_insertion =
287 : 0 : rte_atomic_load_explicit(&gcycles, rte_memory_order_relaxed) /
288 : 0 : rte_atomic_load_explicit(&ginsertions, rte_memory_order_relaxed);
289 : :
290 : : printf("cycles per insertion and lookup: %llu\n", cycles_per_insertion);
291 : :
292 : 0 : rte_free(tbl_rw_test_param.found);
293 : 0 : rte_free(tbl_rw_test_param.keys);
294 : 0 : rte_hash_free(tbl_rw_test_param.h);
295 : : printf("+++++++++Complete function tests+++++++++\n");
296 : 0 : return 0;
297 : :
298 : 0 : err_free:
299 : 0 : rte_free(tbl_rw_test_param.found);
300 : 0 : rte_free(tbl_rw_test_param.keys);
301 : 0 : rte_hash_free(tbl_rw_test_param.h);
302 : : err:
303 : : return -1;
304 : : }
305 : :
306 : : static int
307 : 0 : test_rw_reader(void *arg)
308 : : {
309 : : uint64_t i;
310 : : uint64_t begin, cycles;
311 : 0 : uint64_t read_cnt = (uint64_t)((uintptr_t)arg);
312 : :
313 : : begin = rte_rdtsc_precise();
314 [ # # ]: 0 : for (i = 0; i < read_cnt; i++) {
315 : 0 : void *data = arg;
316 : 0 : rte_hash_lookup_data(tbl_rw_test_param.h,
317 : 0 : tbl_rw_test_param.keys + i,
318 : : &data);
319 [ # # ]: 0 : if (i != (uint64_t)(uintptr_t)data) {
320 : : printf("lookup find wrong value %"PRIu64","
321 : : "%"PRIu64"\n", i,
322 : : (uint64_t)(uintptr_t)data);
323 : 0 : break;
324 : : }
325 : : }
326 : :
327 : 0 : cycles = rte_rdtsc_precise() - begin;
328 : 0 : rte_atomic_fetch_add_explicit(&gread_cycles, cycles, rte_memory_order_relaxed);
329 : 0 : rte_atomic_fetch_add_explicit(&greads, i, rte_memory_order_relaxed);
330 : 0 : return 0;
331 : : }
332 : :
333 : : static int
334 : 0 : test_rw_writer(void *arg)
335 : : {
336 : : uint64_t i;
337 : : uint32_t lcore_id = rte_lcore_id();
338 : : uint64_t begin, cycles;
339 : : int ret;
340 : 0 : uint64_t start_coreid = (uint64_t)(uintptr_t)arg;
341 : : uint64_t offset;
342 : :
343 [ # # ]: 0 : for (i = 0; i < rte_lcore_count(); i++) {
344 [ # # ]: 0 : if (worker_core_ids[i] == lcore_id)
345 : : break;
346 : : }
347 : :
348 : 0 : offset = TOTAL_INSERT / 2 + (i - (start_coreid)) *
349 : 0 : tbl_rw_test_param.num_insert;
350 : : begin = rte_rdtsc_precise();
351 [ # # ]: 0 : for (i = offset; i < offset + tbl_rw_test_param.num_insert; i++) {
352 : 0 : ret = rte_hash_add_key_data(tbl_rw_test_param.h,
353 : 0 : tbl_rw_test_param.keys + i,
354 : : (void *)((uintptr_t)i));
355 [ # # ]: 0 : if (ret < 0) {
356 : : printf("writer failed %"PRIu64"\n", i);
357 : : break;
358 : : }
359 : : }
360 : :
361 : 0 : cycles = rte_rdtsc_precise() - begin;
362 : 0 : rte_atomic_fetch_add_explicit(&gwrite_cycles, cycles, rte_memory_order_relaxed);
363 : 0 : rte_atomic_fetch_add_explicit(&gwrites, tbl_rw_test_param.num_insert,
364 : : rte_memory_order_relaxed);
365 : 0 : return 0;
366 : : }
367 : :
368 : : static int
369 : 0 : test_hash_readwrite_perf(struct perf *perf_results, int use_htm,
370 : : int reader_faster)
371 : : {
372 : : unsigned int n;
373 : : int ret;
374 : : int start_coreid;
375 : : uint64_t i, read_cnt;
376 : :
377 : : const void *next_key;
378 : : void *next_data;
379 : : uint32_t iter;
380 : : int use_jhash = 0;
381 : :
382 : : uint32_t duplicated_keys = 0;
383 : : uint32_t lost_keys = 0;
384 : :
385 : : uint64_t start = 0, end = 0;
386 : :
387 : 0 : rte_atomic_store_explicit(&gwrites, 0, rte_memory_order_relaxed);
388 : 0 : rte_atomic_store_explicit(&greads, 0, rte_memory_order_relaxed);
389 : :
390 : 0 : rte_atomic_store_explicit(&gread_cycles, 0, rte_memory_order_relaxed);
391 : 0 : rte_atomic_store_explicit(&gwrite_cycles, 0, rte_memory_order_relaxed);
392 : :
393 [ # # ]: 0 : if (init_params(0, use_htm, 0, use_jhash, true) != 0)
394 : 0 : goto err;
395 : :
396 : : /*
397 : : * Do a readers finish faster or writers finish faster test.
398 : : * When readers finish faster, we timing the readers, and when writers
399 : : * finish faster, we timing the writers.
400 : : * Divided by 10 or 2 is just experimental values to vary the workload
401 : : * of readers.
402 : : */
403 [ # # ]: 0 : if (reader_faster) {
404 : : printf("++++++Start perf test: reader++++++++\n");
405 : : read_cnt = TOTAL_INSERT / 10;
406 : : } else {
407 : : printf("++++++Start perf test: writer++++++++\n");
408 : : read_cnt = TOTAL_INSERT / 2;
409 : : }
410 : :
411 : : /* We first test single thread performance */
412 : : start = rte_rdtsc_precise();
413 : : /* Insert half of the keys */
414 [ # # ]: 0 : for (i = 0; i < TOTAL_INSERT / 2; i++) {
415 : 0 : ret = rte_hash_add_key_data(tbl_rw_test_param.h,
416 : 0 : tbl_rw_test_param.keys + i,
417 : : (void *)((uintptr_t)i));
418 [ # # ]: 0 : if (ret < 0) {
419 : : printf("Failed to insert half of keys\n");
420 : 0 : goto err_free;
421 : : }
422 : : }
423 : 0 : end = rte_rdtsc_precise() - start;
424 : 0 : perf_results->single_write = end / i;
425 : :
426 : : start = rte_rdtsc_precise();
427 : :
428 [ # # ]: 0 : for (i = 0; i < read_cnt; i++) {
429 : : void *data;
430 : 0 : rte_hash_lookup_data(tbl_rw_test_param.h,
431 : 0 : tbl_rw_test_param.keys + i,
432 : : &data);
433 [ # # ]: 0 : if (i != (uint64_t)(uintptr_t)data) {
434 : : printf("lookup find wrong value"
435 : : " %"PRIu64",%"PRIu64"\n", i,
436 : : (uint64_t)(uintptr_t)data);
437 : 0 : break;
438 : : }
439 : : }
440 : 0 : end = rte_rdtsc_precise() - start;
441 : 0 : perf_results->single_read = end / i;
442 : :
443 [ # # ]: 0 : for (n = 0; n < NUM_TEST; n++) {
444 : 0 : unsigned int tot_worker_lcore = rte_lcore_count() - 1;
445 [ # # ]: 0 : if (tot_worker_lcore < core_cnt[n] * 2)
446 : 0 : goto finish;
447 : :
448 : 0 : rte_atomic_store_explicit(&greads, 0, rte_memory_order_relaxed);
449 : 0 : rte_atomic_store_explicit(&gread_cycles, 0, rte_memory_order_relaxed);
450 : 0 : rte_atomic_store_explicit(&gwrites, 0, rte_memory_order_relaxed);
451 : 0 : rte_atomic_store_explicit(&gwrite_cycles, 0, rte_memory_order_relaxed);
452 : :
453 : 0 : rte_hash_reset(tbl_rw_test_param.h);
454 : :
455 : 0 : tbl_rw_test_param.num_insert = TOTAL_INSERT / 2 / core_cnt[n];
456 : 0 : tbl_rw_test_param.rounded_tot_insert = TOTAL_INSERT / 2 +
457 : 0 : tbl_rw_test_param.num_insert *
458 : : core_cnt[n];
459 : :
460 [ # # ]: 0 : for (i = 0; i < TOTAL_INSERT / 2; i++) {
461 : 0 : ret = rte_hash_add_key_data(tbl_rw_test_param.h,
462 : 0 : tbl_rw_test_param.keys + i,
463 : : (void *)((uintptr_t)i));
464 [ # # ]: 0 : if (ret < 0) {
465 : : printf("Failed to insert half of keys\n");
466 : 0 : goto err_free;
467 : : }
468 : : }
469 : :
470 : : /* Then test multiple thread case but only all reads or
471 : : * all writes
472 : : */
473 : :
474 : : /* Test only reader cases */
475 [ # # ]: 0 : for (i = 0; i < core_cnt[n]; i++)
476 : 0 : rte_eal_remote_launch(test_rw_reader,
477 : : (void *)(uintptr_t)read_cnt,
478 : : worker_core_ids[i]);
479 : :
480 : 0 : rte_eal_mp_wait_lcore();
481 : :
482 : : start_coreid = i;
483 : : /* Test only writer cases */
484 [ # # ]: 0 : for (; i < core_cnt[n] * 2; i++)
485 : 0 : rte_eal_remote_launch(test_rw_writer,
486 : 0 : (void *)((uintptr_t)start_coreid),
487 : : worker_core_ids[i]);
488 : :
489 : 0 : rte_eal_mp_wait_lcore();
490 : :
491 [ # # ]: 0 : if (reader_faster) {
492 : 0 : unsigned long long int cycles_per_insertion =
493 : 0 : rte_atomic_load_explicit(&gread_cycles, rte_memory_order_relaxed) /
494 : 0 : rte_atomic_load_explicit(&greads, rte_memory_order_relaxed);
495 : 0 : perf_results->read_only[n] = cycles_per_insertion;
496 : : printf("Reader only: cycles per lookup: %llu\n",
497 : : cycles_per_insertion);
498 : : }
499 : :
500 : : else {
501 : 0 : unsigned long long int cycles_per_insertion =
502 : 0 : rte_atomic_load_explicit(&gwrite_cycles, rte_memory_order_relaxed) /
503 : 0 : rte_atomic_load_explicit(&gwrites, rte_memory_order_relaxed);
504 : 0 : perf_results->write_only[n] = cycles_per_insertion;
505 : : printf("Writer only: cycles per writes: %llu\n",
506 : : cycles_per_insertion);
507 : : }
508 : :
509 : 0 : rte_atomic_store_explicit(&greads, 0, rte_memory_order_relaxed);
510 : 0 : rte_atomic_store_explicit(&gread_cycles, 0, rte_memory_order_relaxed);
511 : 0 : rte_atomic_store_explicit(&gwrites, 0, rte_memory_order_relaxed);
512 : 0 : rte_atomic_store_explicit(&gwrite_cycles, 0, rte_memory_order_relaxed);
513 : :
514 : 0 : rte_hash_reset(tbl_rw_test_param.h);
515 : :
516 [ # # ]: 0 : for (i = 0; i < TOTAL_INSERT / 2; i++) {
517 : 0 : ret = rte_hash_add_key_data(tbl_rw_test_param.h,
518 : 0 : tbl_rw_test_param.keys + i,
519 : : (void *)((uintptr_t)i));
520 [ # # ]: 0 : if (ret < 0) {
521 : : printf("Failed to insert half of keys\n");
522 : 0 : goto err_free;
523 : : }
524 : : }
525 : :
526 : 0 : start_coreid = core_cnt[n];
527 : :
528 [ # # ]: 0 : if (reader_faster) {
529 [ # # ]: 0 : for (i = core_cnt[n]; i < core_cnt[n] * 2; i++)
530 : 0 : rte_eal_remote_launch(test_rw_writer,
531 : 0 : (void *)((uintptr_t)start_coreid),
532 : : worker_core_ids[i]);
533 [ # # ]: 0 : for (i = 0; i < core_cnt[n]; i++)
534 : 0 : rte_eal_remote_launch(test_rw_reader,
535 : : (void *)(uintptr_t)read_cnt,
536 : : worker_core_ids[i]);
537 : : } else {
538 [ # # ]: 0 : for (i = 0; i < core_cnt[n]; i++)
539 : 0 : rte_eal_remote_launch(test_rw_reader,
540 : : (void *)(uintptr_t)read_cnt,
541 : : worker_core_ids[i]);
542 [ # # ]: 0 : for (; i < core_cnt[n] * 2; i++)
543 : 0 : rte_eal_remote_launch(test_rw_writer,
544 : 0 : (void *)((uintptr_t)start_coreid),
545 : : worker_core_ids[i]);
546 : : }
547 : :
548 : 0 : rte_eal_mp_wait_lcore();
549 : :
550 : 0 : iter = 0;
551 : 0 : memset(tbl_rw_test_param.found, 0, TOTAL_ENTRY * PERF_MULTIPLIER);
552 : 0 : while (rte_hash_iterate(tbl_rw_test_param.h,
553 [ # # ]: 0 : &next_key, &next_data, &iter) >= 0) {
554 : : /* Search for the key in the list of keys added .*/
555 : 0 : i = *(const uint32_t *)next_key;
556 : 0 : tbl_rw_test_param.found[i]++;
557 : : }
558 : :
559 [ # # ]: 0 : for (i = 0; i < tbl_rw_test_param.rounded_tot_insert; i++) {
560 [ # # ]: 0 : if (tbl_rw_test_param.keys[i] != RTE_RWTEST_FAIL) {
561 [ # # ]: 0 : if (tbl_rw_test_param.found[i] > 1) {
562 : : duplicated_keys++;
563 : : break;
564 : : }
565 [ # # ]: 0 : if (tbl_rw_test_param.found[i] == 0) {
566 : : lost_keys++;
567 : : printf("key %"PRIu64" is lost\n", i);
568 : : break;
569 : : }
570 : : }
571 : : }
572 : :
573 [ # # ]: 0 : if (duplicated_keys > 0) {
574 : : printf("%d key duplicated\n", duplicated_keys);
575 : 0 : goto err_free;
576 : : }
577 : :
578 [ # # ]: 0 : if (lost_keys > 0) {
579 : : printf("%d key lost\n", lost_keys);
580 : 0 : goto err_free;
581 : : }
582 : :
583 : : printf("No key corrupted during read-write test.\n");
584 : :
585 [ # # ]: 0 : if (reader_faster) {
586 : 0 : unsigned long long int cycles_per_insertion =
587 : 0 : rte_atomic_load_explicit(&gread_cycles, rte_memory_order_relaxed) /
588 : 0 : rte_atomic_load_explicit(&greads, rte_memory_order_relaxed);
589 : 0 : perf_results->read_write_r[n] = cycles_per_insertion;
590 : : printf("Read-write cycles per lookup: %llu\n",
591 : : cycles_per_insertion);
592 : : }
593 : :
594 : : else {
595 : 0 : unsigned long long int cycles_per_insertion =
596 : 0 : rte_atomic_load_explicit(&gwrite_cycles, rte_memory_order_relaxed) /
597 : 0 : rte_atomic_load_explicit(&gwrites, rte_memory_order_relaxed);
598 : 0 : perf_results->read_write_w[n] = cycles_per_insertion;
599 : : printf("Read-write cycles per writes: %llu\n",
600 : : cycles_per_insertion);
601 : : }
602 : : }
603 : :
604 : 0 : finish:
605 : 0 : rte_free(tbl_rw_test_param.found);
606 : 0 : rte_free(tbl_rw_test_param.keys);
607 : 0 : rte_hash_free(tbl_rw_test_param.h);
608 : 0 : return 0;
609 : :
610 : 0 : err_free:
611 : 0 : rte_free(tbl_rw_test_param.found);
612 : 0 : rte_free(tbl_rw_test_param.keys);
613 : 0 : rte_hash_free(tbl_rw_test_param.h);
614 : :
615 : : err:
616 : : return -1;
617 : : }
618 : :
619 : : static int
620 : 0 : test_hash_rw_perf_main(void)
621 : : {
622 : : /*
623 : : * Variables used to choose different tests.
624 : : * use_htm indicates if hardware transactional memory should be used.
625 : : * reader_faster indicates if the reader threads should finish earlier
626 : : * than writer threads. This is to timing either reader threads or
627 : : * writer threads for performance numbers.
628 : : */
629 : : int use_htm, reader_faster;
630 : : unsigned int i = 0, core_id = 0;
631 : :
632 [ # # ]: 0 : if (rte_lcore_count() < 3) {
633 : : printf("Not enough cores for hash_readwrite_autotest, expecting at least 3\n");
634 : 0 : return TEST_SKIPPED;
635 : : }
636 : :
637 [ # # ]: 0 : RTE_LCORE_FOREACH_WORKER(core_id) {
638 : 0 : worker_core_ids[i] = core_id;
639 : 0 : i++;
640 : : }
641 : :
642 : 0 : setlocale(LC_NUMERIC, "");
643 : :
644 [ # # ]: 0 : if (rte_tm_supported()) {
645 : : printf("Hardware transactional memory (lock elision) "
646 : : "is supported\n");
647 : :
648 : : printf("Test read-write with Hardware transactional memory\n");
649 : :
650 : : use_htm = 1;
651 : :
652 : : reader_faster = 1;
653 [ # # ]: 0 : if (test_hash_readwrite_perf(&htm_results, use_htm,
654 : : reader_faster) < 0)
655 : : return -1;
656 : :
657 : : reader_faster = 0;
658 [ # # ]: 0 : if (test_hash_readwrite_perf(&htm_results, use_htm,
659 : : reader_faster) < 0)
660 : : return -1;
661 : : } else {
662 : : printf("Hardware transactional memory (lock elision) "
663 : : "is NOT supported\n");
664 : : }
665 : :
666 : : printf("Test read-write without Hardware transactional memory\n");
667 : : use_htm = 0;
668 : :
669 : : reader_faster = 1;
670 [ # # ]: 0 : if (test_hash_readwrite_perf(&non_htm_results, use_htm,
671 : : reader_faster) < 0)
672 : : return -1;
673 : : reader_faster = 0;
674 [ # # ]: 0 : if (test_hash_readwrite_perf(&non_htm_results, use_htm,
675 : : reader_faster) < 0)
676 : : return -1;
677 : :
678 : : printf("================\n");
679 : : printf("Results summary:\n");
680 : : printf("================\n");
681 : :
682 : : printf("HTM:\n");
683 : 0 : printf(" single read: %u\n", htm_results.single_read);
684 : 0 : printf(" single write: %u\n", htm_results.single_write);
685 : : printf("non HTM:\n");
686 : 0 : printf(" single read: %u\n", non_htm_results.single_read);
687 : 0 : printf(" single write: %u\n", non_htm_results.single_write);
688 [ # # ]: 0 : for (i = 0; i < NUM_TEST; i++) {
689 : 0 : printf("+++ core_cnt: %u +++\n", core_cnt[i]);
690 : : printf("HTM:\n");
691 : 0 : printf(" read only: %u\n", htm_results.read_only[i]);
692 : 0 : printf(" write only: %u\n", htm_results.write_only[i]);
693 : 0 : printf(" read-write read: %u\n", htm_results.read_write_r[i]);
694 : 0 : printf(" read-write write: %u\n", htm_results.read_write_w[i]);
695 : :
696 : : printf("non HTM:\n");
697 : 0 : printf(" read only: %u\n", non_htm_results.read_only[i]);
698 : 0 : printf(" write only: %u\n", non_htm_results.write_only[i]);
699 : 0 : printf(" read-write read: %u\n",
700 : : non_htm_results.read_write_r[i]);
701 : 0 : printf(" read-write write: %u\n",
702 : : non_htm_results.read_write_w[i]);
703 : : }
704 : :
705 : : return 0;
706 : : }
707 : :
708 : : static int
709 : 1 : test_hash_rw_func_main(void)
710 : : {
711 : : /*
712 : : * Variables used to choose different tests.
713 : : * use_htm indicates if hardware transactional memory should be used.
714 : : * reader_faster indicates if the reader threads should finish earlier
715 : : * than writer threads. This is to timing either reader threads or
716 : : * writer threads for performance numbers.
717 : : */
718 : : unsigned int i = 0, core_id = 0;
719 : :
720 [ + - ]: 1 : if (rte_lcore_count() < 3) {
721 : : printf("Not enough cores for hash_readwrite_autotest, expecting at least 3\n");
722 : 1 : return TEST_SKIPPED;
723 : : }
724 : :
725 [ # # ]: 0 : RTE_LCORE_FOREACH_WORKER(core_id) {
726 : 0 : worker_core_ids[i] = core_id;
727 : 0 : i++;
728 : : }
729 : :
730 : 0 : setlocale(LC_NUMERIC, "");
731 : :
732 [ # # ]: 0 : if (rte_tm_supported()) {
733 : : printf("Hardware transactional memory (lock elision) "
734 : : "is supported\n");
735 : :
736 : : printf("Test read-write with Hardware transactional memory\n");
737 : :
738 : : /* htm = 1, rw_lf = 0, ext = 0 */
739 [ # # ]: 0 : if (test_hash_readwrite_functional(1, 0, 0) < 0)
740 : : return -1;
741 : :
742 : : /* htm = 1, rw_lf = 1, ext = 0 */
743 [ # # ]: 0 : if (test_hash_readwrite_functional(1, 1, 0) < 0)
744 : : return -1;
745 : :
746 : : /* htm = 1, rw_lf = 0, ext = 1 */
747 [ # # ]: 0 : if (test_hash_readwrite_functional(1, 0, 1) < 0)
748 : : return -1;
749 : :
750 : : /* htm = 1, rw_lf = 1, ext = 1 */
751 [ # # ]: 0 : if (test_hash_readwrite_functional(1, 1, 1) < 0)
752 : : return -1;
753 : : } else {
754 : : printf("Hardware transactional memory (lock elision) "
755 : : "is NOT supported\n");
756 : : }
757 : :
758 : : printf("Test read-write without Hardware transactional memory\n");
759 : : /* htm = 0, rw_lf = 0, ext = 0 */
760 [ # # ]: 0 : if (test_hash_readwrite_functional(0, 0, 0) < 0)
761 : : return -1;
762 : :
763 : : /* htm = 0, rw_lf = 1, ext = 0 */
764 [ # # ]: 0 : if (test_hash_readwrite_functional(0, 1, 0) < 0)
765 : : return -1;
766 : :
767 : : /* htm = 0, rw_lf = 0, ext = 1 */
768 [ # # ]: 0 : if (test_hash_readwrite_functional(0, 0, 1) < 0)
769 : : return -1;
770 : :
771 : : /* htm = 0, rw_lf = 1, ext = 1 */
772 [ # # ]: 0 : if (test_hash_readwrite_functional(0, 1, 1) < 0)
773 : 0 : return -1;
774 : :
775 : : return 0;
776 : : }
777 : :
778 : 253 : REGISTER_FAST_TEST(hash_readwrite_func_autotest, false, true, test_hash_rw_func_main);
779 : 253 : REGISTER_PERF_TEST(hash_readwrite_perf_autotest, test_hash_rw_perf_main);
|