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
44 #define READ_PASS_KEY_SHIFTS_EXTBKT 32
46 #define WRITE_NO_KEY_SHIFT 0
47 #define WRITE_KEY_SHIFT 1
48 #define WRITE_EXT_BKT 2
51 unsigned int rwc_core_cnt
[NUM_TEST
] = {1, 2, 4};
54 uint32_t w_no_ks_r_hit
[2][NUM_TEST
];
55 uint32_t w_no_ks_r_miss
[2][NUM_TEST
];
56 uint32_t w_ks_r_hit_nsp
[2][NUM_TEST
];
57 uint32_t w_ks_r_hit_sp
[2][NUM_TEST
];
58 uint32_t w_ks_r_miss
[2][NUM_TEST
];
59 uint32_t multi_rw
[NUM_TEST
- 1][2][NUM_TEST
];
60 uint32_t w_ks_r_hit_extbkt
[2][NUM_TEST
];
63 static struct rwc_perf rwc_lf_results
, rwc_non_lf_results
;
69 uint32_t *keys_absent
;
70 uint32_t *keys_shift_path
;
71 uint32_t *keys_non_shift_path
;
72 uint32_t *keys_ext_bkt
;
73 uint32_t *keys_ks_extbkt
;
74 uint32_t count_keys_no_ks
;
75 uint32_t count_keys_ks
;
76 uint32_t count_keys_absent
;
77 uint32_t count_keys_shift_path
;
78 uint32_t count_keys_non_shift_path
;
79 uint32_t count_keys_extbkt
;
80 uint32_t count_keys_ks_extbkt
;
81 uint32_t single_insert
;
85 static rte_atomic64_t gread_cycles
;
86 static rte_atomic64_t greads
;
88 static volatile uint8_t writer_done
;
89 static volatile uint8_t multi_writer_done
[4];
91 uint16_t enabled_core_ids
[RTE_MAX_LCORE
];
93 uint8_t *scanned_bkts
;
95 static inline uint16_t
96 get_short_sig(const hash_sig_t hash
)
101 static inline uint32_t
102 get_prim_bucket_index(__attribute__((unused
)) const struct rte_hash
*h
,
103 const hash_sig_t hash
)
105 uint32_t num_buckets
;
106 uint32_t bucket_bitmask
;
107 num_buckets
= rte_align32pow2(TOTAL_ENTRY
) / 8;
108 bucket_bitmask
= num_buckets
- 1;
109 return hash
& bucket_bitmask
;
112 static inline uint32_t
113 get_alt_bucket_index(__attribute__((unused
)) const struct rte_hash
*h
,
114 uint32_t cur_bkt_idx
, uint16_t sig
)
116 uint32_t num_buckets
;
117 uint32_t bucket_bitmask
;
118 num_buckets
= rte_align32pow2(TOTAL_ENTRY
) / 8;
119 bucket_bitmask
= num_buckets
- 1;
120 return (cur_bkt_idx
^ sig
) & bucket_bitmask
;
125 get_enabled_cores_list(void)
129 uint32_t max_cores
= rte_lcore_count();
130 for (core_id
= 0; core_id
< RTE_MAX_LCORE
&& i
< max_cores
; core_id
++) {
131 if (rte_lcore_is_enabled(core_id
)) {
132 enabled_core_ids
[i
] = core_id
;
137 if (i
!= max_cores
) {
138 printf("Number of enabled cores in list is different from "
139 "number given by rte_lcore_count()\n");
146 check_bucket(uint32_t bkt_idx
, uint32_t key
)
152 const void *next_key
;
155 /* Temporary bucket to hold the keys */
156 uint32_t keys_in_bkt
[8];
160 while (rte_hash_iterate(tbl_rwc_test_param
.h
,
161 &next_key
, &next_data
, &iter
) >= 0) {
163 /* Check for duplicate entries */
164 if (*(const uint32_t *)next_key
== key
)
167 /* Identify if there is any free entry in the bucket */
168 diff
= iter
- prev_iter
;
173 keys_in_bkt
[count
] = *(const uint32_t *)next_key
;
176 /* All entries in the bucket are occupied */
180 * Check if bucket was not scanned before, to avoid
183 if (scanned_bkts
[bkt_idx
] == 0) {
185 * Since this bucket (pointed to by bkt_idx) is
186 * full, it is likely that key(s) in this
187 * bucket will be on the shift path, when
188 * collision occurs. Thus, add it to
191 memcpy(tbl_rwc_test_param
.keys_shift_path
+
192 tbl_rwc_test_param
.count_keys_shift_path
194 tbl_rwc_test_param
.count_keys_shift_path
+= 8;
195 scanned_bkts
[bkt_idx
] = 1;
206 uint32_t *keys
= NULL
;
207 uint32_t *keys_no_ks
= NULL
;
208 uint32_t *keys_ks
= NULL
;
209 uint32_t *keys_absent
= NULL
;
210 uint32_t *keys_non_shift_path
= NULL
;
211 uint32_t *keys_ext_bkt
= NULL
;
212 uint32_t *keys_ks_extbkt
= NULL
;
213 uint32_t *found
= NULL
;
214 uint32_t count_keys_no_ks
= 0;
215 uint32_t count_keys_ks
= 0;
216 uint32_t count_keys_extbkt
= 0;
220 * keys will consist of a) keys whose addition to the hash table
221 * will result in shifting of the existing keys to their alternate
222 * locations b) keys whose addition to the hash table will not result
223 * in shifting of the existing keys.
225 keys
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
227 printf("RTE_MALLOC failed\n");
232 * keys_no_ks (no key-shifts): Subset of 'keys' - consists of keys that
233 * will NOT result in shifting of the existing keys to their alternate
234 * locations. Roughly around 900K keys.
236 keys_no_ks
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
237 if (keys_no_ks
== NULL
) {
238 printf("RTE_MALLOC failed\n");
243 * keys_ks (key-shifts): Subset of 'keys' - consists of keys that will
244 * result in shifting of the existing keys to their alternate locations.
245 * Roughly around 146K keys. There might be repeating keys. More code is
246 * required to filter out these keys which will complicate the test case
248 keys_ks
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
249 if (keys_ks
== NULL
) {
250 printf("RTE_MALLOC failed\n");
254 /* Used to identify keys not inserted in the hash table */
255 found
= rte_zmalloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
257 printf("RTE_MALLOC failed\n");
262 * This consist of keys not inserted to the hash table.
263 * Used to test perf of lookup on keys that do not exist in the table.
265 keys_absent
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
266 if (keys_absent
== NULL
) {
267 printf("RTE_MALLOC failed\n");
272 * This consist of keys which are likely to be on the shift
273 * path (i.e. being moved to alternate location), when collision occurs
274 * on addition of a key to an already full primary bucket.
275 * Used to test perf of lookup on keys that are on the shift path.
277 tbl_rwc_test_param
.keys_shift_path
= rte_malloc(NULL
, sizeof(uint32_t) *
279 if (tbl_rwc_test_param
.keys_shift_path
== NULL
) {
280 printf("RTE_MALLOC failed\n");
285 * This consist of keys which are never on the shift
286 * path (i.e. being moved to alternate location), when collision occurs
287 * on addition of a key to an already full primary bucket.
288 * Used to test perf of lookup on keys that are not on the shift path.
290 keys_non_shift_path
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
,
292 if (keys_non_shift_path
== NULL
) {
293 printf("RTE_MALLOC failed\n");
298 * This consist of keys which will be stored in extended buckets
300 keys_ext_bkt
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
301 if (keys_ext_bkt
== NULL
) {
302 printf("RTE_MALLOC failed\n");
307 * This consist of keys which when deleted causes shifting of keys
308 * in extended buckets to respective secondary buckets
310 keys_ks_extbkt
= rte_malloc(NULL
, sizeof(uint32_t) * TOTAL_INSERT
, 0);
311 if (keys_ks_extbkt
== NULL
) {
312 printf("RTE_MALLOC failed\n");
317 uint32_t prim_bucket_idx
;
318 uint32_t sec_bucket_idx
;
320 uint32_t num_buckets
;
321 num_buckets
= rte_align32pow2(TOTAL_ENTRY
) / 8;
325 * Used to mark bkts in which at least one key was shifted to its
328 scanned_bkts
= rte_malloc(NULL
, sizeof(uint8_t) * num_buckets
, 0);
329 if (scanned_bkts
== NULL
) {
330 printf("RTE_MALLOC failed\n");
334 tbl_rwc_test_param
.keys
= keys
;
335 tbl_rwc_test_param
.keys_no_ks
= keys_no_ks
;
336 tbl_rwc_test_param
.keys_ks
= keys_ks
;
337 tbl_rwc_test_param
.keys_absent
= keys_absent
;
338 tbl_rwc_test_param
.keys_non_shift_path
= keys_non_shift_path
;
339 tbl_rwc_test_param
.keys_ext_bkt
= keys_ext_bkt
;
340 tbl_rwc_test_param
.keys_ks_extbkt
= keys_ks_extbkt
;
341 /* Generate keys by adding previous two keys, neglect overflow */
342 printf("Generating keys...\n");
345 for (i
= 2; i
< TOTAL_INSERT
; i
++)
346 keys
[i
] = keys
[i
-1] + keys
[i
-2];
348 /* Segregate keys into keys_no_ks and keys_ks */
349 for (i
= 0; i
< TOTAL_INSERT
; i
++) {
350 /* Check if primary bucket has space.*/
351 sig
= rte_hash_hash(tbl_rwc_test_param
.h
,
352 tbl_rwc_test_param
.keys
+i
);
353 prim_bucket_idx
= get_prim_bucket_index(tbl_rwc_test_param
.h
,
355 ret
= check_bucket(prim_bucket_idx
, keys
[i
]);
358 * Primary bucket is full, this key will result in
359 * shifting of the keys to their alternate locations.
361 keys_ks
[count_keys_ks
] = keys
[i
];
363 } else if (ret
== 0) {
365 * Primary bucket has space, this key will not result in
366 * shifting of the keys. Hence, add key to the table.
368 ret
= rte_hash_add_key_data(tbl_rwc_test_param
.h
,
370 (void *)((uintptr_t)i
));
372 printf("writer failed %"PRIu32
"\n", i
);
375 keys_no_ks
[count_keys_no_ks
] = keys
[i
];
380 for (i
= 0; i
< count_keys_no_ks
; i
++) {
382 * Identify keys in keys_no_ks with value less than
383 * 4M (HTM enabled) OR 5K (HTM disabled)
385 if (keys_no_ks
[i
] < TOTAL_INSERT
)
386 found
[keys_no_ks
[i
]]++;
389 for (i
= 0; i
< count_keys_ks
; i
++) {
391 * Identify keys in keys_ks with value less than
392 * 4M (HTM enabled) OR 5K (HTM disabled)
394 if (keys_ks
[i
] < TOTAL_INSERT
)
398 uint32_t count_keys_absent
= 0;
399 for (i
= 0; i
< TOTAL_INSERT
; i
++) {
401 * Identify missing keys between 0 and
402 * 4M (HTM enabled) OR 5K (HTM disabled)
405 keys_absent
[count_keys_absent
++] = i
;
408 /* Find keys that will not be on the shift path */
410 const void *next_key
;
413 for (i
= 0; i
< num_buckets
; i
++) {
414 /* Check bucket for no keys shifted to alternate locations */
415 if (scanned_bkts
[i
] == 0) {
417 while (rte_hash_iterate(tbl_rwc_test_param
.h
,
418 &next_key
, &next_data
, &iter
) >= 0) {
420 /* Check if key belongs to the current bucket */
422 keys_non_shift_path
[count
++]
423 = *(const uint32_t *)next_key
;
430 tbl_rwc_test_param
.count_keys_no_ks
= count_keys_no_ks
;
431 tbl_rwc_test_param
.count_keys_ks
= count_keys_ks
;
432 tbl_rwc_test_param
.count_keys_absent
= count_keys_absent
;
433 tbl_rwc_test_param
.count_keys_non_shift_path
= count
;
435 memset(scanned_bkts
, 0, num_buckets
);
437 /* Find keys that will be in extended buckets */
438 for (i
= 0; i
< count_keys_ks
; i
++) {
439 ret
= rte_hash_add_key(tbl_rwc_test_param
.h
, keys_ks
+ i
);
441 /* Key will be added to ext bkt */
442 keys_ext_bkt
[count_keys_extbkt
++] = keys_ks
[i
];
443 /* Sec bkt to be added to keys_ks_extbkt */
444 sig
= rte_hash_hash(tbl_rwc_test_param
.h
,
445 tbl_rwc_test_param
.keys_ks
+ i
);
446 prim_bucket_idx
= get_prim_bucket_index(
447 tbl_rwc_test_param
.h
, sig
);
448 short_sig
= get_short_sig(sig
);
449 sec_bucket_idx
= get_alt_bucket_index(
450 tbl_rwc_test_param
.h
,
451 prim_bucket_idx
, short_sig
);
452 if (scanned_bkts
[sec_bucket_idx
] == 0)
453 scanned_bkts
[sec_bucket_idx
] = 1;
457 /* Find keys that will shift keys in ext bucket*/
458 for (i
= 0; i
< num_buckets
; i
++) {
459 if (scanned_bkts
[i
] == 1) {
461 while (rte_hash_iterate(tbl_rwc_test_param
.h
,
462 &next_key
, &next_data
, &iter
) >= 0) {
463 /* Check if key belongs to the current bucket */
465 keys_ks_extbkt
[count
++]
466 = *(const uint32_t *)next_key
;
473 tbl_rwc_test_param
.count_keys_ks_extbkt
= count
;
474 tbl_rwc_test_param
.count_keys_extbkt
= count_keys_extbkt
;
476 printf("\nCount of keys NOT causing shifting of existing keys to "
477 "alternate location: %d\n", tbl_rwc_test_param
.count_keys_no_ks
);
478 printf("\nCount of keys causing shifting of existing keys to alternate "
479 "locations: %d\n\n", tbl_rwc_test_param
.count_keys_ks
);
480 printf("Count of absent keys that will never be added to the hash "
481 "table: %d\n\n", tbl_rwc_test_param
.count_keys_absent
);
482 printf("Count of keys likely to be on the shift path: %d\n\n",
483 tbl_rwc_test_param
.count_keys_shift_path
);
484 printf("Count of keys not likely to be on the shift path: %d\n\n",
485 tbl_rwc_test_param
.count_keys_non_shift_path
);
486 printf("Count of keys in extended buckets: %d\n\n",
487 tbl_rwc_test_param
.count_keys_extbkt
);
488 printf("Count of keys shifting keys in ext buckets: %d\n\n",
489 tbl_rwc_test_param
.count_keys_ks_extbkt
);
492 rte_hash_free(tbl_rwc_test_param
.h
);
497 rte_free(keys_no_ks
);
499 rte_free(keys_absent
);
501 rte_free(tbl_rwc_test_param
.keys_shift_path
);
502 rte_free(keys_ext_bkt
);
503 rte_free(keys_ks_extbkt
);
504 rte_free(scanned_bkts
);
509 init_params(int rwc_lf
, int use_jhash
, int htm
, int ext_bkt
)
511 struct rte_hash
*handle
;
513 struct rte_hash_parameters hash_params
= {
514 .entries
= TOTAL_ENTRY
,
515 .key_len
= sizeof(uint32_t),
516 .hash_func_init_val
= 0,
517 .socket_id
= rte_socket_id(),
521 hash_params
.hash_func
= rte_jhash
;
523 hash_params
.hash_func
= rte_hash_crc
;
526 hash_params
.extra_flag
=
527 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF
|
528 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD
;
530 hash_params
.extra_flag
=
531 RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
|
532 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY
|
533 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD
;
535 hash_params
.extra_flag
=
536 RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY
|
537 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD
;
540 hash_params
.extra_flag
|= RTE_HASH_EXTRA_FLAGS_EXT_TABLE
;
542 hash_params
.name
= "tests";
544 handle
= rte_hash_create(&hash_params
);
545 if (handle
== NULL
) {
546 printf("hash creation failed");
550 tbl_rwc_test_param
.h
= handle
;
555 test_rwc_reader(__attribute__((unused
)) void *arg
)
559 uint64_t begin
, cycles
;
560 uint32_t loop_cnt
= 0;
561 uint8_t read_type
= (uint8_t)((uintptr_t)arg
);
566 void *temp_a
[BULK_LOOKUP_SIZE
];
568 /* Used to identify keys not inserted in the hash table */
569 pos
= rte_malloc(NULL
, sizeof(uint32_t) * BULK_LOOKUP_SIZE
, 0);
571 printf("RTE_MALLOC failed\n");
575 if (read_type
& READ_FAIL
) {
576 keys
= tbl_rwc_test_param
.keys_absent
;
577 read_cnt
= tbl_rwc_test_param
.count_keys_absent
;
578 } else if (read_type
& READ_PASS_NO_KEY_SHIFTS
) {
579 keys
= tbl_rwc_test_param
.keys_no_ks
;
580 read_cnt
= tbl_rwc_test_param
.count_keys_no_ks
;
581 } else if (read_type
& READ_PASS_SHIFT_PATH
) {
582 keys
= tbl_rwc_test_param
.keys_shift_path
;
583 read_cnt
= tbl_rwc_test_param
.count_keys_shift_path
;
584 } else if (read_type
& READ_PASS_KEY_SHIFTS_EXTBKT
) {
585 keys
= tbl_rwc_test_param
.keys_ext_bkt
;
586 read_cnt
= tbl_rwc_test_param
.count_keys_extbkt
;
588 keys
= tbl_rwc_test_param
.keys_non_shift_path
;
589 read_cnt
= tbl_rwc_test_param
.count_keys_non_shift_path
;
592 extra_keys
= read_cnt
& (BULK_LOOKUP_SIZE
- 1);
594 begin
= rte_rdtsc_precise();
596 if (read_type
& BULK_LOOKUP
) {
597 for (i
= 0; i
< (read_cnt
- extra_keys
);
598 i
+= BULK_LOOKUP_SIZE
) {
599 /* Array of pointer to the list of keys */
600 for (j
= 0; j
< BULK_LOOKUP_SIZE
; j
++)
601 temp_a
[j
] = keys
+ i
+ j
;
602 rte_hash_lookup_bulk(tbl_rwc_test_param
.h
,
605 BULK_LOOKUP_SIZE
, pos
);
606 /* Validate lookup result */
607 for (j
= 0; j
< BULK_LOOKUP_SIZE
; j
++)
608 if ((read_type
& READ_FAIL
&&
609 pos
[j
] != -ENOENT
) ||
610 (!(read_type
& READ_FAIL
) &&
611 pos
[j
] == -ENOENT
)) {
612 printf("lookup failed!"
618 for (j
= 0; j
< extra_keys
; j
++)
619 temp_a
[j
] = keys
+ i
+ j
;
621 rte_hash_lookup_bulk(tbl_rwc_test_param
.h
,
625 for (j
= 0; j
< extra_keys
; j
++)
626 if ((read_type
& READ_FAIL
&&
627 pos
[j
] != -ENOENT
) ||
628 (!(read_type
& READ_FAIL
) &&
629 pos
[j
] == -ENOENT
)) {
630 printf("lookup failed! %"PRIu32
"\n",
635 for (i
= 0; i
< read_cnt
; i
++) {
636 ret
= rte_hash_lookup
637 (tbl_rwc_test_param
.h
, keys
+ i
);
638 if (((read_type
& READ_FAIL
) &&
640 (!(read_type
& READ_FAIL
) &&
642 printf("lookup failed! %"PRIu32
"\n",
649 } while (!writer_done
);
651 cycles
= rte_rdtsc_precise() - begin
;
652 rte_atomic64_add(&gread_cycles
, cycles
);
653 rte_atomic64_add(&greads
, read_cnt
*loop_cnt
);
658 write_keys(uint8_t write_type
)
662 uint32_t key_cnt
= 0;
664 if (write_type
== WRITE_KEY_SHIFT
) {
665 key_cnt
= tbl_rwc_test_param
.count_keys_ks
;
666 keys
= tbl_rwc_test_param
.keys_ks
;
667 } else if (write_type
== WRITE_NO_KEY_SHIFT
) {
668 key_cnt
= tbl_rwc_test_param
.count_keys_no_ks
;
669 keys
= tbl_rwc_test_param
.keys_no_ks
;
670 } else if (write_type
== WRITE_EXT_BKT
) {
671 key_cnt
= tbl_rwc_test_param
.count_keys_extbkt
;
672 keys
= tbl_rwc_test_param
.keys_ext_bkt
;
674 for (i
= 0; i
< key_cnt
; i
++) {
675 ret
= rte_hash_add_key(tbl_rwc_test_param
.h
, keys
+ i
);
676 if ((write_type
== WRITE_NO_KEY_SHIFT
) && ret
< 0) {
677 printf("writer failed %"PRIu32
"\n", i
);
685 test_rwc_multi_writer(__attribute__((unused
)) void *arg
)
688 uint32_t pos_core
= (uint32_t)((uintptr_t)arg
);
689 offset
= pos_core
* tbl_rwc_test_param
.single_insert
;
690 for (i
= offset
; i
< offset
+ tbl_rwc_test_param
.single_insert
; i
++)
691 rte_hash_add_key(tbl_rwc_test_param
.h
,
692 tbl_rwc_test_param
.keys_ks
+ i
);
693 multi_writer_done
[pos_core
] = 1;
699 * Reader(s) lookup keys present in the table.
702 test_hash_add_no_ks_lookup_hit(struct rwc_perf
*rwc_perf_results
, int rwc_lf
,
703 int htm
, int ext_bkt
)
708 uint8_t write_type
= WRITE_NO_KEY_SHIFT
;
709 uint8_t read_type
= READ_PASS_NO_KEY_SHIFTS
;
711 rte_atomic64_init(&greads
);
712 rte_atomic64_init(&gread_cycles
);
714 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
716 printf("\nTest: Hash add - no key-shifts, read - hit\n");
717 for (m
= 0; m
< 2; m
++) {
719 printf("\n** With bulk-lookup **\n");
720 read_type
|= BULK_LOOKUP
;
722 for (n
= 0; n
< NUM_TEST
; n
++) {
723 unsigned int tot_lcore
= rte_lcore_count();
724 if (tot_lcore
< rwc_core_cnt
[n
] + 1)
727 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
729 rte_atomic64_clear(&greads
);
730 rte_atomic64_clear(&gread_cycles
);
732 rte_hash_reset(tbl_rwc_test_param
.h
);
734 if (write_keys(write_type
) < 0)
737 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
738 rte_eal_remote_launch(test_rwc_reader
,
739 (void *)(uintptr_t)read_type
,
740 enabled_core_ids
[i
]);
741 rte_eal_mp_wait_lcore();
743 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
744 if (lcore_config
[i
].ret
< 0)
747 unsigned long long cycles_per_lookup
=
748 rte_atomic64_read(&gread_cycles
) /
749 rte_atomic64_read(&greads
);
750 rwc_perf_results
->w_no_ks_r_hit
[m
][n
]
752 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
757 rte_hash_free(tbl_rwc_test_param
.h
);
761 rte_hash_free(tbl_rwc_test_param
.h
);
767 * Reader(s) lookup keys absent in the table while
768 * 'Main' thread adds with no key-shifts.
771 test_hash_add_no_ks_lookup_miss(struct rwc_perf
*rwc_perf_results
, int rwc_lf
,
772 int htm
, int ext_bkt
)
777 uint8_t write_type
= WRITE_NO_KEY_SHIFT
;
778 uint8_t read_type
= READ_FAIL
;
781 rte_atomic64_init(&greads
);
782 rte_atomic64_init(&gread_cycles
);
784 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
786 printf("\nTest: Hash add - no key-shifts, Hash lookup - miss\n");
787 for (m
= 0; m
< 2; m
++) {
789 printf("\n** With bulk-lookup **\n");
790 read_type
|= BULK_LOOKUP
;
792 for (n
= 0; n
< NUM_TEST
; n
++) {
793 unsigned int tot_lcore
= rte_lcore_count();
794 if (tot_lcore
< rwc_core_cnt
[n
] + 1)
797 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
799 rte_atomic64_clear(&greads
);
800 rte_atomic64_clear(&gread_cycles
);
802 rte_hash_reset(tbl_rwc_test_param
.h
);
805 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
806 rte_eal_remote_launch(test_rwc_reader
,
807 (void *)(uintptr_t)read_type
,
808 enabled_core_ids
[i
]);
809 ret
= write_keys(write_type
);
811 rte_eal_mp_wait_lcore();
815 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
816 if (lcore_config
[i
].ret
< 0)
819 unsigned long long cycles_per_lookup
=
820 rte_atomic64_read(&gread_cycles
) /
821 rte_atomic64_read(&greads
);
822 rwc_perf_results
->w_no_ks_r_miss
[m
][n
]
824 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
829 rte_hash_free(tbl_rwc_test_param
.h
);
833 rte_hash_free(tbl_rwc_test_param
.h
);
839 * Reader(s) lookup keys present in the table and not likely to be on the
840 * shift path while 'Main' thread adds keys causing key-shifts.
843 test_hash_add_ks_lookup_hit_non_sp(struct rwc_perf
*rwc_perf_results
,
844 int rwc_lf
, int htm
, int ext_bkt
)
851 uint8_t read_type
= READ_PASS_NON_SHIFT_PATH
;
853 rte_atomic64_init(&greads
);
854 rte_atomic64_init(&gread_cycles
);
856 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
858 printf("\nTest: Hash add - key shift, Hash lookup - hit"
859 " (non-shift-path)\n");
860 for (m
= 0; m
< 2; m
++) {
862 printf("\n** With bulk-lookup **\n");
863 read_type
|= BULK_LOOKUP
;
865 for (n
= 0; n
< NUM_TEST
; n
++) {
866 unsigned int tot_lcore
= rte_lcore_count();
867 if (tot_lcore
< rwc_core_cnt
[n
] + 1)
870 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
872 rte_atomic64_clear(&greads
);
873 rte_atomic64_clear(&gread_cycles
);
875 rte_hash_reset(tbl_rwc_test_param
.h
);
877 write_type
= WRITE_NO_KEY_SHIFT
;
878 if (write_keys(write_type
) < 0)
880 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
881 rte_eal_remote_launch(test_rwc_reader
,
882 (void *)(uintptr_t)read_type
,
883 enabled_core_ids
[i
]);
884 write_type
= WRITE_KEY_SHIFT
;
885 ret
= write_keys(write_type
);
887 rte_eal_mp_wait_lcore();
891 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
892 if (lcore_config
[i
].ret
< 0)
895 unsigned long long cycles_per_lookup
=
896 rte_atomic64_read(&gread_cycles
) /
897 rte_atomic64_read(&greads
);
898 rwc_perf_results
->w_ks_r_hit_nsp
[m
][n
]
900 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
905 rte_hash_free(tbl_rwc_test_param
.h
);
909 rte_hash_free(tbl_rwc_test_param
.h
);
915 * Reader(s) lookup keys present in the table and likely on the shift-path while
916 * 'Main' thread adds keys causing key-shifts.
919 test_hash_add_ks_lookup_hit_sp(struct rwc_perf
*rwc_perf_results
, int rwc_lf
,
920 int htm
, int ext_bkt
)
927 uint8_t read_type
= READ_PASS_SHIFT_PATH
;
929 rte_atomic64_init(&greads
);
930 rte_atomic64_init(&gread_cycles
);
932 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
934 printf("\nTest: Hash add - key shift, Hash lookup - hit (shift-path)"
937 for (m
= 0; m
< 2; m
++) {
939 printf("\n** With bulk-lookup **\n");
940 read_type
|= BULK_LOOKUP
;
942 for (n
= 0; n
< NUM_TEST
; n
++) {
943 unsigned int tot_lcore
= rte_lcore_count();
944 if (tot_lcore
< rwc_core_cnt
[n
])
947 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
948 rte_atomic64_clear(&greads
);
949 rte_atomic64_clear(&gread_cycles
);
951 rte_hash_reset(tbl_rwc_test_param
.h
);
953 write_type
= WRITE_NO_KEY_SHIFT
;
954 if (write_keys(write_type
) < 0)
956 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
957 rte_eal_remote_launch(test_rwc_reader
,
958 (void *)(uintptr_t)read_type
,
959 enabled_core_ids
[i
]);
960 write_type
= WRITE_KEY_SHIFT
;
961 ret
= write_keys(write_type
);
963 rte_eal_mp_wait_lcore();
967 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
968 if (lcore_config
[i
].ret
< 0)
971 unsigned long long cycles_per_lookup
=
972 rte_atomic64_read(&gread_cycles
) /
973 rte_atomic64_read(&greads
);
974 rwc_perf_results
->w_ks_r_hit_sp
[m
][n
]
976 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
981 rte_hash_free(tbl_rwc_test_param
.h
);
985 rte_hash_free(tbl_rwc_test_param
.h
);
991 * Reader(s) lookup keys absent in the table while
992 * 'Main' thread adds keys causing key-shifts.
995 test_hash_add_ks_lookup_miss(struct rwc_perf
*rwc_perf_results
, int rwc_lf
, int
1003 uint8_t read_type
= READ_FAIL
;
1005 rte_atomic64_init(&greads
);
1006 rte_atomic64_init(&gread_cycles
);
1008 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
1010 printf("\nTest: Hash add - key shift, Hash lookup - miss\n");
1011 for (m
= 0; m
< 2; m
++) {
1013 printf("\n** With bulk-lookup **\n");
1014 read_type
|= BULK_LOOKUP
;
1016 for (n
= 0; n
< NUM_TEST
; n
++) {
1017 unsigned int tot_lcore
= rte_lcore_count();
1018 if (tot_lcore
< rwc_core_cnt
[n
] + 1)
1021 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
1023 rte_atomic64_clear(&greads
);
1024 rte_atomic64_clear(&gread_cycles
);
1026 rte_hash_reset(tbl_rwc_test_param
.h
);
1028 write_type
= WRITE_NO_KEY_SHIFT
;
1029 if (write_keys(write_type
) < 0)
1031 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1032 rte_eal_remote_launch(test_rwc_reader
,
1033 (void *)(uintptr_t)read_type
,
1034 enabled_core_ids
[i
]);
1035 write_type
= WRITE_KEY_SHIFT
;
1036 ret
= write_keys(write_type
);
1038 rte_eal_mp_wait_lcore();
1042 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1043 if (lcore_config
[i
].ret
< 0)
1046 unsigned long long cycles_per_lookup
=
1047 rte_atomic64_read(&gread_cycles
) /
1048 rte_atomic64_read(&greads
);
1049 rwc_perf_results
->w_ks_r_miss
[m
][n
] = cycles_per_lookup
;
1050 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
1055 rte_hash_free(tbl_rwc_test_param
.h
);
1059 rte_hash_free(tbl_rwc_test_param
.h
);
1064 * Test lookup perf for multi-writer:
1065 * Reader(s) lookup keys present in the table and likely on the shift-path while
1066 * Writers add keys causing key-shiftsi.
1067 * Writers are running in parallel, on different data plane cores.
1070 test_hash_multi_add_lookup(struct rwc_perf
*rwc_perf_results
, int rwc_lf
,
1071 int htm
, int ext_bkt
)
1073 unsigned int n
, m
, k
;
1077 uint8_t read_type
= READ_PASS_SHIFT_PATH
;
1079 rte_atomic64_init(&greads
);
1080 rte_atomic64_init(&gread_cycles
);
1082 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
1084 printf("\nTest: Multi-add-lookup\n");
1086 for (m
= 1; m
< NUM_TEST
; m
++) {
1087 /* Calculate keys added by each writer */
1088 tbl_rwc_test_param
.single_insert
=
1089 tbl_rwc_test_param
.count_keys_ks
/ rwc_core_cnt
[m
];
1090 for (k
= 0; k
< 2; k
++) {
1092 printf("\n** With bulk-lookup **\n");
1093 read_type
|= BULK_LOOKUP
;
1095 for (n
= 0; n
< NUM_TEST
; n
++) {
1096 unsigned int tot_lcore
= rte_lcore_count();
1097 if (tot_lcore
< (rwc_core_cnt
[n
] +
1098 rwc_core_cnt
[m
] + 1))
1101 printf("\nNumber of writers: %u",
1103 printf("\nNumber of readers: %u\n",
1106 rte_atomic64_clear(&greads
);
1107 rte_atomic64_clear(&gread_cycles
);
1109 rte_hash_reset(tbl_rwc_test_param
.h
);
1111 for (i
= 0; i
< 4; i
++)
1112 multi_writer_done
[i
] = 0;
1113 write_type
= WRITE_NO_KEY_SHIFT
;
1114 if (write_keys(write_type
) < 0)
1117 /* Launch reader(s) */
1118 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1119 rte_eal_remote_launch(test_rwc_reader
,
1120 (void *)(uintptr_t)read_type
,
1121 enabled_core_ids
[i
]);
1122 write_type
= WRITE_KEY_SHIFT
;
1125 /* Launch writers */
1126 for (; i
<= rwc_core_cnt
[m
]
1127 + rwc_core_cnt
[n
]; i
++) {
1128 rte_eal_remote_launch
1129 (test_rwc_multi_writer
,
1130 (void *)(uintptr_t)pos_core
,
1131 enabled_core_ids
[i
]);
1135 /* Wait for writers to complete */
1136 for (i
= 0; i
< rwc_core_cnt
[m
]; i
++)
1138 (multi_writer_done
[i
] == 0);
1141 rte_eal_mp_wait_lcore();
1143 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1144 if (lcore_config
[i
].ret
< 0)
1147 unsigned long long cycles_per_lookup
=
1148 rte_atomic64_read(&gread_cycles
)
1149 / rte_atomic64_read(&greads
);
1150 rwc_perf_results
->multi_rw
[m
][k
][n
]
1151 = cycles_per_lookup
;
1152 printf("Cycles per lookup: %llu\n",
1159 rte_hash_free(tbl_rwc_test_param
.h
);
1163 rte_hash_free(tbl_rwc_test_param
.h
);
1169 * Reader(s) lookup keys present in the extendable bkt.
1172 test_hash_add_ks_lookup_hit_extbkt(struct rwc_perf
*rwc_perf_results
,
1173 int rwc_lf
, int htm
, int ext_bkt
)
1179 uint8_t read_type
= READ_PASS_KEY_SHIFTS_EXTBKT
;
1181 rte_atomic64_init(&greads
);
1182 rte_atomic64_init(&gread_cycles
);
1184 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
1186 printf("\nTest: Hash add - key-shifts, read - hit (ext_bkt)\n");
1187 for (m
= 0; m
< 2; m
++) {
1189 printf("\n** With bulk-lookup **\n");
1190 read_type
|= BULK_LOOKUP
;
1192 for (n
= 0; n
< NUM_TEST
; n
++) {
1193 unsigned int tot_lcore
= rte_lcore_count();
1194 if (tot_lcore
< rwc_core_cnt
[n
] + 1)
1197 printf("\nNumber of readers: %u\n", rwc_core_cnt
[n
]);
1199 rte_atomic64_clear(&greads
);
1200 rte_atomic64_clear(&gread_cycles
);
1202 rte_hash_reset(tbl_rwc_test_param
.h
);
1203 write_type
= WRITE_NO_KEY_SHIFT
;
1204 if (write_keys(write_type
) < 0)
1206 write_type
= WRITE_KEY_SHIFT
;
1207 if (write_keys(write_type
) < 0)
1210 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1211 rte_eal_remote_launch(test_rwc_reader
,
1212 (void *)(uintptr_t)read_type
,
1213 enabled_core_ids
[i
]);
1214 for (i
= 0; i
< tbl_rwc_test_param
.count_keys_ks_extbkt
;
1216 if (rte_hash_del_key(tbl_rwc_test_param
.h
,
1217 tbl_rwc_test_param
.keys_ks_extbkt
+ i
)
1219 printf("Delete Failed: %u\n",
1220 tbl_rwc_test_param
.keys_ks_extbkt
[i
]);
1225 rte_eal_mp_wait_lcore();
1227 for (i
= 1; i
<= rwc_core_cnt
[n
]; i
++)
1228 if (lcore_config
[i
].ret
< 0)
1231 unsigned long long cycles_per_lookup
=
1232 rte_atomic64_read(&gread_cycles
) /
1233 rte_atomic64_read(&greads
);
1234 rwc_perf_results
->w_ks_r_hit_extbkt
[m
][n
]
1235 = cycles_per_lookup
;
1236 printf("Cycles per lookup: %llu\n", cycles_per_lookup
);
1241 rte_hash_free(tbl_rwc_test_param
.h
);
1245 rte_hash_free(tbl_rwc_test_param
.h
);
1250 test_hash_readwrite_lf_main(void)
1253 * Variables used to choose different tests.
1254 * rwc_lf indicates if read-write concurrency lock-free support is
1256 * htm indicates if Hardware transactional memory support is enabled.
1262 if (rte_lcore_count() == 1) {
1263 printf("More than one lcore is required "
1264 "to do read write lock-free concurrency test\n");
1268 setlocale(LC_NUMERIC
, "");
1270 if (rte_tm_supported())
1275 if (init_params(rwc_lf
, use_jhash
, htm
, ext_bkt
) != 0)
1277 if (generate_keys() != 0)
1279 if (get_enabled_cores_list() != 0)
1282 if (RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF
) {
1285 printf("Test lookup with read-write concurrency lock free support"
1287 if (test_hash_add_no_ks_lookup_hit(&rwc_lf_results
, rwc_lf
,
1290 if (test_hash_add_no_ks_lookup_miss(&rwc_lf_results
, rwc_lf
,
1293 if (test_hash_add_ks_lookup_hit_non_sp(&rwc_lf_results
, rwc_lf
,
1296 if (test_hash_add_ks_lookup_hit_sp(&rwc_lf_results
, rwc_lf
,
1299 if (test_hash_add_ks_lookup_miss(&rwc_lf_results
, rwc_lf
, htm
,
1302 if (test_hash_multi_add_lookup(&rwc_lf_results
, rwc_lf
, htm
,
1305 if (test_hash_add_ks_lookup_hit_extbkt(&rwc_lf_results
, rwc_lf
,
1309 printf("\nTest lookup with read-write concurrency lock free support"
1313 printf("With HTM Disabled\n");
1314 if (!RUN_WITH_HTM_DISABLED
) {
1315 printf("Enable RUN_WITH_HTM_DISABLED to test with"
1316 " lock-free disabled");
1320 printf("With HTM Enabled\n");
1321 if (test_hash_add_no_ks_lookup_hit(&rwc_non_lf_results
, rwc_lf
, htm
,
1324 if (test_hash_add_no_ks_lookup_miss(&rwc_non_lf_results
, rwc_lf
, htm
,
1327 if (test_hash_add_ks_lookup_hit_non_sp(&rwc_non_lf_results
, rwc_lf
,
1330 if (test_hash_add_ks_lookup_hit_sp(&rwc_non_lf_results
, rwc_lf
, htm
,
1333 if (test_hash_add_ks_lookup_miss(&rwc_non_lf_results
, rwc_lf
, htm
,
1336 if (test_hash_multi_add_lookup(&rwc_non_lf_results
, rwc_lf
, htm
,
1339 if (test_hash_add_ks_lookup_hit_extbkt(&rwc_non_lf_results
, rwc_lf
,
1343 printf("\n\t\t\t\t\t\t********** Results summary **********\n\n");
1345 for (j
= 0; j
< 2; j
++) {
1347 printf("\n\t\t\t\t\t#######********** Bulk Lookup "
1348 "**********#######\n\n");
1349 printf("_______\t\t_______\t\t_________\t___\t\t_________\t\t"
1350 "\t\t\t\t_________________\n");
1351 printf("Writers\t\tReaders\t\tLock-free\tHTM\t\tTest-case\t\t\t"
1352 "\t\t\tCycles per lookup\n");
1353 printf("_______\t\t_______\t\t_________\t___\t\t_________\t\t\t"
1354 "\t\t\t_________________\n");
1355 for (i
= 0; i
< NUM_TEST
; i
++) {
1356 printf("%u\t\t%u\t\t", 1, rwc_core_cnt
[i
]);
1357 printf("Enabled\t\t");
1359 printf("Hash add - no key-shifts, lookup - hit\t\t\t\t"
1360 "%u\n\t\t\t\t\t\t\t\t",
1361 rwc_lf_results
.w_no_ks_r_hit
[j
][i
]);
1362 printf("Hash add - no key-shifts, lookup - miss\t\t\t\t"
1363 "%u\n\t\t\t\t\t\t\t\t",
1364 rwc_lf_results
.w_no_ks_r_miss
[j
][i
]);
1365 printf("Hash add - key-shifts, lookup - hit"
1366 "(non-shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1367 rwc_lf_results
.w_ks_r_hit_nsp
[j
][i
]);
1368 printf("Hash add - key-shifts, lookup - hit "
1369 "(shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1370 rwc_lf_results
.w_ks_r_hit_sp
[j
][i
]);
1371 printf("Hash add - key-shifts, Hash lookup miss\t\t\t\t"
1372 "%u\n\t\t\t\t\t\t\t\t",
1373 rwc_lf_results
.w_ks_r_miss
[j
][i
]);
1374 printf("Hash add - key-shifts, Hash lookup hit (ext_bkt)\t\t"
1376 rwc_lf_results
.w_ks_r_hit_extbkt
[j
][i
]);
1378 printf("Disabled\t");
1380 printf("Enabled\t\t");
1382 printf("Disabled\t");
1383 printf("Hash add - no key-shifts, lookup - hit\t\t\t\t"
1384 "%u\n\t\t\t\t\t\t\t\t",
1385 rwc_non_lf_results
.w_no_ks_r_hit
[j
][i
]);
1386 printf("Hash add - no key-shifts, lookup - miss\t\t\t\t"
1387 "%u\n\t\t\t\t\t\t\t\t",
1388 rwc_non_lf_results
.w_no_ks_r_miss
[j
][i
]);
1389 printf("Hash add - key-shifts, lookup - hit "
1390 "(non-shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1391 rwc_non_lf_results
.w_ks_r_hit_nsp
[j
][i
]);
1392 printf("Hash add - key-shifts, lookup - hit "
1393 "(shift-path)\t\t%u\n\t\t\t\t\t\t\t\t",
1394 rwc_non_lf_results
.w_ks_r_hit_sp
[j
][i
]);
1395 printf("Hash add - key-shifts, Hash lookup miss\t\t\t\t"
1396 "%u\n\t\t\t\t\t\t\t\t",
1397 rwc_non_lf_results
.w_ks_r_miss
[j
][i
]);
1398 printf("Hash add - key-shifts, Hash lookup hit (ext_bkt)\t\t"
1400 rwc_non_lf_results
.w_ks_r_hit_extbkt
[j
][i
]);
1402 printf("_______\t\t_______\t\t_________\t___\t\t"
1403 "_________\t\t\t\t\t\t_________________\n");
1406 for (i
= 1; i
< NUM_TEST
; i
++) {
1407 for (k
= 0; k
< NUM_TEST
; k
++) {
1408 printf("%u", rwc_core_cnt
[i
]);
1409 printf("\t\t%u\t\t", rwc_core_cnt
[k
]);
1410 printf("Enabled\t\t");
1412 printf("Multi-add-lookup\t\t\t\t\t\t%u\n\n\t\t"
1414 rwc_lf_results
.multi_rw
[i
][j
][k
]);
1415 printf("Disabled\t");
1417 printf("Enabled\t\t");
1419 printf("Disabled\t");
1420 printf("Multi-add-lookup\t\t\t\t\t\t%u\n",
1421 rwc_non_lf_results
.multi_rw
[i
][j
][k
]);
1423 printf("_______\t\t_______\t\t_________\t___"
1424 "\t\t_________\t\t\t\t\t\t"
1425 "_________________\n");
1429 rte_free(tbl_rwc_test_param
.keys
);
1430 rte_free(tbl_rwc_test_param
.keys_no_ks
);
1431 rte_free(tbl_rwc_test_param
.keys_ks
);
1432 rte_free(tbl_rwc_test_param
.keys_absent
);
1433 rte_free(tbl_rwc_test_param
.keys_shift_path
);
1434 rte_free(scanned_bkts
);
1438 REGISTER_TEST_COMMAND(hash_readwrite_lf_autotest
, test_hash_readwrite_lf_main
);