xref: /f-stack/dpdk/app/test/test_hash_functions.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 <stdint.h>
74418919fSjohnjiang #include <string.h>
84418919fSjohnjiang #include <stdlib.h>
94418919fSjohnjiang #include <stdarg.h>
104418919fSjohnjiang #include <errno.h>
114418919fSjohnjiang #include <sys/queue.h>
124418919fSjohnjiang 
134418919fSjohnjiang #include <rte_cycles.h>
144418919fSjohnjiang #include <rte_random.h>
154418919fSjohnjiang #include <rte_hash.h>
164418919fSjohnjiang #include <rte_jhash.h>
174418919fSjohnjiang #include <rte_hash_crc.h>
184418919fSjohnjiang 
194418919fSjohnjiang #include "test.h"
204418919fSjohnjiang 
214418919fSjohnjiang /*
224418919fSjohnjiang  * Hash values calculated for key sizes from array "hashtest_key_lens"
234418919fSjohnjiang  * and for initial values from array "hashtest_initvals.
244418919fSjohnjiang  * Each key will be formed by increasing each byte by 1:
254418919fSjohnjiang  * e.g.: key size = 4, key = 0x03020100
264418919fSjohnjiang  *       key size = 8, key = 0x0706050403020100
274418919fSjohnjiang  */
284418919fSjohnjiang static uint32_t hash_values_jhash[2][12] = {{
294418919fSjohnjiang 	0x8ba9414b, 0xdf0d39c9,
304418919fSjohnjiang 	0xe4cf1d42, 0xd4ccb93c, 0x5e84eafc, 0x21362cfe,
314418919fSjohnjiang 	0x2f4775ab, 0x9ff036cc, 0xeca51474, 0xbc9d6816,
324418919fSjohnjiang 	0x12926a31, 0x1c9fa888
334418919fSjohnjiang },
344418919fSjohnjiang {
354418919fSjohnjiang 	0x5c62c303, 0x1b8cf784,
364418919fSjohnjiang 	0x8270ac65, 0x05fa6668, 0x762df861, 0xda088f2f,
374418919fSjohnjiang 	0x59614cd4, 0x7a94f690, 0xdc1e4993, 0x30825494,
384418919fSjohnjiang 	0x91d0e462, 0x768087fc
394418919fSjohnjiang }
404418919fSjohnjiang };
414418919fSjohnjiang static uint32_t hash_values_crc[2][12] = {{
424418919fSjohnjiang 	0x00000000, 0xf26b8303,
434418919fSjohnjiang 	0x91545164, 0x06040eb1, 0x9bb99201, 0xcc4c4fe4,
444418919fSjohnjiang 	0x14a90993, 0xf8a5dd8c, 0xcaa1ad0b, 0x7ac1e03e,
454418919fSjohnjiang 	0x43f44466, 0x4a11475e
464418919fSjohnjiang },
474418919fSjohnjiang {
484418919fSjohnjiang 	0xbdfd3980, 0x70204542,
494418919fSjohnjiang 	0x98cd4c70, 0xd52c702f, 0x41fc0e1c, 0x3905f65c,
504418919fSjohnjiang 	0x94bff47f, 0x1bab102d, 0xf4a2c645, 0xbf441539,
514418919fSjohnjiang 	0x789c104f, 0x53028d3e
524418919fSjohnjiang }
534418919fSjohnjiang };
544418919fSjohnjiang 
554418919fSjohnjiang /*******************************************************************************
564418919fSjohnjiang  * Hash function performance test configuration section. Each performance test
574418919fSjohnjiang  * will be performed HASHTEST_ITERATIONS times.
584418919fSjohnjiang  *
594418919fSjohnjiang  * The three arrays below control what tests are performed. Every combination
604418919fSjohnjiang  * from the array entries is tested.
614418919fSjohnjiang  */
624418919fSjohnjiang #define HASHTEST_ITERATIONS 1000000
634418919fSjohnjiang #define MAX_KEYSIZE 64
644418919fSjohnjiang static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
654418919fSjohnjiang static uint32_t hashtest_initvals[] = {0, 0xdeadbeef};
664418919fSjohnjiang static uint32_t hashtest_key_lens[] = {
674418919fSjohnjiang 	1, 2,                 /* Unusual key sizes */
684418919fSjohnjiang 	4, 8, 16, 32, 48, 64, /* standard key sizes */
694418919fSjohnjiang 	9,                    /* IPv4 SRC + DST + protocol, unpadded */
704418919fSjohnjiang 	13,                   /* IPv4 5-tuple, unpadded */
714418919fSjohnjiang 	37,                   /* IPv6 5-tuple, unpadded */
724418919fSjohnjiang 	40                    /* IPv6 5-tuple, padded to 8-byte boundary */
734418919fSjohnjiang };
744418919fSjohnjiang /******************************************************************************/
754418919fSjohnjiang 
764418919fSjohnjiang /*
774418919fSjohnjiang  * To help print out name of hash functions.
784418919fSjohnjiang  */
794418919fSjohnjiang static const char *
get_hash_name(rte_hash_function f)804418919fSjohnjiang get_hash_name(rte_hash_function f)
814418919fSjohnjiang {
824418919fSjohnjiang 	if (f == rte_jhash)
834418919fSjohnjiang 		return "jhash";
844418919fSjohnjiang 
854418919fSjohnjiang 	if (f == rte_hash_crc)
864418919fSjohnjiang 		return "rte_hash_crc";
874418919fSjohnjiang 
884418919fSjohnjiang 	return "UnknownHash";
894418919fSjohnjiang }
904418919fSjohnjiang 
914418919fSjohnjiang /*
924418919fSjohnjiang  * Test a hash function.
934418919fSjohnjiang  */
944418919fSjohnjiang static void
run_hash_func_perf_test(uint32_t key_len,uint32_t init_val,rte_hash_function f)954418919fSjohnjiang run_hash_func_perf_test(uint32_t key_len, uint32_t init_val,
964418919fSjohnjiang 		rte_hash_function f)
974418919fSjohnjiang {
984418919fSjohnjiang 	static uint8_t key[HASHTEST_ITERATIONS][MAX_KEYSIZE];
994418919fSjohnjiang 	uint64_t ticks, start, end;
1004418919fSjohnjiang 	unsigned i, j;
1014418919fSjohnjiang 
1024418919fSjohnjiang 	for (i = 0; i < HASHTEST_ITERATIONS; i++) {
1034418919fSjohnjiang 		for (j = 0; j < key_len; j++)
1044418919fSjohnjiang 			key[i][j] = (uint8_t) rte_rand();
1054418919fSjohnjiang 	}
1064418919fSjohnjiang 
1074418919fSjohnjiang 	start = rte_rdtsc();
1084418919fSjohnjiang 	for (i = 0; i < HASHTEST_ITERATIONS; i++)
1094418919fSjohnjiang 		f(key[i], key_len, init_val);
1104418919fSjohnjiang 	end = rte_rdtsc();
1114418919fSjohnjiang 	ticks = end - start;
1124418919fSjohnjiang 
1134418919fSjohnjiang 	printf("%-12s, %-18u, %-13u, %.02f\n", get_hash_name(f), (unsigned) key_len,
1144418919fSjohnjiang 			(unsigned) init_val, (double)ticks / HASHTEST_ITERATIONS);
1154418919fSjohnjiang }
1164418919fSjohnjiang 
1174418919fSjohnjiang /*
1184418919fSjohnjiang  * Test all hash functions.
1194418919fSjohnjiang  */
1204418919fSjohnjiang static void
run_hash_func_perf_tests(void)1214418919fSjohnjiang run_hash_func_perf_tests(void)
1224418919fSjohnjiang {
1234418919fSjohnjiang 	unsigned i, j, k;
1244418919fSjohnjiang 
1254418919fSjohnjiang 	printf(" *** Hash function performance test results ***\n");
1264418919fSjohnjiang 	printf(" Number of iterations for each test = %d\n",
1274418919fSjohnjiang 			HASHTEST_ITERATIONS);
1284418919fSjohnjiang 	printf("Hash Func.  , Key Length (bytes), Initial value, Ticks/Op.\n");
1294418919fSjohnjiang 
1304418919fSjohnjiang 	for (i = 0; i < RTE_DIM(hashtest_initvals); i++) {
1314418919fSjohnjiang 		for (j = 0; j < RTE_DIM(hashtest_key_lens); j++) {
1324418919fSjohnjiang 			for (k = 0; k < RTE_DIM(hashtest_funcs); k++) {
1334418919fSjohnjiang 				run_hash_func_perf_test(hashtest_key_lens[j],
1344418919fSjohnjiang 						hashtest_initvals[i],
1354418919fSjohnjiang 						hashtest_funcs[k]);
1364418919fSjohnjiang 			}
1374418919fSjohnjiang 		}
1384418919fSjohnjiang 	}
1394418919fSjohnjiang }
1404418919fSjohnjiang 
1414418919fSjohnjiang /*
1424418919fSjohnjiang  * Verify that hash functions return what they are expected to return
1434418919fSjohnjiang  * (using precalculated values stored above)
1444418919fSjohnjiang  */
1454418919fSjohnjiang static int
verify_precalculated_hash_func_tests(void)1464418919fSjohnjiang verify_precalculated_hash_func_tests(void)
1474418919fSjohnjiang {
1484418919fSjohnjiang 	unsigned i, j;
1494418919fSjohnjiang 	uint8_t key[64];
1504418919fSjohnjiang 	uint32_t hash;
1514418919fSjohnjiang 
1524418919fSjohnjiang 	for (i = 0; i < 64; i++)
1534418919fSjohnjiang 		key[i] = (uint8_t) i;
1544418919fSjohnjiang 
155*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_DIM(hashtest_key_lens); i++) {
156*2d9fd380Sjfb8856606 		for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
1574418919fSjohnjiang 			hash = rte_jhash(key, hashtest_key_lens[i],
1584418919fSjohnjiang 					 hashtest_initvals[j]);
1594418919fSjohnjiang 			if (hash != hash_values_jhash[j][i]) {
1604418919fSjohnjiang 				printf("jhash for %u bytes with initial value 0x%x."
1614418919fSjohnjiang 				       "Expected 0x%x, but got 0x%x\n",
1624418919fSjohnjiang 				       hashtest_key_lens[i], hashtest_initvals[j],
1634418919fSjohnjiang 				       hash_values_jhash[j][i], hash);
1644418919fSjohnjiang 				return -1;
1654418919fSjohnjiang 			}
1664418919fSjohnjiang 
1674418919fSjohnjiang 			hash = rte_hash_crc(key, hashtest_key_lens[i],
1684418919fSjohnjiang 					hashtest_initvals[j]);
1694418919fSjohnjiang 			if (hash != hash_values_crc[j][i]) {
1704418919fSjohnjiang 				printf("CRC for %u bytes with initial value 0x%x."
1714418919fSjohnjiang 				       "Expected 0x%x, but got 0x%x\n",
1724418919fSjohnjiang 				       hashtest_key_lens[i], hashtest_initvals[j],
1734418919fSjohnjiang 				       hash_values_crc[j][i], hash);
1744418919fSjohnjiang 				return -1;
1754418919fSjohnjiang 			}
1764418919fSjohnjiang 		}
1774418919fSjohnjiang 	}
1784418919fSjohnjiang 
1794418919fSjohnjiang 	return 0;
1804418919fSjohnjiang }
1814418919fSjohnjiang 
1824418919fSjohnjiang /*
1834418919fSjohnjiang  * Verify that rte_jhash and rte_jhash_32b return the same
1844418919fSjohnjiang  */
1854418919fSjohnjiang static int
verify_jhash_32bits(void)1864418919fSjohnjiang verify_jhash_32bits(void)
1874418919fSjohnjiang {
1884418919fSjohnjiang 	unsigned i, j;
1894418919fSjohnjiang 	uint8_t key[64];
1904418919fSjohnjiang 	uint32_t hash, hash32;
1914418919fSjohnjiang 
1924418919fSjohnjiang 	for (i = 0; i < 64; i++)
1934418919fSjohnjiang 		key[i] = rand() & 0xff;
1944418919fSjohnjiang 
195*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_DIM(hashtest_key_lens); i++) {
196*2d9fd380Sjfb8856606 		for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
1974418919fSjohnjiang 			/* Key size must be multiple of 4 (32 bits) */
1984418919fSjohnjiang 			if ((hashtest_key_lens[i] & 0x3) == 0) {
1994418919fSjohnjiang 				hash = rte_jhash(key, hashtest_key_lens[i],
2004418919fSjohnjiang 						hashtest_initvals[j]);
2014418919fSjohnjiang 				/* Divide key length by 4 in rte_jhash for 32 bits */
2024418919fSjohnjiang 				hash32 = rte_jhash_32b((const unaligned_uint32_t *)key,
2034418919fSjohnjiang 						hashtest_key_lens[i] >> 2,
2044418919fSjohnjiang 						hashtest_initvals[j]);
2054418919fSjohnjiang 				if (hash != hash32) {
2064418919fSjohnjiang 					printf("rte_jhash returns different value (0x%x)"
2074418919fSjohnjiang 					       "than rte_jhash_32b (0x%x)\n",
2084418919fSjohnjiang 					       hash, hash32);
2094418919fSjohnjiang 					return -1;
2104418919fSjohnjiang 				}
2114418919fSjohnjiang 			}
2124418919fSjohnjiang 		}
2134418919fSjohnjiang 	}
2144418919fSjohnjiang 
2154418919fSjohnjiang 	return 0;
2164418919fSjohnjiang }
2174418919fSjohnjiang 
2184418919fSjohnjiang /*
2194418919fSjohnjiang  * Verify that rte_jhash and rte_jhash_1word, rte_jhash_2words
2204418919fSjohnjiang  * and rte_jhash_3words return the same
2214418919fSjohnjiang  */
2224418919fSjohnjiang static int
verify_jhash_words(void)2234418919fSjohnjiang verify_jhash_words(void)
2244418919fSjohnjiang {
2254418919fSjohnjiang 	unsigned i;
2264418919fSjohnjiang 	uint32_t key[3];
2274418919fSjohnjiang 	uint32_t hash, hash_words;
2284418919fSjohnjiang 
2294418919fSjohnjiang 	for (i = 0; i < 3; i++)
2304418919fSjohnjiang 		key[i] = rand();
2314418919fSjohnjiang 
2324418919fSjohnjiang 	/* Test rte_jhash_1word */
2334418919fSjohnjiang 	hash = rte_jhash(key, 4, 0);
2344418919fSjohnjiang 	hash_words = rte_jhash_1word(key[0], 0);
2354418919fSjohnjiang 	if (hash != hash_words) {
2364418919fSjohnjiang 		printf("rte_jhash returns different value (0x%x)"
2374418919fSjohnjiang 		       "than rte_jhash_1word (0x%x)\n",
2384418919fSjohnjiang 		       hash, hash_words);
2394418919fSjohnjiang 		return -1;
2404418919fSjohnjiang 	}
2414418919fSjohnjiang 	/* Test rte_jhash_2words */
2424418919fSjohnjiang 	hash = rte_jhash(key, 8, 0);
2434418919fSjohnjiang 	hash_words = rte_jhash_2words(key[0], key[1], 0);
2444418919fSjohnjiang 	if (hash != hash_words) {
2454418919fSjohnjiang 		printf("rte_jhash returns different value (0x%x)"
2464418919fSjohnjiang 		       "than rte_jhash_2words (0x%x)\n",
2474418919fSjohnjiang 		       hash, hash_words);
2484418919fSjohnjiang 		return -1;
2494418919fSjohnjiang 	}
2504418919fSjohnjiang 	/* Test rte_jhash_3words */
2514418919fSjohnjiang 	hash = rte_jhash(key, 12, 0);
2524418919fSjohnjiang 	hash_words = rte_jhash_3words(key[0], key[1], key[2], 0);
2534418919fSjohnjiang 	if (hash != hash_words) {
2544418919fSjohnjiang 		printf("rte_jhash returns different value (0x%x)"
2554418919fSjohnjiang 		       "than rte_jhash_3words (0x%x)\n",
2564418919fSjohnjiang 		       hash, hash_words);
2574418919fSjohnjiang 		return -1;
2584418919fSjohnjiang 	}
2594418919fSjohnjiang 
2604418919fSjohnjiang 	return 0;
2614418919fSjohnjiang }
2624418919fSjohnjiang 
2634418919fSjohnjiang /*
2644418919fSjohnjiang  * Run all functional tests for hash functions
2654418919fSjohnjiang  */
2664418919fSjohnjiang static int
run_hash_func_tests(void)2674418919fSjohnjiang run_hash_func_tests(void)
2684418919fSjohnjiang {
2694418919fSjohnjiang 	if (verify_precalculated_hash_func_tests() != 0)
2704418919fSjohnjiang 		return -1;
2714418919fSjohnjiang 
2724418919fSjohnjiang 	if (verify_jhash_32bits() != 0)
2734418919fSjohnjiang 		return -1;
2744418919fSjohnjiang 
2754418919fSjohnjiang 	if (verify_jhash_words() != 0)
2764418919fSjohnjiang 		return -1;
2774418919fSjohnjiang 
2784418919fSjohnjiang 	return 0;
2794418919fSjohnjiang 
2804418919fSjohnjiang }
2814418919fSjohnjiang 
2824418919fSjohnjiang static int
test_hash_functions(void)2834418919fSjohnjiang test_hash_functions(void)
2844418919fSjohnjiang {
2854418919fSjohnjiang 	if (run_hash_func_tests() != 0)
2864418919fSjohnjiang 		return -1;
2874418919fSjohnjiang 
2884418919fSjohnjiang 	run_hash_func_perf_tests();
2894418919fSjohnjiang 
2904418919fSjohnjiang 	return 0;
2914418919fSjohnjiang }
2924418919fSjohnjiang 
2934418919fSjohnjiang REGISTER_TEST_COMMAND(hash_functions_autotest, test_hash_functions);
294