1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2015 Intel Corporation
3 */
4
5 #include <stdio.h>
6 #include <inttypes.h>
7
8 #include <rte_lcore.h>
9 #include <rte_cycles.h>
10 #include <rte_malloc.h>
11 #include <rte_hash.h>
12 #include <rte_hash_crc.h>
13 #include <rte_jhash.h>
14 #include <rte_fbk_hash.h>
15 #include <rte_random.h>
16 #include <rte_string_fns.h>
17
18 #include "test.h"
19
20 #define MAX_ENTRIES (1 << 19)
21 #define KEYS_TO_ADD (MAX_ENTRIES)
22 #define ADD_PERCENT 0.75 /* 75% table utilization */
23 #define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
24 /* BUCKET_SIZE should be same as RTE_HASH_BUCKET_ENTRIES in rte_hash library */
25 #define BUCKET_SIZE 8
26 #define NUM_BUCKETS (MAX_ENTRIES / BUCKET_SIZE)
27 #define MAX_KEYSIZE 64
28 #define NUM_KEYSIZES 10
29 #define NUM_SHUFFLES 10
30 #define BURST_SIZE 16
31
32 enum operations {
33 ADD = 0,
34 LOOKUP,
35 LOOKUP_MULTI,
36 DELETE,
37 NUM_OPERATIONS
38 };
39
40 static uint32_t hashtest_key_lens[] = {
41 /* standard key sizes */
42 4, 8, 16, 32, 48, 64,
43 /* IPv4 SRC + DST + protocol, unpadded */
44 9,
45 /* IPv4 5-tuple, unpadded */
46 13,
47 /* IPv6 5-tuple, unpadded */
48 37,
49 /* IPv6 5-tuple, padded to 8-byte boundary */
50 40
51 };
52
53 struct rte_hash *h[NUM_KEYSIZES];
54
55 /* Array that stores if a slot is full */
56 static uint8_t slot_taken[MAX_ENTRIES];
57
58 /* Array to store number of cycles per operation */
59 static uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2][2];
60
61 /* Array to store all input keys */
62 static uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];
63
64 /* Array to store the precomputed hash for 'keys' */
65 static hash_sig_t signatures[KEYS_TO_ADD];
66
67 /* Array to store how many busy entries have each bucket */
68 static uint8_t buckets[NUM_BUCKETS];
69
70 /* Array to store the positions where keys are added */
71 static int32_t positions[KEYS_TO_ADD];
72
73 /* Parameters used for hash table in unit test functions. */
74 static struct rte_hash_parameters ut_params = {
75 .entries = MAX_ENTRIES,
76 .hash_func = rte_jhash,
77 .hash_func_init_val = 0,
78 };
79
80 static int
create_table(unsigned int with_data,unsigned int table_index,unsigned int with_locks,unsigned int ext)81 create_table(unsigned int with_data, unsigned int table_index,
82 unsigned int with_locks, unsigned int ext)
83 {
84 char name[RTE_HASH_NAMESIZE];
85
86 if (with_data)
87 /* Table will store 8-byte data */
88 snprintf(name, sizeof(name), "test_hash%u_data",
89 hashtest_key_lens[table_index]);
90 else
91 snprintf(name, sizeof(name), "test_hash%u",
92 hashtest_key_lens[table_index]);
93
94
95 if (with_locks)
96 ut_params.extra_flag =
97 RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
98 | RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY;
99 else
100 ut_params.extra_flag = 0;
101
102 if (ext)
103 ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
104
105 ut_params.name = name;
106 ut_params.key_len = hashtest_key_lens[table_index];
107 ut_params.socket_id = rte_socket_id();
108 h[table_index] = rte_hash_find_existing(name);
109 if (h[table_index] != NULL)
110 /*
111 * If table was already created, free it to create it again,
112 * so we force it is empty
113 */
114 rte_hash_free(h[table_index]);
115 h[table_index] = rte_hash_create(&ut_params);
116 if (h[table_index] == NULL) {
117 printf("Error creating table\n");
118 return -1;
119 }
120 return 0;
121
122 }
123
124 /* Shuffle the keys that have been added, so lookups will be totally random */
125 static void
shuffle_input_keys(unsigned int table_index,unsigned int ext)126 shuffle_input_keys(unsigned int table_index, unsigned int ext)
127 {
128 unsigned i;
129 uint32_t swap_idx;
130 uint8_t temp_key[MAX_KEYSIZE];
131 hash_sig_t temp_signature;
132 int32_t temp_position;
133 unsigned int keys_to_add;
134
135 if (!ext)
136 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
137 else
138 keys_to_add = KEYS_TO_ADD;
139
140 for (i = keys_to_add - 1; i > 0; i--) {
141 swap_idx = rte_rand() % i;
142
143 memcpy(temp_key, keys[i], hashtest_key_lens[table_index]);
144 temp_signature = signatures[i];
145 temp_position = positions[i];
146
147 memcpy(keys[i], keys[swap_idx], hashtest_key_lens[table_index]);
148 signatures[i] = signatures[swap_idx];
149 positions[i] = positions[swap_idx];
150
151 memcpy(keys[swap_idx], temp_key, hashtest_key_lens[table_index]);
152 signatures[swap_idx] = temp_signature;
153 positions[swap_idx] = temp_position;
154 }
155 }
156
157 /*
158 * Looks for random keys which
159 * ALL can fit in hash table (no errors)
160 */
161 static int
get_input_keys(unsigned int with_pushes,unsigned int table_index,unsigned int ext)162 get_input_keys(unsigned int with_pushes, unsigned int table_index,
163 unsigned int ext)
164 {
165 unsigned i, j;
166 unsigned bucket_idx, incr, success = 1;
167 uint8_t k = 0;
168 int32_t ret;
169 const uint32_t bucket_bitmask = NUM_BUCKETS - 1;
170 unsigned int keys_to_add;
171
172 if (!ext)
173 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
174 else
175 keys_to_add = KEYS_TO_ADD;
176 /* Reset all arrays */
177 for (i = 0; i < MAX_ENTRIES; i++)
178 slot_taken[i] = 0;
179
180 for (i = 0; i < NUM_BUCKETS; i++)
181 buckets[i] = 0;
182
183 for (j = 0; j < hashtest_key_lens[table_index]; j++)
184 keys[0][j] = 0;
185
186 /*
187 * Add only entries that are not duplicated and that fits in the table
188 * (cannot store more than BUCKET_SIZE entries in a bucket).
189 * Regardless a key has been added correctly or not (success),
190 * the next one to try will be increased by 1.
191 */
192 for (i = 0; i < keys_to_add;) {
193 incr = 0;
194 if (i != 0) {
195 keys[i][0] = ++k;
196 /* Overflow, need to increment the next byte */
197 if (keys[i][0] == 0)
198 incr = 1;
199 for (j = 1; j < hashtest_key_lens[table_index]; j++) {
200 /* Do not increase next byte */
201 if (incr == 0)
202 if (success == 1)
203 keys[i][j] = keys[i - 1][j];
204 else
205 keys[i][j] = keys[i][j];
206 /* Increase next byte by one */
207 else {
208 if (success == 1)
209 keys[i][j] = keys[i-1][j] + 1;
210 else
211 keys[i][j] = keys[i][j] + 1;
212 if (keys[i][j] == 0)
213 incr = 1;
214 else
215 incr = 0;
216 }
217 }
218 }
219 success = 0;
220 signatures[i] = rte_hash_hash(h[table_index], keys[i]);
221 bucket_idx = signatures[i] & bucket_bitmask;
222 /*
223 * If we are not inserting keys in secondary location,
224 * when bucket is full, do not try to insert the key
225 */
226 if (with_pushes == 0)
227 if (buckets[bucket_idx] == BUCKET_SIZE)
228 continue;
229
230 /* If key can be added, leave in successful key arrays "keys" */
231 ret = rte_hash_add_key_with_hash(h[table_index], keys[i],
232 signatures[i]);
233 if (ret >= 0) {
234 /* If key is already added, ignore the entry and do not store */
235 if (slot_taken[ret])
236 continue;
237 else {
238 /* Store the returned position and mark slot as taken */
239 slot_taken[ret] = 1;
240 positions[i] = ret;
241 buckets[bucket_idx]++;
242 success = 1;
243 i++;
244 }
245 }
246 }
247
248 /* Reset the table, so we can measure the time to add all the entries */
249 rte_hash_free(h[table_index]);
250 h[table_index] = rte_hash_create(&ut_params);
251
252 return 0;
253 }
254
255 static int
timed_adds(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)256 timed_adds(unsigned int with_hash, unsigned int with_data,
257 unsigned int table_index, unsigned int ext)
258 {
259 unsigned i;
260 const uint64_t start_tsc = rte_rdtsc();
261 void *data;
262 int32_t ret;
263 unsigned int keys_to_add;
264 if (!ext)
265 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
266 else
267 keys_to_add = KEYS_TO_ADD;
268
269 for (i = 0; i < keys_to_add; i++) {
270 data = (void *) ((uintptr_t) signatures[i]);
271 if (with_hash && with_data) {
272 ret = rte_hash_add_key_with_hash_data(h[table_index],
273 (const void *) keys[i],
274 signatures[i], data);
275 if (ret < 0) {
276 printf("H+D: Failed to add key number %u\n", i);
277 return -1;
278 }
279 } else if (with_hash && !with_data) {
280 ret = rte_hash_add_key_with_hash(h[table_index],
281 (const void *) keys[i],
282 signatures[i]);
283 if (ret >= 0)
284 positions[i] = ret;
285 else {
286 printf("H: Failed to add key number %u\n", i);
287 return -1;
288 }
289 } else if (!with_hash && with_data) {
290 ret = rte_hash_add_key_data(h[table_index],
291 (const void *) keys[i],
292 data);
293 if (ret < 0) {
294 printf("D: Failed to add key number %u\n", i);
295 return -1;
296 }
297 } else {
298 ret = rte_hash_add_key(h[table_index], keys[i]);
299 if (ret >= 0)
300 positions[i] = ret;
301 else {
302 printf("Failed to add key number %u\n", i);
303 return -1;
304 }
305 }
306 }
307
308 const uint64_t end_tsc = rte_rdtsc();
309 const uint64_t time_taken = end_tsc - start_tsc;
310
311 cycles[table_index][ADD][with_hash][with_data] = time_taken/keys_to_add;
312
313 return 0;
314 }
315
316 static int
timed_lookups(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)317 timed_lookups(unsigned int with_hash, unsigned int with_data,
318 unsigned int table_index, unsigned int ext)
319 {
320 unsigned i, j;
321 const uint64_t start_tsc = rte_rdtsc();
322 void *ret_data;
323 void *expected_data;
324 int32_t ret;
325 unsigned int keys_to_add, num_lookups;
326
327 if (!ext) {
328 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
329 num_lookups = NUM_LOOKUPS * ADD_PERCENT;
330 } else {
331 keys_to_add = KEYS_TO_ADD;
332 num_lookups = NUM_LOOKUPS;
333 }
334 for (i = 0; i < num_lookups / keys_to_add; i++) {
335 for (j = 0; j < keys_to_add; j++) {
336 if (with_hash && with_data) {
337 ret = rte_hash_lookup_with_hash_data(h[table_index],
338 (const void *) keys[j],
339 signatures[j], &ret_data);
340 if (ret < 0) {
341 printf("Key number %u was not found\n", j);
342 return -1;
343 }
344 expected_data = (void *) ((uintptr_t) signatures[j]);
345 if (ret_data != expected_data) {
346 printf("Data returned for key number %u is %p,"
347 " but should be %p\n", j, ret_data,
348 expected_data);
349 return -1;
350 }
351 } else if (with_hash && !with_data) {
352 ret = rte_hash_lookup_with_hash(h[table_index],
353 (const void *) keys[j],
354 signatures[j]);
355 if (ret < 0 || ret != positions[j]) {
356 printf("Key looked up in %d, should be in %d\n",
357 ret, positions[j]);
358 return -1;
359 }
360 } else if (!with_hash && with_data) {
361 ret = rte_hash_lookup_data(h[table_index],
362 (const void *) keys[j], &ret_data);
363 if (ret < 0) {
364 printf("Key number %u was not found\n", j);
365 return -1;
366 }
367 expected_data = (void *) ((uintptr_t) signatures[j]);
368 if (ret_data != expected_data) {
369 printf("Data returned for key number %u is %p,"
370 " but should be %p\n", j, ret_data,
371 expected_data);
372 return -1;
373 }
374 } else {
375 ret = rte_hash_lookup(h[table_index], keys[j]);
376 if (ret < 0 || ret != positions[j]) {
377 printf("Key looked up in %d, should be in %d\n",
378 ret, positions[j]);
379 return -1;
380 }
381 }
382 }
383 }
384
385 const uint64_t end_tsc = rte_rdtsc();
386 const uint64_t time_taken = end_tsc - start_tsc;
387
388 cycles[table_index][LOOKUP][with_hash][with_data] = time_taken/num_lookups;
389
390 return 0;
391 }
392
393 static int
timed_lookups_multi(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)394 timed_lookups_multi(unsigned int with_hash, unsigned int with_data,
395 unsigned int table_index, unsigned int ext)
396 {
397 unsigned i, j, k;
398 int32_t positions_burst[BURST_SIZE];
399 const void *keys_burst[BURST_SIZE];
400 void *expected_data[BURST_SIZE];
401 void *ret_data[BURST_SIZE];
402 uint64_t hit_mask;
403 int ret;
404 unsigned int keys_to_add, num_lookups;
405
406 if (!ext) {
407 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
408 num_lookups = NUM_LOOKUPS * ADD_PERCENT;
409 } else {
410 keys_to_add = KEYS_TO_ADD;
411 num_lookups = NUM_LOOKUPS;
412 }
413
414 const uint64_t start_tsc = rte_rdtsc();
415
416 for (i = 0; i < num_lookups/keys_to_add; i++) {
417 for (j = 0; j < keys_to_add/BURST_SIZE; j++) {
418 for (k = 0; k < BURST_SIZE; k++)
419 keys_burst[k] = keys[j * BURST_SIZE + k];
420 if (!with_hash && with_data) {
421 ret = rte_hash_lookup_bulk_data(h[table_index],
422 (const void **) keys_burst,
423 BURST_SIZE,
424 &hit_mask,
425 ret_data);
426 if (ret != BURST_SIZE) {
427 printf("Expect to find %u keys,"
428 " but found %d\n", BURST_SIZE, ret);
429 return -1;
430 }
431 for (k = 0; k < BURST_SIZE; k++) {
432 if ((hit_mask & (1ULL << k)) == 0) {
433 printf("Key number %u not found\n",
434 j * BURST_SIZE + k);
435 return -1;
436 }
437 expected_data[k] = (void *) ((uintptr_t) signatures[j * BURST_SIZE + k]);
438 if (ret_data[k] != expected_data[k]) {
439 printf("Data returned for key number %u is %p,"
440 " but should be %p\n", j * BURST_SIZE + k,
441 ret_data[k], expected_data[k]);
442 return -1;
443 }
444 }
445 } else if (with_hash && with_data) {
446 ret = rte_hash_lookup_with_hash_bulk_data(
447 h[table_index],
448 (const void **)keys_burst,
449 &signatures[j * BURST_SIZE],
450 BURST_SIZE, &hit_mask, ret_data);
451 if (ret != BURST_SIZE) {
452 printf("Expect to find %u keys,"
453 " but found %d\n",
454 BURST_SIZE, ret);
455 return -1;
456 }
457 for (k = 0; k < BURST_SIZE; k++) {
458 if ((hit_mask & (1ULL << k)) == 0) {
459 printf("Key number %u"
460 " not found\n",
461 j * BURST_SIZE + k);
462 return -1;
463 }
464 expected_data[k] =
465 (void *)((uintptr_t)signatures[
466 j * BURST_SIZE + k]);
467 if (ret_data[k] != expected_data[k]) {
468 printf("Data returned for key"
469 " number %u is %p,"
470 " but should be %p\n",
471 j * BURST_SIZE + k,
472 ret_data[k],
473 expected_data[k]);
474 return -1;
475 }
476 }
477 } else if (with_hash && !with_data) {
478 ret = rte_hash_lookup_with_hash_bulk(
479 h[table_index],
480 (const void **)keys_burst,
481 &signatures[j * BURST_SIZE],
482 BURST_SIZE, positions_burst);
483 for (k = 0; k < BURST_SIZE; k++) {
484 if (positions_burst[k] !=
485 positions[j *
486 BURST_SIZE + k]) {
487 printf("Key looked up in %d, should be in %d\n",
488 positions_burst[k],
489 positions[j *
490 BURST_SIZE + k]);
491 return -1;
492 }
493 }
494 } else {
495 rte_hash_lookup_bulk(h[table_index],
496 (const void **) keys_burst,
497 BURST_SIZE,
498 positions_burst);
499 for (k = 0; k < BURST_SIZE; k++) {
500 if (positions_burst[k] != positions[j * BURST_SIZE + k]) {
501 printf("Key looked up in %d, should be in %d\n",
502 positions_burst[k],
503 positions[j * BURST_SIZE + k]);
504 return -1;
505 }
506 }
507 }
508 }
509 }
510
511 const uint64_t end_tsc = rte_rdtsc();
512 const uint64_t time_taken = end_tsc - start_tsc;
513
514 cycles[table_index][LOOKUP_MULTI][with_hash][with_data] =
515 time_taken/num_lookups;
516
517 return 0;
518 }
519
520 static int
timed_deletes(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)521 timed_deletes(unsigned int with_hash, unsigned int with_data,
522 unsigned int table_index, unsigned int ext)
523 {
524 unsigned i;
525 const uint64_t start_tsc = rte_rdtsc();
526 int32_t ret;
527 unsigned int keys_to_add;
528 if (!ext)
529 keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
530 else
531 keys_to_add = KEYS_TO_ADD;
532
533 for (i = 0; i < keys_to_add; i++) {
534 /* There are no delete functions with data, so just call two functions */
535 if (with_hash)
536 ret = rte_hash_del_key_with_hash(h[table_index],
537 (const void *) keys[i],
538 signatures[i]);
539 else
540 ret = rte_hash_del_key(h[table_index],
541 (const void *) keys[i]);
542 if (ret >= 0)
543 positions[i] = ret;
544 else {
545 printf("Failed to delete key number %u\n", i);
546 return -1;
547 }
548 }
549
550 const uint64_t end_tsc = rte_rdtsc();
551 const uint64_t time_taken = end_tsc - start_tsc;
552
553 cycles[table_index][DELETE][with_hash][with_data] = time_taken/keys_to_add;
554
555 return 0;
556 }
557
558 static void
free_table(unsigned table_index)559 free_table(unsigned table_index)
560 {
561 rte_hash_free(h[table_index]);
562 }
563
564 static void
reset_table(unsigned table_index)565 reset_table(unsigned table_index)
566 {
567 rte_hash_reset(h[table_index]);
568 }
569
570 static int
run_all_tbl_perf_tests(unsigned int with_pushes,unsigned int with_locks,unsigned int ext)571 run_all_tbl_perf_tests(unsigned int with_pushes, unsigned int with_locks,
572 unsigned int ext)
573 {
574 unsigned i, j, with_data, with_hash;
575
576 printf("Measuring performance, please wait");
577 fflush(stdout);
578
579 for (with_data = 0; with_data <= 1; with_data++) {
580 for (i = 0; i < NUM_KEYSIZES; i++) {
581 if (create_table(with_data, i, with_locks, ext) < 0)
582 return -1;
583
584 if (get_input_keys(with_pushes, i, ext) < 0)
585 return -1;
586 for (with_hash = 0; with_hash <= 1; with_hash++) {
587 if (timed_adds(with_hash, with_data, i, ext) < 0)
588 return -1;
589
590 for (j = 0; j < NUM_SHUFFLES; j++)
591 shuffle_input_keys(i, ext);
592
593 if (timed_lookups(with_hash, with_data, i, ext) < 0)
594 return -1;
595
596 if (timed_lookups_multi(with_hash, with_data,
597 i, ext) < 0)
598 return -1;
599
600 if (timed_deletes(with_hash, with_data, i, ext) < 0)
601 return -1;
602
603 /* Print a dot to show progress on operations */
604 printf(".");
605 fflush(stdout);
606
607 reset_table(i);
608 }
609 free_table(i);
610 }
611 }
612
613 printf("\nResults (in CPU cycles/operation)\n");
614 printf("-----------------------------------\n");
615 for (with_data = 0; with_data <= 1; with_data++) {
616 if (with_data)
617 printf("\n Operations with 8-byte data\n");
618 else
619 printf("\n Operations without data\n");
620 for (with_hash = 0; with_hash <= 1; with_hash++) {
621 if (with_hash)
622 printf("\nWith pre-computed hash values\n");
623 else
624 printf("\nWithout pre-computed hash values\n");
625
626 printf("\n%-18s%-18s%-18s%-18s%-18s\n",
627 "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete");
628 for (i = 0; i < NUM_KEYSIZES; i++) {
629 printf("%-18d", hashtest_key_lens[i]);
630 for (j = 0; j < NUM_OPERATIONS; j++)
631 printf("%-18"PRIu64, cycles[i][j][with_hash][with_data]);
632 printf("\n");
633 }
634 }
635 }
636 return 0;
637 }
638
639 /* Control operation of performance testing of fbk hash. */
640 #define LOAD_FACTOR 0.667 /* How full to make the hash table. */
641 #define TEST_SIZE 1000000 /* How many operations to time. */
642 #define TEST_ITERATIONS 30 /* How many measurements to take. */
643 #define ENTRIES (1 << 15) /* How many entries. */
644
645 static int
fbk_hash_perf_test(void)646 fbk_hash_perf_test(void)
647 {
648 struct rte_fbk_hash_params params = {
649 .name = "fbk_hash_test",
650 .entries = ENTRIES,
651 .entries_per_bucket = 4,
652 .socket_id = rte_socket_id(),
653 };
654 struct rte_fbk_hash_table *handle = NULL;
655 uint32_t *keys = NULL;
656 unsigned indexes[TEST_SIZE];
657 uint64_t lookup_time = 0;
658 unsigned added = 0;
659 unsigned value = 0;
660 uint32_t key;
661 uint16_t val;
662 unsigned i, j;
663
664 handle = rte_fbk_hash_create(¶ms);
665 if (handle == NULL) {
666 printf("Error creating table\n");
667 return -1;
668 }
669
670 keys = rte_zmalloc(NULL, ENTRIES * sizeof(*keys), 0);
671 if (keys == NULL) {
672 printf("fbk hash: memory allocation for key store failed\n");
673 return -1;
674 }
675
676 /* Generate random keys and values. */
677 for (i = 0; i < ENTRIES; i++) {
678 key = (uint32_t)rte_rand();
679 key = ((uint64_t)key << 32) | (uint64_t)rte_rand();
680 val = (uint16_t)rte_rand();
681
682 if (rte_fbk_hash_add_key(handle, key, val) == 0) {
683 keys[added] = key;
684 added++;
685 }
686 if (added > (LOAD_FACTOR * ENTRIES))
687 break;
688 }
689
690 for (i = 0; i < TEST_ITERATIONS; i++) {
691 uint64_t begin;
692 uint64_t end;
693
694 /* Generate random indexes into keys[] array. */
695 for (j = 0; j < TEST_SIZE; j++)
696 indexes[j] = rte_rand() % added;
697
698 begin = rte_rdtsc();
699 /* Do lookups */
700 for (j = 0; j < TEST_SIZE; j++)
701 value += rte_fbk_hash_lookup(handle, keys[indexes[j]]);
702
703 end = rte_rdtsc();
704 lookup_time += (double)(end - begin);
705 }
706
707 printf("\n\n *** FBK Hash function performance test results ***\n");
708 /*
709 * The use of the 'value' variable ensures that the hash lookup is not
710 * being optimised out by the compiler.
711 */
712 if (value != 0)
713 printf("Number of ticks per lookup = %g\n",
714 (double)lookup_time /
715 ((double)TEST_ITERATIONS * (double)TEST_SIZE));
716
717 rte_fbk_hash_free(handle);
718
719 return 0;
720 }
721
722 static int
test_hash_perf(void)723 test_hash_perf(void)
724 {
725 unsigned int with_pushes, with_locks;
726 for (with_locks = 0; with_locks <= 1; with_locks++) {
727 if (with_locks)
728 printf("\nWith locks in the code\n");
729 else
730 printf("\nWithout locks in the code\n");
731 for (with_pushes = 0; with_pushes <= 1; with_pushes++) {
732 if (with_pushes == 0)
733 printf("\nALL ELEMENTS IN PRIMARY LOCATION\n");
734 else
735 printf("\nELEMENTS IN PRIMARY OR SECONDARY LOCATION\n");
736 if (run_all_tbl_perf_tests(with_pushes, with_locks, 0) < 0)
737 return -1;
738 }
739 }
740
741 printf("\n EXTENDABLE BUCKETS PERFORMANCE\n");
742
743 if (run_all_tbl_perf_tests(1, 0, 1) < 0)
744 return -1;
745
746 if (fbk_hash_perf_test() < 0)
747 return -1;
748
749 return 0;
750 }
751
752 REGISTER_TEST_COMMAND(hash_perf_autotest, test_hash_perf);
753