xref: /f-stack/dpdk/app/test/test_hash_perf.c (revision 2d9fd380)
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(&params);
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