14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2010-2015 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang #include <stdio.h>
64418919fSjohnjiang #include <inttypes.h>
74418919fSjohnjiang
84418919fSjohnjiang #include <rte_lcore.h>
94418919fSjohnjiang #include <rte_cycles.h>
104418919fSjohnjiang #include <rte_malloc.h>
114418919fSjohnjiang #include <rte_hash.h>
124418919fSjohnjiang #include <rte_hash_crc.h>
134418919fSjohnjiang #include <rte_jhash.h>
144418919fSjohnjiang #include <rte_fbk_hash.h>
154418919fSjohnjiang #include <rte_random.h>
164418919fSjohnjiang #include <rte_string_fns.h>
174418919fSjohnjiang
184418919fSjohnjiang #include "test.h"
194418919fSjohnjiang
204418919fSjohnjiang #define MAX_ENTRIES (1 << 19)
214418919fSjohnjiang #define KEYS_TO_ADD (MAX_ENTRIES)
224418919fSjohnjiang #define ADD_PERCENT 0.75 /* 75% table utilization */
234418919fSjohnjiang #define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
244418919fSjohnjiang /* BUCKET_SIZE should be same as RTE_HASH_BUCKET_ENTRIES in rte_hash library */
254418919fSjohnjiang #define BUCKET_SIZE 8
264418919fSjohnjiang #define NUM_BUCKETS (MAX_ENTRIES / BUCKET_SIZE)
274418919fSjohnjiang #define MAX_KEYSIZE 64
284418919fSjohnjiang #define NUM_KEYSIZES 10
294418919fSjohnjiang #define NUM_SHUFFLES 10
304418919fSjohnjiang #define BURST_SIZE 16
314418919fSjohnjiang
324418919fSjohnjiang enum operations {
334418919fSjohnjiang ADD = 0,
344418919fSjohnjiang LOOKUP,
354418919fSjohnjiang LOOKUP_MULTI,
364418919fSjohnjiang DELETE,
374418919fSjohnjiang NUM_OPERATIONS
384418919fSjohnjiang };
394418919fSjohnjiang
404418919fSjohnjiang static uint32_t hashtest_key_lens[] = {
414418919fSjohnjiang /* standard key sizes */
424418919fSjohnjiang 4, 8, 16, 32, 48, 64,
434418919fSjohnjiang /* IPv4 SRC + DST + protocol, unpadded */
444418919fSjohnjiang 9,
454418919fSjohnjiang /* IPv4 5-tuple, unpadded */
464418919fSjohnjiang 13,
474418919fSjohnjiang /* IPv6 5-tuple, unpadded */
484418919fSjohnjiang 37,
494418919fSjohnjiang /* IPv6 5-tuple, padded to 8-byte boundary */
504418919fSjohnjiang 40
514418919fSjohnjiang };
524418919fSjohnjiang
534418919fSjohnjiang struct rte_hash *h[NUM_KEYSIZES];
544418919fSjohnjiang
554418919fSjohnjiang /* Array that stores if a slot is full */
564418919fSjohnjiang static uint8_t slot_taken[MAX_ENTRIES];
574418919fSjohnjiang
584418919fSjohnjiang /* Array to store number of cycles per operation */
594418919fSjohnjiang static uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2][2];
604418919fSjohnjiang
614418919fSjohnjiang /* Array to store all input keys */
624418919fSjohnjiang static uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];
634418919fSjohnjiang
644418919fSjohnjiang /* Array to store the precomputed hash for 'keys' */
654418919fSjohnjiang static hash_sig_t signatures[KEYS_TO_ADD];
664418919fSjohnjiang
674418919fSjohnjiang /* Array to store how many busy entries have each bucket */
684418919fSjohnjiang static uint8_t buckets[NUM_BUCKETS];
694418919fSjohnjiang
704418919fSjohnjiang /* Array to store the positions where keys are added */
714418919fSjohnjiang static int32_t positions[KEYS_TO_ADD];
724418919fSjohnjiang
734418919fSjohnjiang /* Parameters used for hash table in unit test functions. */
744418919fSjohnjiang static struct rte_hash_parameters ut_params = {
754418919fSjohnjiang .entries = MAX_ENTRIES,
764418919fSjohnjiang .hash_func = rte_jhash,
774418919fSjohnjiang .hash_func_init_val = 0,
784418919fSjohnjiang };
794418919fSjohnjiang
804418919fSjohnjiang static int
create_table(unsigned int with_data,unsigned int table_index,unsigned int with_locks,unsigned int ext)814418919fSjohnjiang create_table(unsigned int with_data, unsigned int table_index,
824418919fSjohnjiang unsigned int with_locks, unsigned int ext)
834418919fSjohnjiang {
844418919fSjohnjiang char name[RTE_HASH_NAMESIZE];
854418919fSjohnjiang
864418919fSjohnjiang if (with_data)
874418919fSjohnjiang /* Table will store 8-byte data */
884418919fSjohnjiang snprintf(name, sizeof(name), "test_hash%u_data",
894418919fSjohnjiang hashtest_key_lens[table_index]);
904418919fSjohnjiang else
914418919fSjohnjiang snprintf(name, sizeof(name), "test_hash%u",
924418919fSjohnjiang hashtest_key_lens[table_index]);
934418919fSjohnjiang
944418919fSjohnjiang
954418919fSjohnjiang if (with_locks)
964418919fSjohnjiang ut_params.extra_flag =
974418919fSjohnjiang RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
984418919fSjohnjiang | RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY;
994418919fSjohnjiang else
1004418919fSjohnjiang ut_params.extra_flag = 0;
1014418919fSjohnjiang
1024418919fSjohnjiang if (ext)
1034418919fSjohnjiang ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1044418919fSjohnjiang
1054418919fSjohnjiang ut_params.name = name;
1064418919fSjohnjiang ut_params.key_len = hashtest_key_lens[table_index];
1074418919fSjohnjiang ut_params.socket_id = rte_socket_id();
1084418919fSjohnjiang h[table_index] = rte_hash_find_existing(name);
1094418919fSjohnjiang if (h[table_index] != NULL)
1104418919fSjohnjiang /*
1114418919fSjohnjiang * If table was already created, free it to create it again,
1124418919fSjohnjiang * so we force it is empty
1134418919fSjohnjiang */
1144418919fSjohnjiang rte_hash_free(h[table_index]);
1154418919fSjohnjiang h[table_index] = rte_hash_create(&ut_params);
1164418919fSjohnjiang if (h[table_index] == NULL) {
1174418919fSjohnjiang printf("Error creating table\n");
1184418919fSjohnjiang return -1;
1194418919fSjohnjiang }
1204418919fSjohnjiang return 0;
1214418919fSjohnjiang
1224418919fSjohnjiang }
1234418919fSjohnjiang
1244418919fSjohnjiang /* Shuffle the keys that have been added, so lookups will be totally random */
1254418919fSjohnjiang static void
shuffle_input_keys(unsigned int table_index,unsigned int ext)1264418919fSjohnjiang shuffle_input_keys(unsigned int table_index, unsigned int ext)
1274418919fSjohnjiang {
1284418919fSjohnjiang unsigned i;
1294418919fSjohnjiang uint32_t swap_idx;
1304418919fSjohnjiang uint8_t temp_key[MAX_KEYSIZE];
1314418919fSjohnjiang hash_sig_t temp_signature;
1324418919fSjohnjiang int32_t temp_position;
1334418919fSjohnjiang unsigned int keys_to_add;
1344418919fSjohnjiang
1354418919fSjohnjiang if (!ext)
1364418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
1374418919fSjohnjiang else
1384418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
1394418919fSjohnjiang
1404418919fSjohnjiang for (i = keys_to_add - 1; i > 0; i--) {
1414418919fSjohnjiang swap_idx = rte_rand() % i;
1424418919fSjohnjiang
1434418919fSjohnjiang memcpy(temp_key, keys[i], hashtest_key_lens[table_index]);
1444418919fSjohnjiang temp_signature = signatures[i];
1454418919fSjohnjiang temp_position = positions[i];
1464418919fSjohnjiang
1474418919fSjohnjiang memcpy(keys[i], keys[swap_idx], hashtest_key_lens[table_index]);
1484418919fSjohnjiang signatures[i] = signatures[swap_idx];
1494418919fSjohnjiang positions[i] = positions[swap_idx];
1504418919fSjohnjiang
1514418919fSjohnjiang memcpy(keys[swap_idx], temp_key, hashtest_key_lens[table_index]);
1524418919fSjohnjiang signatures[swap_idx] = temp_signature;
1534418919fSjohnjiang positions[swap_idx] = temp_position;
1544418919fSjohnjiang }
1554418919fSjohnjiang }
1564418919fSjohnjiang
1574418919fSjohnjiang /*
1584418919fSjohnjiang * Looks for random keys which
1594418919fSjohnjiang * ALL can fit in hash table (no errors)
1604418919fSjohnjiang */
1614418919fSjohnjiang static int
get_input_keys(unsigned int with_pushes,unsigned int table_index,unsigned int ext)1624418919fSjohnjiang get_input_keys(unsigned int with_pushes, unsigned int table_index,
1634418919fSjohnjiang unsigned int ext)
1644418919fSjohnjiang {
1654418919fSjohnjiang unsigned i, j;
1664418919fSjohnjiang unsigned bucket_idx, incr, success = 1;
1674418919fSjohnjiang uint8_t k = 0;
1684418919fSjohnjiang int32_t ret;
1694418919fSjohnjiang const uint32_t bucket_bitmask = NUM_BUCKETS - 1;
1704418919fSjohnjiang unsigned int keys_to_add;
1714418919fSjohnjiang
1724418919fSjohnjiang if (!ext)
1734418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
1744418919fSjohnjiang else
1754418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
1764418919fSjohnjiang /* Reset all arrays */
1774418919fSjohnjiang for (i = 0; i < MAX_ENTRIES; i++)
1784418919fSjohnjiang slot_taken[i] = 0;
1794418919fSjohnjiang
1804418919fSjohnjiang for (i = 0; i < NUM_BUCKETS; i++)
1814418919fSjohnjiang buckets[i] = 0;
1824418919fSjohnjiang
1834418919fSjohnjiang for (j = 0; j < hashtest_key_lens[table_index]; j++)
1844418919fSjohnjiang keys[0][j] = 0;
1854418919fSjohnjiang
1864418919fSjohnjiang /*
1874418919fSjohnjiang * Add only entries that are not duplicated and that fits in the table
1884418919fSjohnjiang * (cannot store more than BUCKET_SIZE entries in a bucket).
1894418919fSjohnjiang * Regardless a key has been added correctly or not (success),
1904418919fSjohnjiang * the next one to try will be increased by 1.
1914418919fSjohnjiang */
1924418919fSjohnjiang for (i = 0; i < keys_to_add;) {
1934418919fSjohnjiang incr = 0;
1944418919fSjohnjiang if (i != 0) {
1954418919fSjohnjiang keys[i][0] = ++k;
1964418919fSjohnjiang /* Overflow, need to increment the next byte */
1974418919fSjohnjiang if (keys[i][0] == 0)
1984418919fSjohnjiang incr = 1;
1994418919fSjohnjiang for (j = 1; j < hashtest_key_lens[table_index]; j++) {
2004418919fSjohnjiang /* Do not increase next byte */
2014418919fSjohnjiang if (incr == 0)
2024418919fSjohnjiang if (success == 1)
2034418919fSjohnjiang keys[i][j] = keys[i - 1][j];
2044418919fSjohnjiang else
2054418919fSjohnjiang keys[i][j] = keys[i][j];
2064418919fSjohnjiang /* Increase next byte by one */
2074418919fSjohnjiang else {
2084418919fSjohnjiang if (success == 1)
2094418919fSjohnjiang keys[i][j] = keys[i-1][j] + 1;
2104418919fSjohnjiang else
2114418919fSjohnjiang keys[i][j] = keys[i][j] + 1;
2124418919fSjohnjiang if (keys[i][j] == 0)
2134418919fSjohnjiang incr = 1;
2144418919fSjohnjiang else
2154418919fSjohnjiang incr = 0;
2164418919fSjohnjiang }
2174418919fSjohnjiang }
2184418919fSjohnjiang }
2194418919fSjohnjiang success = 0;
2204418919fSjohnjiang signatures[i] = rte_hash_hash(h[table_index], keys[i]);
2214418919fSjohnjiang bucket_idx = signatures[i] & bucket_bitmask;
2224418919fSjohnjiang /*
2234418919fSjohnjiang * If we are not inserting keys in secondary location,
2244418919fSjohnjiang * when bucket is full, do not try to insert the key
2254418919fSjohnjiang */
2264418919fSjohnjiang if (with_pushes == 0)
2274418919fSjohnjiang if (buckets[bucket_idx] == BUCKET_SIZE)
2284418919fSjohnjiang continue;
2294418919fSjohnjiang
2304418919fSjohnjiang /* If key can be added, leave in successful key arrays "keys" */
2314418919fSjohnjiang ret = rte_hash_add_key_with_hash(h[table_index], keys[i],
2324418919fSjohnjiang signatures[i]);
2334418919fSjohnjiang if (ret >= 0) {
2344418919fSjohnjiang /* If key is already added, ignore the entry and do not store */
2354418919fSjohnjiang if (slot_taken[ret])
2364418919fSjohnjiang continue;
2374418919fSjohnjiang else {
2384418919fSjohnjiang /* Store the returned position and mark slot as taken */
2394418919fSjohnjiang slot_taken[ret] = 1;
2404418919fSjohnjiang positions[i] = ret;
2414418919fSjohnjiang buckets[bucket_idx]++;
2424418919fSjohnjiang success = 1;
2434418919fSjohnjiang i++;
2444418919fSjohnjiang }
2454418919fSjohnjiang }
2464418919fSjohnjiang }
2474418919fSjohnjiang
2484418919fSjohnjiang /* Reset the table, so we can measure the time to add all the entries */
2494418919fSjohnjiang rte_hash_free(h[table_index]);
2504418919fSjohnjiang h[table_index] = rte_hash_create(&ut_params);
2514418919fSjohnjiang
2524418919fSjohnjiang return 0;
2534418919fSjohnjiang }
2544418919fSjohnjiang
2554418919fSjohnjiang static int
timed_adds(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)2564418919fSjohnjiang timed_adds(unsigned int with_hash, unsigned int with_data,
2574418919fSjohnjiang unsigned int table_index, unsigned int ext)
2584418919fSjohnjiang {
2594418919fSjohnjiang unsigned i;
2604418919fSjohnjiang const uint64_t start_tsc = rte_rdtsc();
2614418919fSjohnjiang void *data;
2624418919fSjohnjiang int32_t ret;
2634418919fSjohnjiang unsigned int keys_to_add;
2644418919fSjohnjiang if (!ext)
2654418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
2664418919fSjohnjiang else
2674418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
2684418919fSjohnjiang
2694418919fSjohnjiang for (i = 0; i < keys_to_add; i++) {
2704418919fSjohnjiang data = (void *) ((uintptr_t) signatures[i]);
2714418919fSjohnjiang if (with_hash && with_data) {
2724418919fSjohnjiang ret = rte_hash_add_key_with_hash_data(h[table_index],
2734418919fSjohnjiang (const void *) keys[i],
2744418919fSjohnjiang signatures[i], data);
2754418919fSjohnjiang if (ret < 0) {
2764418919fSjohnjiang printf("H+D: Failed to add key number %u\n", i);
2774418919fSjohnjiang return -1;
2784418919fSjohnjiang }
2794418919fSjohnjiang } else if (with_hash && !with_data) {
2804418919fSjohnjiang ret = rte_hash_add_key_with_hash(h[table_index],
2814418919fSjohnjiang (const void *) keys[i],
2824418919fSjohnjiang signatures[i]);
2834418919fSjohnjiang if (ret >= 0)
2844418919fSjohnjiang positions[i] = ret;
2854418919fSjohnjiang else {
2864418919fSjohnjiang printf("H: Failed to add key number %u\n", i);
2874418919fSjohnjiang return -1;
2884418919fSjohnjiang }
2894418919fSjohnjiang } else if (!with_hash && with_data) {
2904418919fSjohnjiang ret = rte_hash_add_key_data(h[table_index],
2914418919fSjohnjiang (const void *) keys[i],
2924418919fSjohnjiang data);
2934418919fSjohnjiang if (ret < 0) {
2944418919fSjohnjiang printf("D: Failed to add key number %u\n", i);
2954418919fSjohnjiang return -1;
2964418919fSjohnjiang }
2974418919fSjohnjiang } else {
2984418919fSjohnjiang ret = rte_hash_add_key(h[table_index], keys[i]);
2994418919fSjohnjiang if (ret >= 0)
3004418919fSjohnjiang positions[i] = ret;
3014418919fSjohnjiang else {
3024418919fSjohnjiang printf("Failed to add key number %u\n", i);
3034418919fSjohnjiang return -1;
3044418919fSjohnjiang }
3054418919fSjohnjiang }
3064418919fSjohnjiang }
3074418919fSjohnjiang
3084418919fSjohnjiang const uint64_t end_tsc = rte_rdtsc();
3094418919fSjohnjiang const uint64_t time_taken = end_tsc - start_tsc;
3104418919fSjohnjiang
3114418919fSjohnjiang cycles[table_index][ADD][with_hash][with_data] = time_taken/keys_to_add;
3124418919fSjohnjiang
3134418919fSjohnjiang return 0;
3144418919fSjohnjiang }
3154418919fSjohnjiang
3164418919fSjohnjiang static int
timed_lookups(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)3174418919fSjohnjiang timed_lookups(unsigned int with_hash, unsigned int with_data,
3184418919fSjohnjiang unsigned int table_index, unsigned int ext)
3194418919fSjohnjiang {
3204418919fSjohnjiang unsigned i, j;
3214418919fSjohnjiang const uint64_t start_tsc = rte_rdtsc();
3224418919fSjohnjiang void *ret_data;
3234418919fSjohnjiang void *expected_data;
3244418919fSjohnjiang int32_t ret;
3254418919fSjohnjiang unsigned int keys_to_add, num_lookups;
3264418919fSjohnjiang
3274418919fSjohnjiang if (!ext) {
3284418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
3294418919fSjohnjiang num_lookups = NUM_LOOKUPS * ADD_PERCENT;
3304418919fSjohnjiang } else {
3314418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
3324418919fSjohnjiang num_lookups = NUM_LOOKUPS;
3334418919fSjohnjiang }
3344418919fSjohnjiang for (i = 0; i < num_lookups / keys_to_add; i++) {
3354418919fSjohnjiang for (j = 0; j < keys_to_add; j++) {
3364418919fSjohnjiang if (with_hash && with_data) {
3374418919fSjohnjiang ret = rte_hash_lookup_with_hash_data(h[table_index],
3384418919fSjohnjiang (const void *) keys[j],
3394418919fSjohnjiang signatures[j], &ret_data);
3404418919fSjohnjiang if (ret < 0) {
3414418919fSjohnjiang printf("Key number %u was not found\n", j);
3424418919fSjohnjiang return -1;
3434418919fSjohnjiang }
3444418919fSjohnjiang expected_data = (void *) ((uintptr_t) signatures[j]);
3454418919fSjohnjiang if (ret_data != expected_data) {
3464418919fSjohnjiang printf("Data returned for key number %u is %p,"
3474418919fSjohnjiang " but should be %p\n", j, ret_data,
3484418919fSjohnjiang expected_data);
3494418919fSjohnjiang return -1;
3504418919fSjohnjiang }
3514418919fSjohnjiang } else if (with_hash && !with_data) {
3524418919fSjohnjiang ret = rte_hash_lookup_with_hash(h[table_index],
3534418919fSjohnjiang (const void *) keys[j],
3544418919fSjohnjiang signatures[j]);
3554418919fSjohnjiang if (ret < 0 || ret != positions[j]) {
3564418919fSjohnjiang printf("Key looked up in %d, should be in %d\n",
3574418919fSjohnjiang ret, positions[j]);
3584418919fSjohnjiang return -1;
3594418919fSjohnjiang }
3604418919fSjohnjiang } else if (!with_hash && with_data) {
3614418919fSjohnjiang ret = rte_hash_lookup_data(h[table_index],
3624418919fSjohnjiang (const void *) keys[j], &ret_data);
3634418919fSjohnjiang if (ret < 0) {
3644418919fSjohnjiang printf("Key number %u was not found\n", j);
3654418919fSjohnjiang return -1;
3664418919fSjohnjiang }
3674418919fSjohnjiang expected_data = (void *) ((uintptr_t) signatures[j]);
3684418919fSjohnjiang if (ret_data != expected_data) {
3694418919fSjohnjiang printf("Data returned for key number %u is %p,"
3704418919fSjohnjiang " but should be %p\n", j, ret_data,
3714418919fSjohnjiang expected_data);
3724418919fSjohnjiang return -1;
3734418919fSjohnjiang }
3744418919fSjohnjiang } else {
3754418919fSjohnjiang ret = rte_hash_lookup(h[table_index], keys[j]);
3764418919fSjohnjiang if (ret < 0 || ret != positions[j]) {
3774418919fSjohnjiang printf("Key looked up in %d, should be in %d\n",
3784418919fSjohnjiang ret, positions[j]);
3794418919fSjohnjiang return -1;
3804418919fSjohnjiang }
3814418919fSjohnjiang }
3824418919fSjohnjiang }
3834418919fSjohnjiang }
3844418919fSjohnjiang
3854418919fSjohnjiang const uint64_t end_tsc = rte_rdtsc();
3864418919fSjohnjiang const uint64_t time_taken = end_tsc - start_tsc;
3874418919fSjohnjiang
3884418919fSjohnjiang cycles[table_index][LOOKUP][with_hash][with_data] = time_taken/num_lookups;
3894418919fSjohnjiang
3904418919fSjohnjiang return 0;
3914418919fSjohnjiang }
3924418919fSjohnjiang
3934418919fSjohnjiang static int
timed_lookups_multi(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)394*2d9fd380Sjfb8856606 timed_lookups_multi(unsigned int with_hash, unsigned int with_data,
395*2d9fd380Sjfb8856606 unsigned int table_index, unsigned int ext)
3964418919fSjohnjiang {
3974418919fSjohnjiang unsigned i, j, k;
3984418919fSjohnjiang int32_t positions_burst[BURST_SIZE];
3994418919fSjohnjiang const void *keys_burst[BURST_SIZE];
4004418919fSjohnjiang void *expected_data[BURST_SIZE];
4014418919fSjohnjiang void *ret_data[BURST_SIZE];
4024418919fSjohnjiang uint64_t hit_mask;
4034418919fSjohnjiang int ret;
4044418919fSjohnjiang unsigned int keys_to_add, num_lookups;
4054418919fSjohnjiang
4064418919fSjohnjiang if (!ext) {
4074418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
4084418919fSjohnjiang num_lookups = NUM_LOOKUPS * ADD_PERCENT;
4094418919fSjohnjiang } else {
4104418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
4114418919fSjohnjiang num_lookups = NUM_LOOKUPS;
4124418919fSjohnjiang }
4134418919fSjohnjiang
4144418919fSjohnjiang const uint64_t start_tsc = rte_rdtsc();
4154418919fSjohnjiang
4164418919fSjohnjiang for (i = 0; i < num_lookups/keys_to_add; i++) {
4174418919fSjohnjiang for (j = 0; j < keys_to_add/BURST_SIZE; j++) {
4184418919fSjohnjiang for (k = 0; k < BURST_SIZE; k++)
4194418919fSjohnjiang keys_burst[k] = keys[j * BURST_SIZE + k];
420*2d9fd380Sjfb8856606 if (!with_hash && with_data) {
4214418919fSjohnjiang ret = rte_hash_lookup_bulk_data(h[table_index],
4224418919fSjohnjiang (const void **) keys_burst,
4234418919fSjohnjiang BURST_SIZE,
4244418919fSjohnjiang &hit_mask,
4254418919fSjohnjiang ret_data);
4264418919fSjohnjiang if (ret != BURST_SIZE) {
4274418919fSjohnjiang printf("Expect to find %u keys,"
4284418919fSjohnjiang " but found %d\n", BURST_SIZE, ret);
4294418919fSjohnjiang return -1;
4304418919fSjohnjiang }
4314418919fSjohnjiang for (k = 0; k < BURST_SIZE; k++) {
4324418919fSjohnjiang if ((hit_mask & (1ULL << k)) == 0) {
4334418919fSjohnjiang printf("Key number %u not found\n",
4344418919fSjohnjiang j * BURST_SIZE + k);
4354418919fSjohnjiang return -1;
4364418919fSjohnjiang }
4374418919fSjohnjiang expected_data[k] = (void *) ((uintptr_t) signatures[j * BURST_SIZE + k]);
4384418919fSjohnjiang if (ret_data[k] != expected_data[k]) {
4394418919fSjohnjiang printf("Data returned for key number %u is %p,"
4404418919fSjohnjiang " but should be %p\n", j * BURST_SIZE + k,
4414418919fSjohnjiang ret_data[k], expected_data[k]);
4424418919fSjohnjiang return -1;
4434418919fSjohnjiang }
4444418919fSjohnjiang }
445*2d9fd380Sjfb8856606 } else if (with_hash && with_data) {
446*2d9fd380Sjfb8856606 ret = rte_hash_lookup_with_hash_bulk_data(
447*2d9fd380Sjfb8856606 h[table_index],
448*2d9fd380Sjfb8856606 (const void **)keys_burst,
449*2d9fd380Sjfb8856606 &signatures[j * BURST_SIZE],
450*2d9fd380Sjfb8856606 BURST_SIZE, &hit_mask, ret_data);
451*2d9fd380Sjfb8856606 if (ret != BURST_SIZE) {
452*2d9fd380Sjfb8856606 printf("Expect to find %u keys,"
453*2d9fd380Sjfb8856606 " but found %d\n",
454*2d9fd380Sjfb8856606 BURST_SIZE, ret);
455*2d9fd380Sjfb8856606 return -1;
456*2d9fd380Sjfb8856606 }
457*2d9fd380Sjfb8856606 for (k = 0; k < BURST_SIZE; k++) {
458*2d9fd380Sjfb8856606 if ((hit_mask & (1ULL << k)) == 0) {
459*2d9fd380Sjfb8856606 printf("Key number %u"
460*2d9fd380Sjfb8856606 " not found\n",
461*2d9fd380Sjfb8856606 j * BURST_SIZE + k);
462*2d9fd380Sjfb8856606 return -1;
463*2d9fd380Sjfb8856606 }
464*2d9fd380Sjfb8856606 expected_data[k] =
465*2d9fd380Sjfb8856606 (void *)((uintptr_t)signatures[
466*2d9fd380Sjfb8856606 j * BURST_SIZE + k]);
467*2d9fd380Sjfb8856606 if (ret_data[k] != expected_data[k]) {
468*2d9fd380Sjfb8856606 printf("Data returned for key"
469*2d9fd380Sjfb8856606 " number %u is %p,"
470*2d9fd380Sjfb8856606 " but should be %p\n",
471*2d9fd380Sjfb8856606 j * BURST_SIZE + k,
472*2d9fd380Sjfb8856606 ret_data[k],
473*2d9fd380Sjfb8856606 expected_data[k]);
474*2d9fd380Sjfb8856606 return -1;
475*2d9fd380Sjfb8856606 }
476*2d9fd380Sjfb8856606 }
477*2d9fd380Sjfb8856606 } else if (with_hash && !with_data) {
478*2d9fd380Sjfb8856606 ret = rte_hash_lookup_with_hash_bulk(
479*2d9fd380Sjfb8856606 h[table_index],
480*2d9fd380Sjfb8856606 (const void **)keys_burst,
481*2d9fd380Sjfb8856606 &signatures[j * BURST_SIZE],
482*2d9fd380Sjfb8856606 BURST_SIZE, positions_burst);
483*2d9fd380Sjfb8856606 for (k = 0; k < BURST_SIZE; k++) {
484*2d9fd380Sjfb8856606 if (positions_burst[k] !=
485*2d9fd380Sjfb8856606 positions[j *
486*2d9fd380Sjfb8856606 BURST_SIZE + k]) {
487*2d9fd380Sjfb8856606 printf("Key looked up in %d, should be in %d\n",
488*2d9fd380Sjfb8856606 positions_burst[k],
489*2d9fd380Sjfb8856606 positions[j *
490*2d9fd380Sjfb8856606 BURST_SIZE + k]);
491*2d9fd380Sjfb8856606 return -1;
492*2d9fd380Sjfb8856606 }
493*2d9fd380Sjfb8856606 }
4944418919fSjohnjiang } else {
4954418919fSjohnjiang rte_hash_lookup_bulk(h[table_index],
4964418919fSjohnjiang (const void **) keys_burst,
4974418919fSjohnjiang BURST_SIZE,
4984418919fSjohnjiang positions_burst);
4994418919fSjohnjiang for (k = 0; k < BURST_SIZE; k++) {
5004418919fSjohnjiang if (positions_burst[k] != positions[j * BURST_SIZE + k]) {
5014418919fSjohnjiang printf("Key looked up in %d, should be in %d\n",
5024418919fSjohnjiang positions_burst[k],
5034418919fSjohnjiang positions[j * BURST_SIZE + k]);
5044418919fSjohnjiang return -1;
5054418919fSjohnjiang }
5064418919fSjohnjiang }
5074418919fSjohnjiang }
5084418919fSjohnjiang }
5094418919fSjohnjiang }
5104418919fSjohnjiang
5114418919fSjohnjiang const uint64_t end_tsc = rte_rdtsc();
5124418919fSjohnjiang const uint64_t time_taken = end_tsc - start_tsc;
5134418919fSjohnjiang
514*2d9fd380Sjfb8856606 cycles[table_index][LOOKUP_MULTI][with_hash][with_data] =
515*2d9fd380Sjfb8856606 time_taken/num_lookups;
5164418919fSjohnjiang
5174418919fSjohnjiang return 0;
5184418919fSjohnjiang }
5194418919fSjohnjiang
5204418919fSjohnjiang static int
timed_deletes(unsigned int with_hash,unsigned int with_data,unsigned int table_index,unsigned int ext)5214418919fSjohnjiang timed_deletes(unsigned int with_hash, unsigned int with_data,
5224418919fSjohnjiang unsigned int table_index, unsigned int ext)
5234418919fSjohnjiang {
5244418919fSjohnjiang unsigned i;
5254418919fSjohnjiang const uint64_t start_tsc = rte_rdtsc();
5264418919fSjohnjiang int32_t ret;
5274418919fSjohnjiang unsigned int keys_to_add;
5284418919fSjohnjiang if (!ext)
5294418919fSjohnjiang keys_to_add = KEYS_TO_ADD * ADD_PERCENT;
5304418919fSjohnjiang else
5314418919fSjohnjiang keys_to_add = KEYS_TO_ADD;
5324418919fSjohnjiang
5334418919fSjohnjiang for (i = 0; i < keys_to_add; i++) {
5344418919fSjohnjiang /* There are no delete functions with data, so just call two functions */
5354418919fSjohnjiang if (with_hash)
5364418919fSjohnjiang ret = rte_hash_del_key_with_hash(h[table_index],
5374418919fSjohnjiang (const void *) keys[i],
5384418919fSjohnjiang signatures[i]);
5394418919fSjohnjiang else
5404418919fSjohnjiang ret = rte_hash_del_key(h[table_index],
5414418919fSjohnjiang (const void *) keys[i]);
5424418919fSjohnjiang if (ret >= 0)
5434418919fSjohnjiang positions[i] = ret;
5444418919fSjohnjiang else {
5454418919fSjohnjiang printf("Failed to delete key number %u\n", i);
5464418919fSjohnjiang return -1;
5474418919fSjohnjiang }
5484418919fSjohnjiang }
5494418919fSjohnjiang
5504418919fSjohnjiang const uint64_t end_tsc = rte_rdtsc();
5514418919fSjohnjiang const uint64_t time_taken = end_tsc - start_tsc;
5524418919fSjohnjiang
5534418919fSjohnjiang cycles[table_index][DELETE][with_hash][with_data] = time_taken/keys_to_add;
5544418919fSjohnjiang
5554418919fSjohnjiang return 0;
5564418919fSjohnjiang }
5574418919fSjohnjiang
5584418919fSjohnjiang static void
free_table(unsigned table_index)5594418919fSjohnjiang free_table(unsigned table_index)
5604418919fSjohnjiang {
5614418919fSjohnjiang rte_hash_free(h[table_index]);
5624418919fSjohnjiang }
5634418919fSjohnjiang
5644418919fSjohnjiang static void
reset_table(unsigned table_index)5654418919fSjohnjiang reset_table(unsigned table_index)
5664418919fSjohnjiang {
5674418919fSjohnjiang rte_hash_reset(h[table_index]);
5684418919fSjohnjiang }
5694418919fSjohnjiang
5704418919fSjohnjiang static int
run_all_tbl_perf_tests(unsigned int with_pushes,unsigned int with_locks,unsigned int ext)5714418919fSjohnjiang run_all_tbl_perf_tests(unsigned int with_pushes, unsigned int with_locks,
5724418919fSjohnjiang unsigned int ext)
5734418919fSjohnjiang {
5744418919fSjohnjiang unsigned i, j, with_data, with_hash;
5754418919fSjohnjiang
5764418919fSjohnjiang printf("Measuring performance, please wait");
5774418919fSjohnjiang fflush(stdout);
5784418919fSjohnjiang
5794418919fSjohnjiang for (with_data = 0; with_data <= 1; with_data++) {
5804418919fSjohnjiang for (i = 0; i < NUM_KEYSIZES; i++) {
5814418919fSjohnjiang if (create_table(with_data, i, with_locks, ext) < 0)
5824418919fSjohnjiang return -1;
5834418919fSjohnjiang
5844418919fSjohnjiang if (get_input_keys(with_pushes, i, ext) < 0)
5854418919fSjohnjiang return -1;
5864418919fSjohnjiang for (with_hash = 0; with_hash <= 1; with_hash++) {
5874418919fSjohnjiang if (timed_adds(with_hash, with_data, i, ext) < 0)
5884418919fSjohnjiang return -1;
5894418919fSjohnjiang
5904418919fSjohnjiang for (j = 0; j < NUM_SHUFFLES; j++)
5914418919fSjohnjiang shuffle_input_keys(i, ext);
5924418919fSjohnjiang
5934418919fSjohnjiang if (timed_lookups(with_hash, with_data, i, ext) < 0)
5944418919fSjohnjiang return -1;
5954418919fSjohnjiang
596*2d9fd380Sjfb8856606 if (timed_lookups_multi(with_hash, with_data,
597*2d9fd380Sjfb8856606 i, ext) < 0)
5984418919fSjohnjiang return -1;
5994418919fSjohnjiang
6004418919fSjohnjiang if (timed_deletes(with_hash, with_data, i, ext) < 0)
6014418919fSjohnjiang return -1;
6024418919fSjohnjiang
6034418919fSjohnjiang /* Print a dot to show progress on operations */
6044418919fSjohnjiang printf(".");
6054418919fSjohnjiang fflush(stdout);
6064418919fSjohnjiang
6074418919fSjohnjiang reset_table(i);
6084418919fSjohnjiang }
6094418919fSjohnjiang free_table(i);
6104418919fSjohnjiang }
6114418919fSjohnjiang }
6124418919fSjohnjiang
6134418919fSjohnjiang printf("\nResults (in CPU cycles/operation)\n");
6144418919fSjohnjiang printf("-----------------------------------\n");
6154418919fSjohnjiang for (with_data = 0; with_data <= 1; with_data++) {
6164418919fSjohnjiang if (with_data)
6174418919fSjohnjiang printf("\n Operations with 8-byte data\n");
6184418919fSjohnjiang else
6194418919fSjohnjiang printf("\n Operations without data\n");
6204418919fSjohnjiang for (with_hash = 0; with_hash <= 1; with_hash++) {
6214418919fSjohnjiang if (with_hash)
6224418919fSjohnjiang printf("\nWith pre-computed hash values\n");
6234418919fSjohnjiang else
6244418919fSjohnjiang printf("\nWithout pre-computed hash values\n");
6254418919fSjohnjiang
6264418919fSjohnjiang printf("\n%-18s%-18s%-18s%-18s%-18s\n",
6274418919fSjohnjiang "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete");
6284418919fSjohnjiang for (i = 0; i < NUM_KEYSIZES; i++) {
6294418919fSjohnjiang printf("%-18d", hashtest_key_lens[i]);
6304418919fSjohnjiang for (j = 0; j < NUM_OPERATIONS; j++)
6314418919fSjohnjiang printf("%-18"PRIu64, cycles[i][j][with_hash][with_data]);
6324418919fSjohnjiang printf("\n");
6334418919fSjohnjiang }
6344418919fSjohnjiang }
6354418919fSjohnjiang }
6364418919fSjohnjiang return 0;
6374418919fSjohnjiang }
6384418919fSjohnjiang
6394418919fSjohnjiang /* Control operation of performance testing of fbk hash. */
6404418919fSjohnjiang #define LOAD_FACTOR 0.667 /* How full to make the hash table. */
6414418919fSjohnjiang #define TEST_SIZE 1000000 /* How many operations to time. */
6424418919fSjohnjiang #define TEST_ITERATIONS 30 /* How many measurements to take. */
6434418919fSjohnjiang #define ENTRIES (1 << 15) /* How many entries. */
6444418919fSjohnjiang
6454418919fSjohnjiang static int
fbk_hash_perf_test(void)6464418919fSjohnjiang fbk_hash_perf_test(void)
6474418919fSjohnjiang {
6484418919fSjohnjiang struct rte_fbk_hash_params params = {
6494418919fSjohnjiang .name = "fbk_hash_test",
6504418919fSjohnjiang .entries = ENTRIES,
6514418919fSjohnjiang .entries_per_bucket = 4,
6524418919fSjohnjiang .socket_id = rte_socket_id(),
6534418919fSjohnjiang };
6544418919fSjohnjiang struct rte_fbk_hash_table *handle = NULL;
6554418919fSjohnjiang uint32_t *keys = NULL;
6564418919fSjohnjiang unsigned indexes[TEST_SIZE];
6574418919fSjohnjiang uint64_t lookup_time = 0;
6584418919fSjohnjiang unsigned added = 0;
6594418919fSjohnjiang unsigned value = 0;
6604418919fSjohnjiang uint32_t key;
6614418919fSjohnjiang uint16_t val;
6624418919fSjohnjiang unsigned i, j;
6634418919fSjohnjiang
6644418919fSjohnjiang handle = rte_fbk_hash_create(¶ms);
6654418919fSjohnjiang if (handle == NULL) {
6664418919fSjohnjiang printf("Error creating table\n");
6674418919fSjohnjiang return -1;
6684418919fSjohnjiang }
6694418919fSjohnjiang
6704418919fSjohnjiang keys = rte_zmalloc(NULL, ENTRIES * sizeof(*keys), 0);
6714418919fSjohnjiang if (keys == NULL) {
6724418919fSjohnjiang printf("fbk hash: memory allocation for key store failed\n");
6734418919fSjohnjiang return -1;
6744418919fSjohnjiang }
6754418919fSjohnjiang
6764418919fSjohnjiang /* Generate random keys and values. */
6774418919fSjohnjiang for (i = 0; i < ENTRIES; i++) {
6784418919fSjohnjiang key = (uint32_t)rte_rand();
6794418919fSjohnjiang key = ((uint64_t)key << 32) | (uint64_t)rte_rand();
6804418919fSjohnjiang val = (uint16_t)rte_rand();
6814418919fSjohnjiang
6824418919fSjohnjiang if (rte_fbk_hash_add_key(handle, key, val) == 0) {
6834418919fSjohnjiang keys[added] = key;
6844418919fSjohnjiang added++;
6854418919fSjohnjiang }
6864418919fSjohnjiang if (added > (LOAD_FACTOR * ENTRIES))
6874418919fSjohnjiang break;
6884418919fSjohnjiang }
6894418919fSjohnjiang
6904418919fSjohnjiang for (i = 0; i < TEST_ITERATIONS; i++) {
6914418919fSjohnjiang uint64_t begin;
6924418919fSjohnjiang uint64_t end;
6934418919fSjohnjiang
6944418919fSjohnjiang /* Generate random indexes into keys[] array. */
6954418919fSjohnjiang for (j = 0; j < TEST_SIZE; j++)
6964418919fSjohnjiang indexes[j] = rte_rand() % added;
6974418919fSjohnjiang
6984418919fSjohnjiang begin = rte_rdtsc();
6994418919fSjohnjiang /* Do lookups */
7004418919fSjohnjiang for (j = 0; j < TEST_SIZE; j++)
7014418919fSjohnjiang value += rte_fbk_hash_lookup(handle, keys[indexes[j]]);
7024418919fSjohnjiang
7034418919fSjohnjiang end = rte_rdtsc();
7044418919fSjohnjiang lookup_time += (double)(end - begin);
7054418919fSjohnjiang }
7064418919fSjohnjiang
7074418919fSjohnjiang printf("\n\n *** FBK Hash function performance test results ***\n");
7084418919fSjohnjiang /*
7094418919fSjohnjiang * The use of the 'value' variable ensures that the hash lookup is not
7104418919fSjohnjiang * being optimised out by the compiler.
7114418919fSjohnjiang */
7124418919fSjohnjiang if (value != 0)
7134418919fSjohnjiang printf("Number of ticks per lookup = %g\n",
7144418919fSjohnjiang (double)lookup_time /
7154418919fSjohnjiang ((double)TEST_ITERATIONS * (double)TEST_SIZE));
7164418919fSjohnjiang
7174418919fSjohnjiang rte_fbk_hash_free(handle);
7184418919fSjohnjiang
7194418919fSjohnjiang return 0;
7204418919fSjohnjiang }
7214418919fSjohnjiang
7224418919fSjohnjiang static int
test_hash_perf(void)7234418919fSjohnjiang test_hash_perf(void)
7244418919fSjohnjiang {
7254418919fSjohnjiang unsigned int with_pushes, with_locks;
7264418919fSjohnjiang for (with_locks = 0; with_locks <= 1; with_locks++) {
7274418919fSjohnjiang if (with_locks)
7284418919fSjohnjiang printf("\nWith locks in the code\n");
7294418919fSjohnjiang else
7304418919fSjohnjiang printf("\nWithout locks in the code\n");
7314418919fSjohnjiang for (with_pushes = 0; with_pushes <= 1; with_pushes++) {
7324418919fSjohnjiang if (with_pushes == 0)
7334418919fSjohnjiang printf("\nALL ELEMENTS IN PRIMARY LOCATION\n");
7344418919fSjohnjiang else
7354418919fSjohnjiang printf("\nELEMENTS IN PRIMARY OR SECONDARY LOCATION\n");
7364418919fSjohnjiang if (run_all_tbl_perf_tests(with_pushes, with_locks, 0) < 0)
7374418919fSjohnjiang return -1;
7384418919fSjohnjiang }
7394418919fSjohnjiang }
7404418919fSjohnjiang
7414418919fSjohnjiang printf("\n EXTENDABLE BUCKETS PERFORMANCE\n");
7424418919fSjohnjiang
7434418919fSjohnjiang if (run_all_tbl_perf_tests(1, 0, 1) < 0)
7444418919fSjohnjiang return -1;
7454418919fSjohnjiang
7464418919fSjohnjiang if (fbk_hash_perf_test() < 0)
7474418919fSjohnjiang return -1;
7484418919fSjohnjiang
7494418919fSjohnjiang return 0;
7504418919fSjohnjiang }
7514418919fSjohnjiang
7524418919fSjohnjiang REGISTER_TEST_COMMAND(hash_perf_autotest, test_hash_perf);
753