1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Intel Corporation
9 #include <rte_cycles.h>
10 #include <rte_malloc.h>
11 #include <rte_random.h>
12 #include <rte_memcpy.h>
13 #include <rte_thash.h>
14 #include <rte_member.h>
18 #define NUM_KEYSIZES 10
19 #define NUM_SHUFFLES 10
20 #define MAX_KEYSIZE 64
21 #define MAX_ENTRIES (1 << 19)
22 #define KEYS_TO_ADD (MAX_ENTRIES * 75 / 100) /* 75% table utilization */
23 #define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
24 #define VBF_SET_CNT 16
26 #define VBF_FALSE_RATE 0.03
28 static unsigned int test_socket_id
;
48 struct member_perf_params
{
49 struct rte_member_setsum
*setsum
[NUM_TYPE
];
54 static uint32_t hashtest_key_lens
[] = {
55 /* standard key sizes */
57 /* IPv4 SRC + DST + protocol, unpadded */
59 /* IPv4 5-tuple, unpadded */
61 /* IPv6 5-tuple, unpadded */
63 /* IPv6 5-tuple, padded to 8-byte boundary */
67 /* Array to store number of cycles per operation */
68 uint64_t cycles
[NUM_TYPE
][NUM_KEYSIZES
][NUM_OPERATIONS
];
69 uint64_t false_data
[NUM_TYPE
][NUM_KEYSIZES
];
70 uint64_t false_data_bulk
[NUM_TYPE
][NUM_KEYSIZES
];
71 uint64_t false_data_multi
[NUM_TYPE
][NUM_KEYSIZES
];
72 uint64_t false_data_multi_bulk
[NUM_TYPE
][NUM_KEYSIZES
];
74 uint64_t false_hit
[NUM_TYPE
][NUM_KEYSIZES
];
76 member_set_t data
[NUM_TYPE
][/* Array to store the data */KEYS_TO_ADD
];
78 /* Array to store all input keys */
79 uint8_t keys
[KEYS_TO_ADD
][MAX_KEYSIZE
];
81 /* Shuffle the keys that have been added, so lookups will be totally random */
83 shuffle_input_keys(struct member_perf_params
*params
)
85 member_set_t temp_data
;
88 uint8_t temp_key
[MAX_KEYSIZE
];
90 for (i
= KEYS_TO_ADD
- 1; i
> 0; i
--) {
91 swap_idx
= rte_rand() % i
;
92 memcpy(temp_key
, keys
[i
], hashtest_key_lens
[params
->cycle
]);
93 memcpy(keys
[i
], keys
[swap_idx
],
94 hashtest_key_lens
[params
->cycle
]);
95 memcpy(keys
[swap_idx
], temp_key
,
96 hashtest_key_lens
[params
->cycle
]);
97 for (j
= 0; j
< NUM_TYPE
; j
++) {
98 temp_data
= data
[j
][i
];
99 data
[j
][i
] = data
[j
][swap_idx
];
100 data
[j
][swap_idx
] = temp_data
;
105 static int key_compare(const void *key1
, const void *key2
)
107 return memcmp(key1
, key2
, MAX_KEYSIZE
);
110 struct rte_member_parameters member_params
= {
111 .num_keys
= MAX_ENTRIES
, /* Total hash table entries. */
112 .key_len
= 4, /* Length of hash key. */
114 /* num_set and false_positive_rate only relevant to vBF */
115 .num_set
= VBF_SET_CNT
,
116 .false_positive_rate
= 0.03,
119 .socket_id
= 0, /* NUMA Socket ID for memory. */
123 setup_keys_and_data(struct member_perf_params
*params
, unsigned int cycle
,
129 params
->key_size
= hashtest_key_lens
[cycle
];
130 params
->cycle
= cycle
;
132 /* Reset all arrays */
133 for (i
= 0; i
< params
->key_size
; i
++)
136 /* Generate a list of keys, some of which may be duplicates */
137 for (i
= 0; i
< KEYS_TO_ADD
; i
++) {
138 for (j
= 0; j
< params
->key_size
; j
++)
139 keys
[i
][j
] = rte_rand() & 0xFF;
141 data
[HT
][i
] = data
[CACHE
][i
] = (rte_rand() & 0x7FFE) + 1;
142 data
[VBF
][i
] = rte_rand() % VBF_SET_CNT
+ 1;
145 /* Remove duplicates from the keys array */
149 /* Sort the list of keys to make it easier to find duplicates */
150 qsort(keys
, KEYS_TO_ADD
, MAX_KEYSIZE
, key_compare
);
152 /* Sift through the list of keys and look for duplicates */
153 int num_duplicates
= 0;
154 for (i
= 0; i
< KEYS_TO_ADD
- 1; i
++) {
155 if (memcmp(keys
[i
], keys
[i
+ 1],
156 params
->key_size
) == 0) {
157 /* This key already exists, try again */
159 for (j
= 0; j
< params
->key_size
; j
++)
160 keys
[i
][j
] = rte_rand() & 0xFF;
163 } while (num_duplicates
!= 0);
165 /* Shuffle the random values again */
166 shuffle_input_keys(params
);
168 /* For testing miss lookup, we insert half and lookup the other half */
169 unsigned int entry_cnt
, bf_key_cnt
;
171 entry_cnt
= MAX_ENTRIES
;
172 bf_key_cnt
= KEYS_TO_ADD
;
174 entry_cnt
= MAX_ENTRIES
/ 2;
175 bf_key_cnt
= KEYS_TO_ADD
/ 2;
177 member_params
.false_positive_rate
= VBF_FALSE_RATE
;
178 member_params
.key_len
= params
->key_size
;
179 member_params
.socket_id
= test_socket_id
;
180 member_params
.num_keys
= entry_cnt
;
181 member_params
.name
= "test_member_ht";
182 member_params
.is_cache
= 0;
183 member_params
.type
= RTE_MEMBER_TYPE_HT
;
184 params
->setsum
[HT
] = rte_member_create(&member_params
);
185 if (params
->setsum
[HT
] == NULL
)
186 fprintf(stderr
, "ht create fail\n");
188 member_params
.name
= "test_member_cache";
189 member_params
.is_cache
= 1;
190 params
->setsum
[CACHE
] = rte_member_create(&member_params
);
191 if (params
->setsum
[CACHE
] == NULL
)
192 fprintf(stderr
, "CACHE create fail\n");
194 member_params
.name
= "test_member_vbf";
195 member_params
.type
= RTE_MEMBER_TYPE_VBF
;
196 member_params
.num_keys
= bf_key_cnt
;
197 params
->setsum
[VBF
] = rte_member_create(&member_params
);
198 if (params
->setsum
[VBF
] == NULL
)
199 fprintf(stderr
, "VBF create fail\n");
200 for (i
= 0; i
< NUM_TYPE
; i
++) {
201 if (params
->setsum
[i
] == NULL
)
209 timed_adds(struct member_perf_params
*params
, int type
)
211 const uint64_t start_tsc
= rte_rdtsc();
215 for (i
= 0; i
< KEYS_TO_ADD
; i
++) {
216 ret
= rte_member_add(params
->setsum
[type
], &keys
[i
],
219 printf("Error %d in rte_member_add - key=0x", ret
);
220 for (a
= 0; a
< params
->key_size
; a
++)
221 printf("%02x", keys
[i
][a
]);
222 printf(" value=%d, type: %d\n", data
[type
][i
], type
);
228 const uint64_t end_tsc
= rte_rdtsc();
229 const uint64_t time_taken
= end_tsc
- start_tsc
;
231 cycles
[type
][params
->cycle
][ADD
] = time_taken
/ KEYS_TO_ADD
;
236 timed_lookups(struct member_perf_params
*params
, int type
)
240 false_data
[type
][params
->cycle
] = 0;
242 const uint64_t start_tsc
= rte_rdtsc();
246 for (i
= 0; i
< NUM_LOOKUPS
/ KEYS_TO_ADD
; i
++) {
247 for (j
= 0; j
< KEYS_TO_ADD
; j
++) {
248 ret
= rte_member_lookup(params
->setsum
[type
], &keys
[j
],
251 printf("lookup wrong internally");
254 if (type
== HT
&& result
== RTE_MEMBER_NO_MATCH
) {
255 printf("HT mode shouldn't have false negative");
258 if (result
!= data
[type
][j
])
259 false_data
[type
][params
->cycle
]++;
263 const uint64_t end_tsc
= rte_rdtsc();
264 const uint64_t time_taken
= end_tsc
- start_tsc
;
266 cycles
[type
][params
->cycle
][LOOKUP
] = time_taken
/ NUM_LOOKUPS
;
272 timed_lookups_bulk(struct member_perf_params
*params
, int type
)
274 unsigned int i
, j
, k
;
275 member_set_t result
[BURST_SIZE
] = {0};
276 const void *keys_burst
[BURST_SIZE
];
279 false_data_bulk
[type
][params
->cycle
] = 0;
281 const uint64_t start_tsc
= rte_rdtsc();
283 for (i
= 0; i
< NUM_LOOKUPS
/ KEYS_TO_ADD
; i
++) {
284 for (j
= 0; j
< KEYS_TO_ADD
/ BURST_SIZE
; j
++) {
285 for (k
= 0; k
< BURST_SIZE
; k
++)
286 keys_burst
[k
] = keys
[j
* BURST_SIZE
+ k
];
288 ret
= rte_member_lookup_bulk(params
->setsum
[type
],
293 printf("lookup bulk has wrong return value\n");
296 for (k
= 0; k
< BURST_SIZE
; k
++) {
297 uint32_t data_idx
= j
* BURST_SIZE
+ k
;
298 if (type
== HT
&& result
[k
] ==
299 RTE_MEMBER_NO_MATCH
) {
300 printf("HT mode shouldn't have "
304 if (result
[k
] != data
[type
][data_idx
])
305 false_data_bulk
[type
][params
->cycle
]++;
310 const uint64_t end_tsc
= rte_rdtsc();
311 const uint64_t time_taken
= end_tsc
- start_tsc
;
313 cycles
[type
][params
->cycle
][LOOKUP_BULK
] = time_taken
/ NUM_LOOKUPS
;
319 timed_lookups_multimatch(struct member_perf_params
*params
, int type
)
322 member_set_t result
[RTE_MEMBER_BUCKET_ENTRIES
] = {0};
324 false_data_multi
[type
][params
->cycle
] = 0;
326 const uint64_t start_tsc
= rte_rdtsc();
328 for (i
= 0; i
< NUM_LOOKUPS
/ KEYS_TO_ADD
; i
++) {
329 for (j
= 0; j
< KEYS_TO_ADD
; j
++) {
330 ret
= rte_member_lookup_multi(params
->setsum
[type
],
331 &keys
[j
], RTE_MEMBER_BUCKET_ENTRIES
, result
);
332 if (type
!= CACHE
&& ret
<= 0) {
333 printf("lookup multi has wrong return value %d,"
334 "type %d\n", ret
, type
);
336 if (type
== HT
&& ret
== 0) {
337 printf("HT mode shouldn't have false negative");
341 * For performance test purpose, we do not iterate all
342 * results here. We assume most likely each key can only
343 * find one match which is result[0].
345 if (result
[0] != data
[type
][j
])
346 false_data_multi
[type
][params
->cycle
]++;
350 const uint64_t end_tsc
= rte_rdtsc();
351 const uint64_t time_taken
= end_tsc
- start_tsc
;
353 cycles
[type
][params
->cycle
][LOOKUP_MULTI
] = time_taken
/ NUM_LOOKUPS
;
359 timed_lookups_multimatch_bulk(struct member_perf_params
*params
, int type
)
361 unsigned int i
, j
, k
;
362 member_set_t result
[BURST_SIZE
][RTE_MEMBER_BUCKET_ENTRIES
] = {{0} };
363 const void *keys_burst
[BURST_SIZE
];
364 uint32_t match_count
[BURST_SIZE
];
367 false_data_multi_bulk
[type
][params
->cycle
] = 0;
369 const uint64_t start_tsc
= rte_rdtsc();
371 for (i
= 0; i
< NUM_LOOKUPS
/ KEYS_TO_ADD
; i
++) {
372 for (j
= 0; j
< KEYS_TO_ADD
/ BURST_SIZE
; j
++) {
373 for (k
= 0; k
< BURST_SIZE
; k
++)
374 keys_burst
[k
] = keys
[j
* BURST_SIZE
+ k
];
376 ret
= rte_member_lookup_multi_bulk(
377 params
->setsum
[type
],
378 keys_burst
, BURST_SIZE
,
379 RTE_MEMBER_BUCKET_ENTRIES
, match_count
,
380 (member_set_t
*)result
);
382 printf("lookup multimatch bulk has wrong return"
386 for (k
= 0; k
< BURST_SIZE
; k
++) {
387 if (type
!= CACHE
&& match_count
[k
] == 0) {
388 printf("lookup multimatch bulk get "
389 "wrong match count\n");
392 if (type
== HT
&& match_count
[k
] == 0) {
393 printf("HT mode shouldn't have "
397 uint32_t data_idx
= j
* BURST_SIZE
+ k
;
398 if (result
[k
][0] != data
[type
][data_idx
])
399 false_data_multi_bulk
[type
][params
->cycle
]++;
404 const uint64_t end_tsc
= rte_rdtsc();
405 const uint64_t time_taken
= end_tsc
- start_tsc
;
407 cycles
[type
][params
->cycle
][LOOKUP_MULTI_BULK
] = time_taken
/
414 timed_deletes(struct member_perf_params
*params
, int type
)
421 const uint64_t start_tsc
= rte_rdtsc();
422 for (i
= 0; i
< KEYS_TO_ADD
; i
++) {
423 ret
= rte_member_delete(params
->setsum
[type
], &keys
[i
],
425 if (type
!= CACHE
&& ret
< 0) {
426 printf("delete error\n");
431 const uint64_t end_tsc
= rte_rdtsc();
432 const uint64_t time_taken
= end_tsc
- start_tsc
;
434 cycles
[type
][params
->cycle
][DELETE
] = time_taken
/ KEYS_TO_ADD
;
440 timed_miss_lookup(struct member_perf_params
*params
, int type
)
445 false_hit
[type
][params
->cycle
] = 0;
447 for (i
= 0; i
< KEYS_TO_ADD
/ 2; i
++) {
448 ret
= rte_member_add(params
->setsum
[type
], &keys
[i
],
452 printf("Error %d in rte_member_add - key=0x", ret
);
453 for (a
= 0; a
< params
->key_size
; a
++)
454 printf("%02x", keys
[i
][a
]);
455 printf(" value=%d, type: %d\n", data
[type
][i
], type
);
461 const uint64_t start_tsc
= rte_rdtsc();
464 for (i
= 0; i
< 2 * NUM_LOOKUPS
/ KEYS_TO_ADD
; i
++) {
465 for (j
= KEYS_TO_ADD
/ 2; j
< KEYS_TO_ADD
; j
++) {
466 ret
= rte_member_lookup(params
->setsum
[type
], &keys
[j
],
469 printf("lookup wrong internally");
472 if (result
!= RTE_MEMBER_NO_MATCH
)
473 false_hit
[type
][params
->cycle
]++;
477 const uint64_t end_tsc
= rte_rdtsc();
478 const uint64_t time_taken
= end_tsc
- start_tsc
;
480 cycles
[type
][params
->cycle
][LOOKUP_MISS
] = time_taken
/ NUM_LOOKUPS
;
486 perform_frees(struct member_perf_params
*params
)
489 for (i
= 0; i
< NUM_TYPE
; i
++) {
490 if (params
->setsum
[i
] != NULL
) {
491 rte_member_free(params
->setsum
[i
]);
492 params
->setsum
[i
] = NULL
;
498 exit_with_fail(const char *testname
, struct member_perf_params
*params
,
499 unsigned int i
, unsigned int j
)
501 printf("<<<<<Test %s failed at keysize %d iteration %d type %d>>>>>\n",
502 testname
, hashtest_key_lens
[params
->cycle
], i
, j
);
503 perform_frees(params
);
508 run_all_tbl_perf_tests(void)
510 unsigned int i
, j
, k
;
511 struct member_perf_params params
;
513 printf("Measuring performance, please wait\n");
516 test_socket_id
= rte_socket_id();
518 for (i
= 0; i
< NUM_KEYSIZES
; i
++) {
519 if (setup_keys_and_data(¶ms
, i
, 0) < 0) {
520 printf("Could not create keys/data/table\n");
523 for (j
= 0; j
< NUM_TYPE
; j
++) {
525 if (timed_adds(¶ms
, j
) < 0)
526 return exit_with_fail("timed_adds", ¶ms
,
529 for (k
= 0; k
< NUM_SHUFFLES
; k
++)
530 shuffle_input_keys(¶ms
);
532 if (timed_lookups(¶ms
, j
) < 0)
533 return exit_with_fail("timed_lookups", ¶ms
,
536 if (timed_lookups_bulk(¶ms
, j
) < 0)
537 return exit_with_fail("timed_lookups_bulk",
540 if (timed_lookups_multimatch(¶ms
, j
) < 0)
541 return exit_with_fail("timed_lookups_multi",
544 if (timed_lookups_multimatch_bulk(¶ms
, j
) < 0)
545 return exit_with_fail("timed_lookups_multi_bulk",
548 if (timed_deletes(¶ms
, j
) < 0)
549 return exit_with_fail("timed_deletes", ¶ms
,
552 /* Print a dot to show progress on operations */
557 perform_frees(¶ms
);
560 /* Test false positive rate using un-inserted keys */
561 for (i
= 0; i
< NUM_KEYSIZES
; i
++) {
562 if (setup_keys_and_data(¶ms
, i
, 1) < 0) {
563 printf("Could not create keys/data/table\n");
566 for (j
= 0; j
< NUM_TYPE
; j
++) {
567 if (timed_miss_lookup(¶ms
, j
) < 0)
568 return exit_with_fail("timed_miss_lookup",
571 perform_frees(¶ms
);
574 printf("\nResults (in CPU cycles/operation)\n");
575 printf("-----------------------------------\n");
576 printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
577 "Keysize", "type", "Add", "Lookup", "Lookup_bulk",
578 "lookup_multi", "lookup_multi_bulk", "Delete",
580 for (i
= 0; i
< NUM_KEYSIZES
; i
++) {
581 for (j
= 0; j
< NUM_TYPE
; j
++) {
582 printf("%-18d", hashtest_key_lens
[i
]);
584 for (k
= 0; k
< NUM_OPERATIONS
; k
++)
585 printf("%-18"PRIu64
, cycles
[j
][i
][k
]);
590 printf("\nFalse results rate (and false positive rate)\n");
591 printf("-----------------------------------\n");
592 printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
593 "Keysize", "type", "fr_single", "fr_bulk", "fr_multi",
594 "fr_multi_bulk", "false_positive_rate");
595 /* Key size not influence False rate so just print out one key size */
596 for (i
= 0; i
< 1; i
++) {
597 for (j
= 0; j
< NUM_TYPE
; j
++) {
598 printf("%-18d", hashtest_key_lens
[i
]);
600 printf("%-18f", (float)false_data
[j
][i
] / NUM_LOOKUPS
);
601 printf("%-18f", (float)false_data_bulk
[j
][i
] /
603 printf("%-18f", (float)false_data_multi
[j
][i
] /
605 printf("%-18f", (float)false_data_multi_bulk
[j
][i
] /
607 printf("%-18f", (float)false_hit
[j
][i
] /
616 test_member_perf(void)
619 if (run_all_tbl_perf_tests() < 0)
625 REGISTER_TEST_COMMAND(member_perf_autotest
, test_member_perf
);