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