1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Arm Limited
8 #include <rte_cycles.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>
19 #ifndef RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF
20 #define RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF 0
23 #define BULK_LOOKUP_SIZE 32
25 #define RUN_WITH_HTM_DISABLED 0
27 #if (RUN_WITH_HTM_DISABLED)
29 #define TOTAL_ENTRY (5*1024)
30 #define TOTAL_INSERT (5*1024)
34 #define TOTAL_ENTRY (4*1024*1024)
35 #define TOTAL_INSERT (4*1024*1024)
40 #define READ_PASS_NO_KEY_SHIFTS 2
41 #define READ_PASS_SHIFT_PATH 4
42 #define READ_PASS_NON_SHIFT_PATH 8
43 #define BULK_LOOKUP 16
45 unsigned int rwc_core_cnt[NUM_TEST] = {1, 2, 4};
48 uint32_t w_no_ks_r_hit[2][NUM_TEST];
49 uint32_t w_no_ks_r_miss[2][NUM_TEST];
50 uint32_t w_ks_r_hit_nsp[2][NUM_TEST];
51 uint32_t w_ks_r_hit_sp[2][NUM_TEST];
52 uint32_t w_ks_r_miss[2][NUM_TEST];
53 uint32_t multi_rw[NUM_TEST - 1][2][NUM_TEST];
56 static struct rwc_perf rwc_lf_results, rwc_non_lf_results;
62 uint32_t *keys_absent;
63 uint32_t *keys_shift_path;
64 uint32_t *keys_non_shift_path;
65 uint32_t count_keys_no_ks;
66 uint32_t count_keys_ks;
67 uint32_t count_keys_absent;
68 uint32_t count_keys_shift_path;
69 uint32_t count_keys_non_shift_path;
70 uint32_t single_insert;
74 static rte_atomic64_t gread_cycles;
75 static rte_atomic64_t greads;
77 static volatile uint8_t writer_done;
78 static volatile uint8_t multi_writer_done[4];
80 uint16_t enabled_core_ids[RTE_MAX_LCORE];
82 uint8_t *scanned_bkts;
85 get_enabled_cores_list(void)
89 uint32_t max_cores = rte_lcore_count();
90 for (core_id = 0; core_id < RTE_MAX_LCORE && i < max_cores; core_id++) {
91 if (rte_lcore_is_enabled(core_id)) {
92 enabled_core_ids[i] = core_id;
98 printf("Number of enabled cores in list is different from "
99 "number given by rte_lcore_count()\n");
106 check_bucket(uint32_t bkt_idx, uint32_t key)
112 const void *next_key;
115 /* Temporary bucket to hold the keys */
116 uint32_t keys_in_bkt[8];
120 while (rte_hash_iterate(tbl_rwc_test_param.h,
121 &next_key, &next_data, &iter) >= 0) {
123 /* Check for duplicate entries */
124 if (*(const uint32_t *)next_key == key)
127 /* Identify if there is any free entry in the bucket */
128 diff = iter - prev_iter;
133 keys_in_bkt[count] = *(const uint32_t *)next_key;
136 /* All entries in the bucket are occupied */
140 * Check if bucket was not scanned before, to avoid
143 if (scanned_bkts[bkt_idx] == 0) {
145 * Since this bucket (pointed to by bkt_idx) is
146 * full, it is likely that key(s) in this
147 * bucket will be on the shift path, when
148 * collision occurs. Thus, add it to
151 memcpy(tbl_rwc_test_param.keys_shift_path +
152 tbl_rwc_test_param.count_keys_shift_path
154 tbl_rwc_test_param.count_keys_shift_path += 8;
155 scanned_bkts[bkt_idx] = 1;
166 uint32_t *keys = NULL;
167 uint32_t *keys_no_ks = NULL;
168 uint32_t *keys_ks = NULL;
169 uint32_t *keys_absent = NULL;
170 uint32_t *keys_non_shift_path = NULL;
171 uint32_t *found = NULL;
172 uint32_t count_keys_no_ks = 0;
173 uint32_t count_keys_ks = 0;
177 * keys will consist of a) keys whose addition to the hash table
178 * will result in shifting of the existing keys to their alternate
179 * locations b) keys whose addition to the hash table will not result
180 * in shifting of the existing keys.
182 keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);
184 printf("RTE_MALLOC failed\n");
189 * keys_no_ks (no key-shifts): Subset of 'keys' - consists of keys that
190 * will NOT result in shifting of the existing keys to their alternate
191 * locations. Roughly around 900K keys.
193 keys_no_ks = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);
194 if (keys_no_ks == NULL) {
195 printf("RTE_MALLOC failed\n");
200 * keys_ks (key-shifts): Subset of 'keys' - consists of keys that will
201 * result in shifting of the existing keys to their alternate locations.
202 * Roughly around 146K keys. There might be repeating keys. More code is
203 * required to filter out these keys which will complicate the test case
205 keys_ks = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);
206 if (keys_ks == NULL) {
207 printf("RTE_MALLOC failed\n");
211 /* Used to identify keys not inserted in the hash table */
212 found = rte_zmalloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);
214 printf("RTE_MALLOC failed\n");
219 * This consist of keys not inserted to the hash table.
220 * Used to test perf of lookup on keys that do not exist in the table.
222 keys_absent = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);
223 if (keys_absent == NULL) {
224 printf("RTE_MALLOC failed\n");
229 * This consist of keys which are likely to be on the shift
230 * path (i.e. being moved to alternate location), when collision occurs
231 * on addition of a key to an already full primary bucket.
232 * Used to test perf of lookup on keys that are on the shift path.
234 tbl_rwc_test_param.keys_shift_path = rte_malloc(NULL, sizeof(uint32_t) *
236 if (tbl_rwc_test_param.keys_shift_path == NULL) {
237 printf("RTE_MALLOC failed\n");
242 * This consist of keys which are never on the shift
243 * path (i.e. being moved to alternate location), when collision occurs
244 * on addition of a key to an already full primary bucket.
245 * Used to test perf of lookup on keys that are not on the shift path.
247 keys_non_shift_path = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT,
249 if (keys_non_shift_path == NULL) {
250 printf("RTE_MALLOC failed\n");
256 uint32_t prim_bucket_idx;
258 uint32_t num_buckets;
259 uint32_t bucket_bitmask;
260 num_buckets = rte_align32pow2(TOTAL_ENTRY) / 8;
261 bucket_bitmask = num_buckets - 1;
264 * Used to mark bkts in which at least one key was shifted to its
267 scanned_bkts = rte_malloc(NULL, sizeof(uint8_t) * num_buckets, 0);
268 if (scanned_bkts == NULL) {
269 printf("RTE_MALLOC failed\n");
273 tbl_rwc_test_param.keys = keys;
274 tbl_rwc_test_param.keys_no_ks = keys_no_ks;
275 tbl_rwc_test_param.keys_ks = keys_ks;
276 tbl_rwc_test_param.keys_absent = keys_absent;
277 tbl_rwc_test_param.keys_non_shift_path = keys_non_shift_path;
278 /* Generate keys by adding previous two keys, neglect overflow */
279 printf("Generating keys...\n");
282 for (i = 2; i < TOTAL_INSERT; i++)
283 keys[i] = keys[i-1] + keys[i-2];
285 /* Segregate keys into keys_no_ks and keys_ks */
286 for (i = 0; i < TOTAL_INSERT; i++) {
287 /* Check if primary bucket has space.*/
288 sig = rte_hash_hash(tbl_rwc_test_param.h,
289 tbl_rwc_test_param.keys+i);
290 prim_bucket_idx = sig & bucket_bitmask;
291 ret = check_bucket(prim_bucket_idx, keys[i]);
294 * Primary bucket is full, this key will result in
295 * shifting of the keys to their alternate locations.
297 keys_ks[count_keys_ks] = keys[i];
299 } else if (ret == 0) {
301 * Primary bucket has space, this key will not result in
302 * shifting of the keys. Hence, add key to the table.
304 ret = rte_hash_add_key_data(tbl_rwc_test_param.h,
306 (void *)((uintptr_t)i));
308 printf("writer failed %"PRIu32"\n", i);
311 keys_no_ks[count_keys_no_ks] = keys[i];
316 for (i = 0; i < count_keys_no_ks; i++) {
318 * Identify keys in keys_no_ks with value less than
319 * 4M (HTM enabled) OR 5K (HTM disabled)
321 if (keys_no_ks[i] < TOTAL_INSERT)
322 found[keys_no_ks[i]]++;
325 for (i = 0; i < count_keys_ks; i++) {
327 * Identify keys in keys_ks with value less than
328 * 4M (HTM enabled) OR 5K (HTM disabled)
330 if (keys_ks[i] < TOTAL_INSERT)
334 uint32_t count_keys_absent = 0;
335 for (i = 0; i < TOTAL_INSERT; i++) {
337 * Identify missing keys between 0 and
338 * 4M (HTM enabled) OR 5K (HTM disabled)
341 keys_absent[count_keys_absent++] = i;
344 /* Find keys that will not be on the shift path */
346 const void *next_key;
349 for (i = 0; i < num_buckets; i++) {
350 /* Check bucket for no keys shifted to alternate locations */
351 if (scanned_bkts[i] == 0) {
353 while (rte_hash_iterate(tbl_rwc_test_param.h,
354 &next_key, &next_data, &iter) >= 0) {
356 /* Check if key belongs to the current bucket */
358 keys_non_shift_path[count++]
359 = *(const uint32_t *)next_key;
366 tbl_rwc_test_param.count_keys_no_ks = count_keys_no_ks;
367 tbl_rwc_test_param.count_keys_ks = count_keys_ks;
368 tbl_rwc_test_param.count_keys_absent = count_keys_absent;
369 tbl_rwc_test_param.count_keys_non_shift_path = count;
371 printf("\nCount of keys NOT causing shifting of existing keys to "
372 "alternate location: %d\n", tbl_rwc_test_param.count_keys_no_ks);
373 printf("\nCount of keys causing shifting of existing keys to alternate "
374 "locations: %d\n\n", tbl_rwc_test_param.count_keys_ks);
375 printf("Count of absent keys that will never be added to the hash "
376 "table: %d\n\n", tbl_rwc_test_param.count_keys_absent);
377 printf("Count of keys likely to be on the shift path: %d\n\n",
378 tbl_rwc_test_param.count_keys_shift_path);
379 printf("Count of keys not likely to be on the shift path: %d\n\n",
380 tbl_rwc_test_param.count_keys_non_shift_path);
383 rte_hash_free(tbl_rwc_test_param.h);
388 rte_free(keys_no_ks);
390 rte_free(keys_absent);
392 rte_free(tbl_rwc_test_param.keys_shift_path);
393 rte_free(scanned_bkts);
398 init_params(int rwc_lf, int use_jhash, int htm)
400 struct rte_hash *handle;
402 struct rte_hash_parameters hash_params = {
403 .entries = TOTAL_ENTRY,
404 .key_len = sizeof(uint32_t),
405 .hash_func_init_val = 0,
406 .socket_id = rte_socket_id(),
410 hash_params.hash_func = rte_jhash;
412 hash_params.hash_func = rte_hash_crc;
415 hash_params.extra_flag =
416 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
417 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
419 hash_params.extra_flag =
420 RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT |
421 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY |
422 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
424 hash_params.extra_flag =
425 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY |
426 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
428 hash_params.name = "tests";
430 handle = rte_hash_create(&hash_params);
431 if (handle == NULL) {
432 printf("hash creation failed");
436 tbl_rwc_test_param.h = handle;
441 test_rwc_reader(__attribute__((unused)) void *arg)
445 uint64_t begin, cycles;
446 uint32_t loop_cnt = 0;
447 uint8_t read_type = (uint8_t)((uintptr_t)arg);
452 void *temp_a[BULK_LOOKUP_SIZE];
454 /* Used to identify keys not inserted in the hash table */
455 pos = rte_zmalloc(NULL, sizeof(uint32_t) * BULK_LOOKUP_SIZE, 0);
457 printf("RTE_MALLOC failed\n");
461 if (read_type & READ_FAIL) {
462 keys = tbl_rwc_test_param.keys_absent;
463 read_cnt = tbl_rwc_test_param.count_keys_absent;
464 } else if (read_type & READ_PASS_NO_KEY_SHIFTS) {
465 keys = tbl_rwc_test_param.keys_no_ks;
466 read_cnt = tbl_rwc_test_param.count_keys_no_ks;
467 } else if (read_type & READ_PASS_SHIFT_PATH) {
468 keys = tbl_rwc_test_param.keys_shift_path;
469 read_cnt = tbl_rwc_test_param.count_keys_shift_path;
471 keys = tbl_rwc_test_param.keys_non_shift_path;
472 read_cnt = tbl_rwc_test_param.count_keys_non_shift_path;
475 extra_keys = read_cnt & (BULK_LOOKUP_SIZE - 1);
477 begin = rte_rdtsc_precise();
479 if (read_type & BULK_LOOKUP) {
480 for (i = 0; i < (read_cnt - extra_keys);
481 i += BULK_LOOKUP_SIZE) {
482 /* Array of pointer to the list of keys */
483 for (j = 0; j < BULK_LOOKUP_SIZE; j++)
484 temp_a[j] = keys + i + j;
486 rte_hash_lookup_bulk(tbl_rwc_test_param.h,
489 BULK_LOOKUP_SIZE, pos);
490 /* Validate lookup result */
491 for (j = 0; j < BULK_LOOKUP_SIZE; j++)
492 if ((read_type & READ_FAIL &&
493 pos[j] != -ENOENT) ||
494 (!(read_type & READ_FAIL) &&
495 pos[j] == -ENOENT)) {
496 printf("lookup failed!"
502 for (j = 0; j < extra_keys; j++)
503 temp_a[j] = keys + i + j;
505 rte_hash_lookup_bulk(tbl_rwc_test_param.h,
509 for (j = 0; j < extra_keys; j++)
510 if ((read_type & READ_FAIL &&
511 pos[j] != -ENOENT) ||
512 (!(read_type & READ_FAIL) &&
513 pos[j] == -ENOENT)) {
514 printf("lookup failed! %"PRIu32"\n",
519 for (i = 0; i < read_cnt; i++) {
520 ret = rte_hash_lookup
521 (tbl_rwc_test_param.h, keys + i);
522 if (((read_type & READ_FAIL) &&
524 (!(read_type & READ_FAIL) &&
526 printf("lookup failed! %"PRIu32"\n",
533 } while (!writer_done);
535 cycles = rte_rdtsc_precise() - begin;
536 rte_atomic64_add(&gread_cycles, cycles);
537 rte_atomic64_add(&greads, read_cnt*loop_cnt);
542 write_keys(uint8_t key_shift)
549 key_cnt = tbl_rwc_test_param.count_keys_ks;
550 keys = tbl_rwc_test_param.keys_ks;
552 key_cnt = tbl_rwc_test_param.count_keys_no_ks;
553 keys = tbl_rwc_test_param.keys_no_ks;
555 for (i = 0; i < key_cnt; i++) {
556 ret = rte_hash_add_key(tbl_rwc_test_param.h, keys + i);
557 if (!key_shift && ret < 0) {
558 printf("writer failed %"PRIu32"\n", i);
566 test_rwc_multi_writer(__attribute__((unused)) void *arg)
569 uint32_t pos_core = (uint32_t)((uintptr_t)arg);
570 offset = pos_core * tbl_rwc_test_param.single_insert;
571 for (i = offset; i < offset + tbl_rwc_test_param.single_insert; i++)
572 rte_hash_add_key(tbl_rwc_test_param.h,
573 tbl_rwc_test_param.keys_ks + i);
574 multi_writer_done[pos_core] = 1;
580 * Reader(s) lookup keys present in the table.
583 test_hash_add_no_ks_lookup_hit(struct rwc_perf *rwc_perf_results, int rwc_lf,
589 uint8_t key_shift = 0;
590 uint8_t read_type = READ_PASS_NO_KEY_SHIFTS;
592 rte_atomic64_init(&greads);
593 rte_atomic64_init(&gread_cycles);
595 if (init_params(rwc_lf, use_jhash, htm) != 0)
597 printf("\nTest: Hash add - no key-shifts, read - hit\n");
598 for (m = 0; m < 2; m++) {
600 printf("\n** With bulk-lookup **\n");
601 read_type |= BULK_LOOKUP;
603 for (n = 0; n < NUM_TEST; n++) {
604 unsigned int tot_lcore = rte_lcore_count();
605 if (tot_lcore < rwc_core_cnt[n] + 1)
608 printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
610 rte_atomic64_clear(&greads);
611 rte_atomic64_clear(&gread_cycles);
613 rte_hash_reset(tbl_rwc_test_param.h);
615 if (write_keys(key_shift) < 0)
618 for (i = 1; i <= rwc_core_cnt[n]; i++)
619 rte_eal_remote_launch(test_rwc_reader,
620 (void *)(uintptr_t)read_type,
621 enabled_core_ids[i]);
622 rte_eal_mp_wait_lcore();
624 for (i = 1; i <= rwc_core_cnt[n]; i++)
625 if (lcore_config[i].ret < 0)
628 unsigned long long cycles_per_lookup =
629 rte_atomic64_read(&gread_cycles) /
630 rte_atomic64_read(&greads);
631 rwc_perf_results->w_no_ks_r_hit[m][n]
633 printf("Cycles per lookup: %llu\n", cycles_per_lookup);
638 rte_hash_free(tbl_rwc_test_param.h);
642 rte_hash_free(tbl_rwc_test_param.h);
648 * Reader(s) lookup keys absent in the table while
649 * 'Main' thread adds with no key-shifts.
652 test_hash_add_no_ks_lookup_miss(struct rwc_perf *rwc_perf_results, int rwc_lf,
658 uint8_t key_shift = 0;
659 uint8_t read_type = READ_FAIL;
662 rte_atomic64_init(&greads);
663 rte_atomic64_init(&gread_cycles);
665 if (init_params(rwc_lf, use_jhash, htm) != 0)
667 printf("\nTest: Hash add - no key-shifts, Hash lookup - miss\n");
668 for (m = 0; m < 2; m++) {
670 printf("\n** With bulk-lookup **\n");
671 read_type |= BULK_LOOKUP;
673 for (n = 0; n < NUM_TEST; n++) {
674 unsigned int tot_lcore = rte_lcore_count();
675 if (tot_lcore < rwc_core_cnt[n] + 1)
678 printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
680 rte_atomic64_clear(&greads);
681 rte_atomic64_clear(&gread_cycles);
683 rte_hash_reset(tbl_rwc_test_param.h);
686 for (i = 1; i <= rwc_core_cnt[n]; i++)
687 rte_eal_remote_launch(test_rwc_reader,
688 (void *)(uintptr_t)read_type,
689 enabled_core_ids[i]);
690 ret = write_keys(key_shift);
692 rte_eal_mp_wait_lcore();
696 for (i = 1; i <= rwc_core_cnt[n]; i++)
697 if (lcore_config[i].ret < 0)
700 unsigned long long cycles_per_lookup =
701 rte_atomic64_read(&gread_cycles) /
702 rte_atomic64_read(&greads);
703 rwc_perf_results->w_no_ks_r_miss[m][n]
705 printf("Cycles per lookup: %llu\n", cycles_per_lookup);
710 rte_hash_free(tbl_rwc_test_param.h);
714 rte_hash_free(tbl_rwc_test_param.h);
720 * Reader(s) lookup keys present in the table and not likely to be on the
721 * shift path while 'Main' thread adds keys causing key-shifts.
724 test_hash_add_ks_lookup_hit_non_sp(struct rwc_perf *rwc_perf_results,
732 uint8_t read_type = READ_PASS_NON_SHIFT_PATH;
734 rte_atomic64_init(&greads);
735 rte_atomic64_init(&gread_cycles);
737 if (init_params(rwc_lf, use_jhash, htm) != 0)
739 printf("\nTest: Hash add - key shift, Hash lookup - hit"
740 " (non-shift-path)\n");
741 for (m = 0; m < 2; m++) {
743 printf("\n** With bulk-lookup **\n");
744 read_type |= BULK_LOOKUP;
746 for (n = 0; n < NUM_TEST; n++) {
747 unsigned int tot_lcore = rte_lcore_count();
748 if (tot_lcore < rwc_core_cnt[n] + 1)
751 printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
753 rte_atomic64_clear(&greads);
754 rte_atomic64_clear(&gread_cycles);
756 rte_hash_reset(tbl_rwc_test_param.h);
759 if (write_keys(key_shift) < 0)
761 for (i = 1; i <= rwc_core_cnt[n]; i++)
762 rte_eal_remote_launch(test_rwc_reader,
763 (void *)(uintptr_t)read_type,
764 enabled_core_ids[i]);
766 ret = write_keys(key_shift);
768 rte_eal_mp_wait_lcore();
772 for (i = 1; i <= rwc_core_cnt[n]; i++)
773 if (lcore_config[i].ret < 0)
776 unsigned long long cycles_per_lookup =
777 rte_atomic64_read(&gread_cycles) /
778 rte_atomic64_read(&greads);
779 rwc_perf_results->w_ks_r_hit_nsp[m][n]
781 printf("Cycles per lookup: %llu\n", cycles_per_lookup);
786 rte_hash_free(tbl_rwc_test_param.h);
790 rte_hash_free(tbl_rwc_test_param.h);
796 * Reader(s) lookup keys present in the table and likely on the shift-path while
797 * 'Main' thread adds keys causing key-shifts.
800 test_hash_add_ks_lookup_hit_sp(struct rwc_perf *rwc_perf_results, int rwc_lf,
808 uint8_t read_type = READ_PASS_SHIFT_PATH;
810 rte_atomic64_init(&greads);
811 rte_atomic64_init(&gread_cycles);
813 if (init_params(rwc_lf, use_jhash, htm) != 0)
815 printf("\nTest: Hash add - key shift, Hash lookup - hit (shift-path)"
818 for (m = 0; m < 2; m++) {
820 printf("\n** With bulk-lookup **\n");
821 read_type |= BULK_LOOKUP;
823 for (n = 0; n < NUM_TEST; n++) {
824 unsigned int tot_lcore = rte_lcore_count();
825 if (tot_lcore < rwc_core_cnt[n])
828 printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
829 rte_atomic64_clear(&greads);
830 rte_atomic64_clear(&gread_cycles);
832 rte_hash_reset(tbl_rwc_test_param.h);
835 if (write_keys(key_shift) < 0)
837 for (i = 1; i <= rwc_core_cnt[n]; i++)
838 rte_eal_remote_launch(test_rwc_reader,
839 (void *)(uintptr_t)read_type,
840 enabled_core_ids[i]);
842 ret = write_keys(key_shift);
844 rte_eal_mp_wait_lcore();
848 for (i = 1; i <= rwc_core_cnt[n]; i++)
849 if (lcore_config[i].ret < 0)
852 unsigned long long cycles_per_lookup =
853 rte_atomic64_read(&gread_cycles) /
854 rte_atomic64_read(&greads);
855 rwc_perf_results->w_ks_r_hit_sp[m][n]
857 printf("Cycles per lookup: %llu\n", cycles_per_lookup);
862 rte_hash_free(tbl_rwc_test_param.h);
866 rte_hash_free(tbl_rwc_test_param.h);
872 * Reader(s) lookup keys absent in the table while
873 * 'Main' thread adds keys causing key-shifts.
876 test_hash_add_ks_lookup_miss(struct rwc_perf *rwc_perf_results, int rwc_lf, int
884 uint8_t read_type = READ_FAIL;
886 rte_atomic64_init(&greads);
887 rte_atomic64_init(&gread_cycles);
889 if (init_params(rwc_lf, use_jhash, htm) != 0)
891 printf("\nTest: Hash add - key shift, Hash lookup - miss\n");
892 for (m = 0; m < 2; m++) {
894 printf("\n** With bulk-lookup **\n");
895 read_type |= BULK_LOOKUP;
897 for (n = 0; n < NUM_TEST; n++) {
898 unsigned int tot_lcore = rte_lcore_count();
899 if (tot_lcore < rwc_core_cnt[n] + 1)
902 printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
904 rte_atomic64_clear(&greads);
905 rte_atomic64_clear(&gread_cycles);
907 rte_hash_reset(tbl_rwc_test_param.h);
910 if (write_keys(key_shift) < 0)
912 for (i = 1; i <= rwc_core_cnt[n]; i++)
913 rte_eal_remote_launch(test_rwc_reader,
914 (void *)(uintptr_t)read_type,
915 enabled_core_ids[i]);
917 ret = write_keys(key_shift);
919 rte_eal_mp_wait_lcore();
923 for (i = 1; i <= rwc_core_cnt[n]; i++)
924 if (lcore_config[i].ret < 0)
927 unsigned long long cycles_per_lookup =
928 rte_atomic64_read(&gread_cycles) /
929 rte_atomic64_read(&greads);
930 rwc_perf_results->w_ks_r_miss[m][n] = cycles_per_lookup;
931 printf("Cycles per lookup: %llu\n", cycles_per_lookup);
936 rte_hash_free(tbl_rwc_test_param.h);
940 rte_hash_free(tbl_rwc_test_param.h);
945 * Test lookup perf for multi-writer:
946 * Reader(s) lookup keys present in the table and likely on the shift-path while
947 * Writers add keys causing key-shiftsi.
948 * Writers are running in parallel, on different data plane cores.
951 test_hash_multi_add_lookup(struct rwc_perf *rwc_perf_results, int rwc_lf,
954 unsigned int n, m, k;
958 uint8_t read_type = READ_PASS_SHIFT_PATH;
960 rte_atomic64_init(&greads);
961 rte_atomic64_init(&gread_cycles);
963 if (init_params(rwc_lf, use_jhash, htm) != 0)
965 printf("\nTest: Multi-add-lookup\n");
967 for (m = 1; m < NUM_TEST; m++) {
968 /* Calculate keys added by each writer */
969 tbl_rwc_test_param.single_insert =
970 tbl_rwc_test_param.count_keys_ks / rwc_core_cnt[m];
971 for (k = 0; k < 2; k++) {
973 printf("\n** With bulk-lookup **\n");
974 read_type |= BULK_LOOKUP;
976 for (n = 0; n < NUM_TEST; n++) {
977 unsigned int tot_lcore = rte_lcore_count();
978 if (tot_lcore < (rwc_core_cnt[n] +
979 rwc_core_cnt[m] + 1))
982 printf("\nNumber of writers: %u",
984 printf("\nNumber of readers: %u\n",
987 rte_atomic64_clear(&greads);
988 rte_atomic64_clear(&gread_cycles);
990 rte_hash_reset(tbl_rwc_test_param.h);
992 for (i = 0; i < 4; i++)
993 multi_writer_done[i] = 0;
995 if (write_keys(key_shift) < 0)
998 /* Launch reader(s) */
999 for (i = 1; i <= rwc_core_cnt[n]; i++)
1000 rte_eal_remote_launch(test_rwc_reader,
1001 (void *)(uintptr_t)read_type,
1002 enabled_core_ids[i]);
1006 /* Launch writers */
1007 for (; i <= rwc_core_cnt[m]
1008 + rwc_core_cnt[n]; i++) {
1009 rte_eal_remote_launch
1010 (test_rwc_multi_writer,
1011 (void *)(uintptr_t)pos_core,
1012 enabled_core_ids[i]);
1016 /* Wait for writers to complete */
1017 for (i = 0; i < rwc_core_cnt[m]; i++)
1019 (multi_writer_done[i] == 0);
1022 rte_eal_mp_wait_lcore();
1024 for (i = 1; i <= rwc_core_cnt[n]; i++)
1025 if (lcore_config[i].ret < 0)
1028 unsigned long long cycles_per_lookup =
1029 rte_atomic64_read(&gread_cycles)
1030 / rte_atomic64_read(&greads);
1031 rwc_perf_results->multi_rw[m][k][n]
1032 = cycles_per_lookup;
1033 printf("Cycles per lookup: %llu\n",
1040 rte_hash_free(tbl_rwc_test_param.h);
1044 rte_hash_free(tbl_rwc_test_param.h);
1049 test_hash_readwrite_lf_main(void)
1052 * Variables used to choose different tests.
1053 * rwc_lf indicates if read-write concurrency lock-free support is
1055 * htm indicates if Hardware transactional memory support is enabled.
1060 if (rte_lcore_count() == 1) {
1061 printf("More than one lcore is required "
1062 "to do read write lock-free concurrency test\n");
1066 setlocale(LC_NUMERIC, "");
1068 if (rte_tm_supported())
1073 if (init_params(rwc_lf, use_jhash, htm) != 0)
1075 if (generate_keys() != 0)
1077 if (get_enabled_cores_list() != 0)
1080 if (RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF) {
1082 printf("Test lookup with read-write concurrency lock free support"
1084 if (test_hash_add_no_ks_lookup_hit(&rwc_lf_results, rwc_lf,
1087 if (test_hash_add_no_ks_lookup_miss(&rwc_lf_results, rwc_lf,
1090 if (test_hash_add_ks_lookup_hit_non_sp(&rwc_lf_results, rwc_lf,
1093 if (test_hash_add_ks_lookup_hit_sp(&rwc_lf_results, rwc_lf,
1096 if (test_hash_add_ks_lookup_miss(&rwc_lf_results, rwc_lf, htm)
1099 if (test_hash_multi_add_lookup(&rwc_lf_results, rwc_lf, htm)
1103 printf("\nTest lookup with read-write concurrency lock free support"
1107 printf("With HTM Disabled\n");
1108 if (!RUN_WITH_HTM_DISABLED) {
1109 printf("Enable RUN_WITH_HTM_DISABLED to test with"
1110 " lock-free disabled");
1114 printf("With HTM Enabled\n");
1115 if (test_hash_add_no_ks_lookup_hit(&rwc_non_lf_results, rwc_lf, htm)
1118 if (test_hash_add_no_ks_lookup_miss(&rwc_non_lf_results, rwc_lf, htm)
1121 if (test_hash_add_ks_lookup_hit_non_sp(&rwc_non_lf_results, rwc_lf,
1124 if (test_hash_add_ks_lookup_hit_sp(&rwc_non_lf_results, rwc_lf, htm)
1127 if (test_hash_add_ks_lookup_miss(&rwc_non_lf_results, rwc_lf, htm) < 0)
1129 if (test_hash_multi_add_lookup(&rwc_non_lf_results, rwc_lf, htm) < 0)
1132 printf("\n\t\t\t\t\t\t********** Results summary **********\n\n");
1134 for (j = 0; j < 2; j++) {
1136 printf("\n\t\t\t\t\t#######********** Bulk Lookup "
1137 "**********#######\n\n");
1138 printf("_______\t\t_______\t\t_________\t___\t\t_________\t\t"
1139 "\t\t\t\t_________________\n");
1140 printf("Writers\t\tReaders\t\tLock-free\tHTM\t\tTest-case\t\t\t"
1141 "\t\t\tCycles per lookup\n");
1142 printf("_______\t\t_______\t\t_________\t___\t\t_________\t\t\t"
1143 "\t\t\t_________________\n");
1144 for (i = 0; i < NUM_TEST; i++) {
1145 printf("%u\t\t%u\t\t", 1, rwc_core_cnt[i]);
1146 printf("Enabled\t\t");
1148 printf("Hash add - no key-shifts, lookup - hit\t\t\t\t"
1149 "%u\n\t\t\t\t\t\t\t\t",
1150 rwc_lf_results.w_no_ks_r_hit[j][i]);
1151 printf("Hash add - no key-shifts, lookup - miss\t\t\t\t"
1152 "%u\n\t\t\t\t\t\t\t\t",
1153 rwc_lf_results.w_no_ks_r_miss[j][i]);
1154 printf("Hash add - key-shifts, lookup - hit"
1155 "(non-shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1156 rwc_lf_results.w_ks_r_hit_nsp[j][i]);
1157 printf("Hash add - key-shifts, lookup - hit "
1158 "(shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1159 rwc_lf_results.w_ks_r_hit_sp[j][i]);
1160 printf("Hash add - key-shifts, Hash lookup miss\t\t\t\t"
1162 rwc_lf_results.w_ks_r_miss[j][i]);
1164 printf("Disabled\t");
1166 printf("Enabled\t\t");
1168 printf("Disabled\t");
1169 printf("Hash add - no key-shifts, lookup - hit\t\t\t\t"
1170 "%u\n\t\t\t\t\t\t\t\t",
1171 rwc_non_lf_results.w_no_ks_r_hit[j][i]);
1172 printf("Hash add - no key-shifts, lookup - miss\t\t\t\t"
1173 "%u\n\t\t\t\t\t\t\t\t",
1174 rwc_non_lf_results.w_no_ks_r_miss[j][i]);
1175 printf("Hash add - key-shifts, lookup - hit "
1176 "(non-shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1177 rwc_non_lf_results.w_ks_r_hit_nsp[j][i]);
1178 printf("Hash add - key-shifts, lookup - hit "
1179 "(shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1180 rwc_non_lf_results.w_ks_r_hit_sp[j][i]);
1181 printf("Hash add - key-shifts, Hash lookup miss\t\t\t\t"
1182 "%u\n", rwc_non_lf_results.w_ks_r_miss[j][i]);
1184 printf("_______\t\t_______\t\t_________\t___\t\t"
1185 "_________\t\t\t\t\t\t_________________\n");
1188 for (i = 1; i < NUM_TEST; i++) {
1189 for (k = 0; k < NUM_TEST; k++) {
1190 printf("%u", rwc_core_cnt[i]);
1191 printf("\t\t%u\t\t", rwc_core_cnt[k]);
1192 printf("Enabled\t\t");
1194 printf("Multi-add-lookup\t\t\t\t\t\t%u\n\n\t\t"
1196 rwc_lf_results.multi_rw[i][j][k]);
1197 printf("Disabled\t");
1199 printf("Enabled\t\t");
1201 printf("Disabled\t");
1202 printf("Multi-add-lookup\t\t\t\t\t\t%u\n",
1203 rwc_non_lf_results.multi_rw[i][j][k]);
1205 printf("_______\t\t_______\t\t_________\t___"
1206 "\t\t_________\t\t\t\t\t\t"
1207 "_________________\n");
1211 rte_free(tbl_rwc_test_param.keys);
1212 rte_free(tbl_rwc_test_param.keys_no_ks);
1213 rte_free(tbl_rwc_test_param.keys_ks);
1214 rte_free(tbl_rwc_test_param.keys_absent);
1215 rte_free(tbl_rwc_test_param.keys_shift_path);
1216 rte_free(scanned_bkts);
1220 REGISTER_TEST_COMMAND(hash_readwrite_lf_autotest, test_hash_readwrite_lf_main);