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