1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 2a9de470cSBruce Richardson * Copyright(c) 2010-2015 Intel Corporation 3a9de470cSBruce Richardson */ 4a9de470cSBruce Richardson 5a9de470cSBruce Richardson #include <stdio.h> 6a9de470cSBruce Richardson #include <stdint.h> 7a9de470cSBruce Richardson #include <string.h> 8a9de470cSBruce Richardson #include <stdlib.h> 9a9de470cSBruce Richardson #include <stdarg.h> 10a9de470cSBruce Richardson #include <errno.h> 11a9de470cSBruce Richardson #include <sys/queue.h> 12a9de470cSBruce Richardson 13a9de470cSBruce Richardson #include <rte_cycles.h> 14a9de470cSBruce Richardson #include <rte_random.h> 15a9de470cSBruce Richardson #include <rte_hash.h> 16a9de470cSBruce Richardson #include <rte_jhash.h> 17a9de470cSBruce Richardson #include <rte_hash_crc.h> 18a9de470cSBruce Richardson 19a9de470cSBruce Richardson #include "test.h" 20a9de470cSBruce Richardson 21a9de470cSBruce Richardson /* 22a9de470cSBruce Richardson * Hash values calculated for key sizes from array "hashtest_key_lens" 23a9de470cSBruce Richardson * and for initial values from array "hashtest_initvals. 24a9de470cSBruce Richardson * Each key will be formed by increasing each byte by 1: 25a9de470cSBruce Richardson * e.g.: key size = 4, key = 0x03020100 26a9de470cSBruce Richardson * key size = 8, key = 0x0706050403020100 27a9de470cSBruce Richardson */ 28a9de470cSBruce Richardson static uint32_t hash_values_jhash[2][12] = {{ 29a9de470cSBruce Richardson 0x8ba9414b, 0xdf0d39c9, 30a9de470cSBruce Richardson 0xe4cf1d42, 0xd4ccb93c, 0x5e84eafc, 0x21362cfe, 31a9de470cSBruce Richardson 0x2f4775ab, 0x9ff036cc, 0xeca51474, 0xbc9d6816, 32a9de470cSBruce Richardson 0x12926a31, 0x1c9fa888 33a9de470cSBruce Richardson }, 34a9de470cSBruce Richardson { 35a9de470cSBruce Richardson 0x5c62c303, 0x1b8cf784, 36a9de470cSBruce Richardson 0x8270ac65, 0x05fa6668, 0x762df861, 0xda088f2f, 37a9de470cSBruce Richardson 0x59614cd4, 0x7a94f690, 0xdc1e4993, 0x30825494, 38a9de470cSBruce Richardson 0x91d0e462, 0x768087fc 39a9de470cSBruce Richardson } 40a9de470cSBruce Richardson }; 41a9de470cSBruce Richardson static uint32_t hash_values_crc[2][12] = {{ 42a9de470cSBruce Richardson 0x00000000, 0xf26b8303, 43a9de470cSBruce Richardson 0x91545164, 0x06040eb1, 0x9bb99201, 0xcc4c4fe4, 44a9de470cSBruce Richardson 0x14a90993, 0xf8a5dd8c, 0xcaa1ad0b, 0x7ac1e03e, 45a9de470cSBruce Richardson 0x43f44466, 0x4a11475e 46a9de470cSBruce Richardson }, 47a9de470cSBruce Richardson { 48a9de470cSBruce Richardson 0xbdfd3980, 0x70204542, 49a9de470cSBruce Richardson 0x98cd4c70, 0xd52c702f, 0x41fc0e1c, 0x3905f65c, 50a9de470cSBruce Richardson 0x94bff47f, 0x1bab102d, 0xf4a2c645, 0xbf441539, 51a9de470cSBruce Richardson 0x789c104f, 0x53028d3e 52a9de470cSBruce Richardson } 53a9de470cSBruce Richardson }; 54a9de470cSBruce Richardson 55a9de470cSBruce Richardson /******************************************************************************* 56a9de470cSBruce Richardson * Hash function performance test configuration section. Each performance test 57a9de470cSBruce Richardson * will be performed HASHTEST_ITERATIONS times. 58a9de470cSBruce Richardson * 59a9de470cSBruce Richardson * The three arrays below control what tests are performed. Every combination 60a9de470cSBruce Richardson * from the array entries is tested. 61a9de470cSBruce Richardson */ 62a9de470cSBruce Richardson #define HASHTEST_ITERATIONS 1000000 63a9de470cSBruce Richardson #define MAX_KEYSIZE 64 64a9de470cSBruce Richardson static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; 65a9de470cSBruce Richardson static uint32_t hashtest_initvals[] = {0, 0xdeadbeef}; 66a9de470cSBruce Richardson static uint32_t hashtest_key_lens[] = { 67a9de470cSBruce Richardson 1, 2, /* Unusual key sizes */ 68a9de470cSBruce Richardson 4, 8, 16, 32, 48, 64, /* standard key sizes */ 69a9de470cSBruce Richardson 9, /* IPv4 SRC + DST + protocol, unpadded */ 70a9de470cSBruce Richardson 13, /* IPv4 5-tuple, unpadded */ 71a9de470cSBruce Richardson 37, /* IPv6 5-tuple, unpadded */ 72a9de470cSBruce Richardson 40 /* IPv6 5-tuple, padded to 8-byte boundary */ 73a9de470cSBruce Richardson }; 74a9de470cSBruce Richardson /******************************************************************************/ 75a9de470cSBruce Richardson 76a9de470cSBruce Richardson /* 77a9de470cSBruce Richardson * To help print out name of hash functions. 78a9de470cSBruce Richardson */ 79a9de470cSBruce Richardson static const char * 80a9de470cSBruce Richardson get_hash_name(rte_hash_function f) 81a9de470cSBruce Richardson { 82a9de470cSBruce Richardson if (f == rte_jhash) 83a9de470cSBruce Richardson return "jhash"; 84a9de470cSBruce Richardson 85a9de470cSBruce Richardson if (f == rte_hash_crc) 86a9de470cSBruce Richardson return "rte_hash_crc"; 87a9de470cSBruce Richardson 88a9de470cSBruce Richardson return "UnknownHash"; 89a9de470cSBruce Richardson } 90a9de470cSBruce Richardson 91a9de470cSBruce Richardson /* 92a9de470cSBruce Richardson * Test a hash function. 93a9de470cSBruce Richardson */ 94a9de470cSBruce Richardson static void 95a9de470cSBruce Richardson run_hash_func_perf_test(uint32_t key_len, uint32_t init_val, 96a9de470cSBruce Richardson rte_hash_function f) 97a9de470cSBruce Richardson { 98a9de470cSBruce Richardson static uint8_t key[HASHTEST_ITERATIONS][MAX_KEYSIZE]; 99a9de470cSBruce Richardson uint64_t ticks, start, end; 100a9de470cSBruce Richardson unsigned i, j; 101a9de470cSBruce Richardson 102a9de470cSBruce Richardson for (i = 0; i < HASHTEST_ITERATIONS; i++) { 103a9de470cSBruce Richardson for (j = 0; j < key_len; j++) 104a9de470cSBruce Richardson key[i][j] = (uint8_t) rte_rand(); 105a9de470cSBruce Richardson } 106a9de470cSBruce Richardson 107a9de470cSBruce Richardson start = rte_rdtsc(); 108a9de470cSBruce Richardson for (i = 0; i < HASHTEST_ITERATIONS; i++) 109a9de470cSBruce Richardson f(key[i], key_len, init_val); 110a9de470cSBruce Richardson end = rte_rdtsc(); 111a9de470cSBruce Richardson ticks = end - start; 112a9de470cSBruce Richardson 113a9de470cSBruce Richardson printf("%-12s, %-18u, %-13u, %.02f\n", get_hash_name(f), (unsigned) key_len, 114a9de470cSBruce Richardson (unsigned) init_val, (double)ticks / HASHTEST_ITERATIONS); 115a9de470cSBruce Richardson } 116a9de470cSBruce Richardson 117a9de470cSBruce Richardson /* 118a9de470cSBruce Richardson * Test all hash functions. 119a9de470cSBruce Richardson */ 120a9de470cSBruce Richardson static void 121a9de470cSBruce Richardson run_hash_func_perf_tests(void) 122a9de470cSBruce Richardson { 123a9de470cSBruce Richardson unsigned i, j, k; 124a9de470cSBruce Richardson 125a9de470cSBruce Richardson printf(" *** Hash function performance test results ***\n"); 126a9de470cSBruce Richardson printf(" Number of iterations for each test = %d\n", 127a9de470cSBruce Richardson HASHTEST_ITERATIONS); 128a9de470cSBruce Richardson printf("Hash Func. , Key Length (bytes), Initial value, Ticks/Op.\n"); 129a9de470cSBruce Richardson 130a9de470cSBruce Richardson for (i = 0; i < RTE_DIM(hashtest_initvals); i++) { 131a9de470cSBruce Richardson for (j = 0; j < RTE_DIM(hashtest_key_lens); j++) { 132a9de470cSBruce Richardson for (k = 0; k < RTE_DIM(hashtest_funcs); k++) { 133a9de470cSBruce Richardson run_hash_func_perf_test(hashtest_key_lens[j], 134a9de470cSBruce Richardson hashtest_initvals[i], 135a9de470cSBruce Richardson hashtest_funcs[k]); 136a9de470cSBruce Richardson } 137a9de470cSBruce Richardson } 138a9de470cSBruce Richardson } 139a9de470cSBruce Richardson } 140a9de470cSBruce Richardson 141a9de470cSBruce Richardson /* 142a9de470cSBruce Richardson * Verify that hash functions return what they are expected to return 143a9de470cSBruce Richardson * (using precalculated values stored above) 144a9de470cSBruce Richardson */ 145a9de470cSBruce Richardson static int 146a9de470cSBruce Richardson verify_precalculated_hash_func_tests(void) 147a9de470cSBruce Richardson { 148a9de470cSBruce Richardson unsigned i, j; 149a9de470cSBruce Richardson uint8_t key[64]; 150a9de470cSBruce Richardson uint32_t hash; 151a9de470cSBruce Richardson 152a9de470cSBruce Richardson for (i = 0; i < 64; i++) 153a9de470cSBruce Richardson key[i] = (uint8_t) i; 154a9de470cSBruce Richardson 155*71bdd8a1SPavan Nikhilesh for (i = 0; i < RTE_DIM(hashtest_key_lens); i++) { 156*71bdd8a1SPavan Nikhilesh for (j = 0; j < RTE_DIM(hashtest_initvals); j++) { 157a9de470cSBruce Richardson hash = rte_jhash(key, hashtest_key_lens[i], 158a9de470cSBruce Richardson hashtest_initvals[j]); 159a9de470cSBruce Richardson if (hash != hash_values_jhash[j][i]) { 160a9de470cSBruce Richardson printf("jhash for %u bytes with initial value 0x%x." 161a9de470cSBruce Richardson "Expected 0x%x, but got 0x%x\n", 162a9de470cSBruce Richardson hashtest_key_lens[i], hashtest_initvals[j], 163a9de470cSBruce Richardson hash_values_jhash[j][i], hash); 164a9de470cSBruce Richardson return -1; 165a9de470cSBruce Richardson } 166a9de470cSBruce Richardson 167a9de470cSBruce Richardson hash = rte_hash_crc(key, hashtest_key_lens[i], 168a9de470cSBruce Richardson hashtest_initvals[j]); 169a9de470cSBruce Richardson if (hash != hash_values_crc[j][i]) { 170a9de470cSBruce Richardson printf("CRC for %u bytes with initial value 0x%x." 171a9de470cSBruce Richardson "Expected 0x%x, but got 0x%x\n", 172a9de470cSBruce Richardson hashtest_key_lens[i], hashtest_initvals[j], 173a9de470cSBruce Richardson hash_values_crc[j][i], hash); 174a9de470cSBruce Richardson return -1; 175a9de470cSBruce Richardson } 176a9de470cSBruce Richardson } 177a9de470cSBruce Richardson } 178a9de470cSBruce Richardson 179a9de470cSBruce Richardson return 0; 180a9de470cSBruce Richardson } 181a9de470cSBruce Richardson 182a9de470cSBruce Richardson /* 183a9de470cSBruce Richardson * Verify that rte_jhash and rte_jhash_32b return the same 184a9de470cSBruce Richardson */ 185a9de470cSBruce Richardson static int 186a9de470cSBruce Richardson verify_jhash_32bits(void) 187a9de470cSBruce Richardson { 188a9de470cSBruce Richardson unsigned i, j; 189a9de470cSBruce Richardson uint8_t key[64]; 190a9de470cSBruce Richardson uint32_t hash, hash32; 191a9de470cSBruce Richardson 192a9de470cSBruce Richardson for (i = 0; i < 64; i++) 193a9de470cSBruce Richardson key[i] = rand() & 0xff; 194a9de470cSBruce Richardson 195*71bdd8a1SPavan Nikhilesh for (i = 0; i < RTE_DIM(hashtest_key_lens); i++) { 196*71bdd8a1SPavan Nikhilesh for (j = 0; j < RTE_DIM(hashtest_initvals); j++) { 197a9de470cSBruce Richardson /* Key size must be multiple of 4 (32 bits) */ 198a9de470cSBruce Richardson if ((hashtest_key_lens[i] & 0x3) == 0) { 199a9de470cSBruce Richardson hash = rte_jhash(key, hashtest_key_lens[i], 200a9de470cSBruce Richardson hashtest_initvals[j]); 201a9de470cSBruce Richardson /* Divide key length by 4 in rte_jhash for 32 bits */ 202a9de470cSBruce Richardson hash32 = rte_jhash_32b((const unaligned_uint32_t *)key, 203a9de470cSBruce Richardson hashtest_key_lens[i] >> 2, 204a9de470cSBruce Richardson hashtest_initvals[j]); 205a9de470cSBruce Richardson if (hash != hash32) { 206a9de470cSBruce Richardson printf("rte_jhash returns different value (0x%x)" 207a9de470cSBruce Richardson "than rte_jhash_32b (0x%x)\n", 208a9de470cSBruce Richardson hash, hash32); 209a9de470cSBruce Richardson return -1; 210a9de470cSBruce Richardson } 211a9de470cSBruce Richardson } 212a9de470cSBruce Richardson } 213a9de470cSBruce Richardson } 214a9de470cSBruce Richardson 215a9de470cSBruce Richardson return 0; 216a9de470cSBruce Richardson } 217a9de470cSBruce Richardson 218a9de470cSBruce Richardson /* 219a9de470cSBruce Richardson * Verify that rte_jhash and rte_jhash_1word, rte_jhash_2words 220a9de470cSBruce Richardson * and rte_jhash_3words return the same 221a9de470cSBruce Richardson */ 222a9de470cSBruce Richardson static int 223a9de470cSBruce Richardson verify_jhash_words(void) 224a9de470cSBruce Richardson { 225a9de470cSBruce Richardson unsigned i; 226a9de470cSBruce Richardson uint32_t key[3]; 227a9de470cSBruce Richardson uint32_t hash, hash_words; 228a9de470cSBruce Richardson 229a9de470cSBruce Richardson for (i = 0; i < 3; i++) 230a9de470cSBruce Richardson key[i] = rand(); 231a9de470cSBruce Richardson 232a9de470cSBruce Richardson /* Test rte_jhash_1word */ 233a9de470cSBruce Richardson hash = rte_jhash(key, 4, 0); 234a9de470cSBruce Richardson hash_words = rte_jhash_1word(key[0], 0); 235a9de470cSBruce Richardson if (hash != hash_words) { 236a9de470cSBruce Richardson printf("rte_jhash returns different value (0x%x)" 237a9de470cSBruce Richardson "than rte_jhash_1word (0x%x)\n", 238a9de470cSBruce Richardson hash, hash_words); 239a9de470cSBruce Richardson return -1; 240a9de470cSBruce Richardson } 241a9de470cSBruce Richardson /* Test rte_jhash_2words */ 242a9de470cSBruce Richardson hash = rte_jhash(key, 8, 0); 243a9de470cSBruce Richardson hash_words = rte_jhash_2words(key[0], key[1], 0); 244a9de470cSBruce Richardson if (hash != hash_words) { 245a9de470cSBruce Richardson printf("rte_jhash returns different value (0x%x)" 246a9de470cSBruce Richardson "than rte_jhash_2words (0x%x)\n", 247a9de470cSBruce Richardson hash, hash_words); 248a9de470cSBruce Richardson return -1; 249a9de470cSBruce Richardson } 250a9de470cSBruce Richardson /* Test rte_jhash_3words */ 251a9de470cSBruce Richardson hash = rte_jhash(key, 12, 0); 252a9de470cSBruce Richardson hash_words = rte_jhash_3words(key[0], key[1], key[2], 0); 253a9de470cSBruce Richardson if (hash != hash_words) { 254a9de470cSBruce Richardson printf("rte_jhash returns different value (0x%x)" 255a9de470cSBruce Richardson "than rte_jhash_3words (0x%x)\n", 256a9de470cSBruce Richardson hash, hash_words); 257a9de470cSBruce Richardson return -1; 258a9de470cSBruce Richardson } 259a9de470cSBruce Richardson 260a9de470cSBruce Richardson return 0; 261a9de470cSBruce Richardson } 262a9de470cSBruce Richardson 263a9de470cSBruce Richardson /* 264a9de470cSBruce Richardson * Run all functional tests for hash functions 265a9de470cSBruce Richardson */ 266a9de470cSBruce Richardson static int 267a9de470cSBruce Richardson run_hash_func_tests(void) 268a9de470cSBruce Richardson { 269a9de470cSBruce Richardson if (verify_precalculated_hash_func_tests() != 0) 270a9de470cSBruce Richardson return -1; 271a9de470cSBruce Richardson 272a9de470cSBruce Richardson if (verify_jhash_32bits() != 0) 273a9de470cSBruce Richardson return -1; 274a9de470cSBruce Richardson 275a9de470cSBruce Richardson if (verify_jhash_words() != 0) 276a9de470cSBruce Richardson return -1; 277a9de470cSBruce Richardson 278a9de470cSBruce Richardson return 0; 279a9de470cSBruce Richardson 280a9de470cSBruce Richardson } 281a9de470cSBruce Richardson 282a9de470cSBruce Richardson static int 283a9de470cSBruce Richardson test_hash_functions(void) 284a9de470cSBruce Richardson { 285a9de470cSBruce Richardson if (run_hash_func_tests() != 0) 286a9de470cSBruce Richardson return -1; 287a9de470cSBruce Richardson 288a9de470cSBruce Richardson run_hash_func_perf_tests(); 289a9de470cSBruce Richardson 290a9de470cSBruce Richardson return 0; 291a9de470cSBruce Richardson } 292a9de470cSBruce Richardson 293a9de470cSBruce Richardson REGISTER_TEST_COMMAND(hash_functions_autotest, test_hash_functions); 294