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