1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016-2017 Intel Corporation 3 */ 4 5 #include "test.h" 6 7 #ifdef RTE_EXEC_ENV_WINDOWS 8 static int 9 test_efd_perf(void) 10 { 11 printf("EFD not supported on Windows, skipping test\n"); 12 return TEST_SKIPPED; 13 } 14 15 #else 16 17 #include <stdio.h> 18 #include <inttypes.h> 19 20 #include <rte_lcore.h> 21 #include <rte_cycles.h> 22 #include <rte_malloc.h> 23 #include <rte_random.h> 24 #include <rte_efd.h> 25 #include <rte_memcpy.h> 26 #include <rte_thash.h> 27 28 #define NUM_KEYSIZES 10 29 #define NUM_SHUFFLES 10 30 #define MAX_KEYSIZE 64 31 #define MAX_ENTRIES (1 << 19) 32 #define KEYS_TO_ADD (MAX_ENTRIES * 3 / 4) /* 75% table utilization */ 33 #define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */ 34 35 #if RTE_EFD_VALUE_NUM_BITS == 32 36 #define VALUE_BITMASK 0xffffffff 37 #else 38 #define VALUE_BITMASK ((1 << RTE_EFD_VALUE_NUM_BITS) - 1) 39 #endif 40 static unsigned int test_socket_id; 41 42 static inline uint64_t efd_get_all_sockets_bitmask(void) 43 { 44 uint64_t all_cpu_sockets_bitmask = 0; 45 unsigned int i; 46 unsigned int next_lcore = rte_get_main_lcore(); 47 const int val_true = 1, val_false = 0; 48 for (i = 0; i < rte_lcore_count(); i++) { 49 all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore); 50 next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true); 51 } 52 53 return all_cpu_sockets_bitmask; 54 } 55 56 enum operations { 57 ADD = 0, 58 LOOKUP, 59 LOOKUP_MULTI, 60 DELETE, 61 NUM_OPERATIONS 62 }; 63 64 struct efd_perf_params { 65 struct rte_efd_table *efd_table; 66 uint32_t key_size; 67 unsigned int cycle; 68 }; 69 70 static uint32_t hashtest_key_lens[] = { 71 /* standard key sizes */ 72 4, 8, 16, 32, 48, 64, 73 /* IPv4 SRC + DST + protocol, unpadded */ 74 9, 75 /* IPv4 5-tuple, unpadded */ 76 13, 77 /* IPv6 5-tuple, unpadded */ 78 37, 79 /* IPv6 5-tuple, padded to 8-byte boundary */ 80 40 81 }; 82 83 /* Array to store number of cycles per operation */ 84 static uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS]; 85 86 /* Array to store the data */ 87 static efd_value_t data[KEYS_TO_ADD]; 88 89 /* Array to store all input keys */ 90 static uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE]; 91 92 /* Shuffle the keys that have been added, so lookups will be totally random */ 93 static void 94 shuffle_input_keys(struct efd_perf_params *params) 95 { 96 efd_value_t temp_data; 97 unsigned int i; 98 uint32_t swap_idx; 99 uint8_t temp_key[MAX_KEYSIZE]; 100 101 for (i = KEYS_TO_ADD - 1; i > 0; i--) { 102 swap_idx = rte_rand() % i; 103 104 memcpy(temp_key, keys[i], hashtest_key_lens[params->cycle]); 105 temp_data = data[i]; 106 107 memcpy(keys[i], keys[swap_idx], hashtest_key_lens[params->cycle]); 108 data[i] = data[swap_idx]; 109 110 memcpy(keys[swap_idx], temp_key, hashtest_key_lens[params->cycle]); 111 data[swap_idx] = temp_data; 112 } 113 } 114 115 static int key_compare(const void *key1, const void *key2) 116 { 117 return memcmp(key1, key2, MAX_KEYSIZE); 118 } 119 120 /* 121 * TODO: we could "error proof" these as done in test_hash_perf.c ln 165: 122 * 123 * The current setup may give errors if too full in some cases which we check 124 * for. However, since EFD allows for ~99% capacity, these errors are rare for 125 * #"KEYS_TO_ADD" which is 75% capacity. 126 */ 127 static int 128 setup_keys_and_data(struct efd_perf_params *params, unsigned int cycle) 129 { 130 unsigned int i, j; 131 int num_duplicates; 132 133 params->key_size = hashtest_key_lens[cycle]; 134 params->cycle = cycle; 135 136 /* Reset all arrays */ 137 for (i = 0; i < params->key_size; i++) 138 keys[0][i] = 0; 139 140 /* Generate a list of keys, some of which may be duplicates */ 141 for (i = 0; i < KEYS_TO_ADD; i++) { 142 for (j = 0; j < params->key_size; j++) 143 keys[i][j] = rte_rand() & 0xFF; 144 145 data[i] = rte_rand() & VALUE_BITMASK; 146 } 147 148 /* Remove duplicates from the keys array */ 149 do { 150 num_duplicates = 0; 151 152 /* Sort the list of keys to make it easier to find duplicates */ 153 qsort(keys, KEYS_TO_ADD, MAX_KEYSIZE, key_compare); 154 155 /* Sift through the list of keys and look for duplicates */ 156 int num_duplicates = 0; 157 for (i = 0; i < KEYS_TO_ADD - 1; i++) { 158 if (memcmp(keys[i], keys[i + 1], params->key_size) == 0) { 159 /* This key already exists, try again */ 160 num_duplicates++; 161 for (j = 0; j < params->key_size; j++) 162 keys[i][j] = rte_rand() & 0xFF; 163 } 164 } 165 } while (num_duplicates != 0); 166 167 /* Shuffle the random values again */ 168 shuffle_input_keys(params); 169 170 params->efd_table = rte_efd_create("test_efd_perf", 171 MAX_ENTRIES, params->key_size, 172 efd_get_all_sockets_bitmask(), test_socket_id); 173 TEST_ASSERT_NOT_NULL(params->efd_table, "Error creating the efd table\n"); 174 175 return 0; 176 } 177 178 static int 179 timed_adds(struct efd_perf_params *params) 180 { 181 const uint64_t start_tsc = rte_rdtsc(); 182 unsigned int i, a; 183 int32_t ret; 184 185 for (i = 0; i < KEYS_TO_ADD; i++) { 186 ret = rte_efd_update(params->efd_table, test_socket_id, keys[i], 187 data[i]); 188 if (ret != 0) { 189 printf("Error %d in rte_efd_update - key=0x", ret); 190 for (a = 0; a < params->key_size; a++) 191 printf("%02x", keys[i][a]); 192 printf(" value=%d\n", data[i]); 193 194 return -1; 195 } 196 } 197 198 const uint64_t end_tsc = rte_rdtsc(); 199 const uint64_t time_taken = end_tsc - start_tsc; 200 201 cycles[params->cycle][ADD] = time_taken / KEYS_TO_ADD; 202 return 0; 203 } 204 205 static int 206 timed_lookups(struct efd_perf_params *params) 207 { 208 unsigned int i, j, a; 209 const uint64_t start_tsc = rte_rdtsc(); 210 efd_value_t ret_data; 211 212 for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) { 213 for (j = 0; j < KEYS_TO_ADD; j++) { 214 ret_data = rte_efd_lookup(params->efd_table, 215 test_socket_id, keys[j]); 216 if (ret_data != data[j]) { 217 printf("Value mismatch using rte_efd_lookup: " 218 "key #%d (0x", i); 219 for (a = 0; a < params->key_size; a++) 220 printf("%02x", keys[i][a]); 221 printf(")\n"); 222 printf(" Expected %d, got %d\n", data[i], 223 ret_data); 224 225 return -1; 226 } 227 228 } 229 } 230 231 const uint64_t end_tsc = rte_rdtsc(); 232 const uint64_t time_taken = end_tsc - start_tsc; 233 234 cycles[params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS; 235 236 return 0; 237 } 238 239 static int 240 timed_lookups_multi(struct efd_perf_params *params) 241 { 242 unsigned int i, j, k, a; 243 efd_value_t result[RTE_EFD_BURST_MAX] = {0}; 244 const void *keys_burst[RTE_EFD_BURST_MAX]; 245 const uint64_t start_tsc = rte_rdtsc(); 246 247 for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) { 248 for (j = 0; j < KEYS_TO_ADD / RTE_EFD_BURST_MAX; j++) { 249 for (k = 0; k < RTE_EFD_BURST_MAX; k++) 250 keys_burst[k] = keys[j * RTE_EFD_BURST_MAX + k]; 251 252 rte_efd_lookup_bulk(params->efd_table, test_socket_id, 253 RTE_EFD_BURST_MAX, 254 keys_burst, result); 255 256 for (k = 0; k < RTE_EFD_BURST_MAX; k++) { 257 uint32_t data_idx = j * RTE_EFD_BURST_MAX + k; 258 if (result[k] != data[data_idx]) { 259 printf("Value mismatch using " 260 "rte_efd_lookup_bulk: key #%d " 261 "(0x", i); 262 for (a = 0; a < params->key_size; a++) 263 printf("%02x", 264 keys[data_idx][a]); 265 printf(")\n"); 266 printf(" Expected %d, got %d\n", 267 data[data_idx], result[k]); 268 269 return -1; 270 } 271 } 272 } 273 } 274 275 const uint64_t end_tsc = rte_rdtsc(); 276 const uint64_t time_taken = end_tsc - start_tsc; 277 278 cycles[params->cycle][LOOKUP_MULTI] = time_taken / NUM_LOOKUPS; 279 280 return 0; 281 } 282 283 static int 284 timed_deletes(struct efd_perf_params *params) 285 { 286 unsigned int i, a; 287 const uint64_t start_tsc = rte_rdtsc(); 288 int32_t ret; 289 290 for (i = 0; i < KEYS_TO_ADD; i++) { 291 ret = rte_efd_delete(params->efd_table, test_socket_id, keys[i], 292 NULL); 293 294 if (ret != 0) { 295 printf("Error %d in rte_efd_delete - key=0x", ret); 296 for (a = 0; a < params->key_size; a++) 297 printf("%02x", keys[i][a]); 298 printf("\n"); 299 300 return -1; 301 } 302 } 303 304 const uint64_t end_tsc = rte_rdtsc(); 305 const uint64_t time_taken = end_tsc - start_tsc; 306 307 cycles[params->cycle][DELETE] = time_taken / KEYS_TO_ADD; 308 309 return 0; 310 } 311 312 static void 313 perform_frees(struct efd_perf_params *params) 314 { 315 if (params->efd_table != NULL) { 316 rte_efd_free(params->efd_table); 317 params->efd_table = NULL; 318 } 319 } 320 321 static int 322 exit_with_fail(const char *testname, struct efd_perf_params *params, 323 unsigned int i) 324 { 325 326 printf("<<<<<Test %s failed at keysize %d iteration %d >>>>>\n", 327 testname, hashtest_key_lens[params->cycle], i); 328 perform_frees(params); 329 return -1; 330 } 331 332 static int 333 run_all_tbl_perf_tests(void) 334 { 335 unsigned int i, j; 336 struct efd_perf_params params; 337 338 printf("Measuring performance, please wait\n"); 339 fflush(stdout); 340 341 test_socket_id = rte_socket_id(); 342 343 for (i = 0; i < NUM_KEYSIZES; i++) { 344 345 if (setup_keys_and_data(¶ms, i) < 0) { 346 printf("Could not create keys/data/table\n"); 347 return -1; 348 } 349 350 if (timed_adds(¶ms) < 0) 351 return exit_with_fail("timed_adds", ¶ms, i); 352 353 for (j = 0; j < NUM_SHUFFLES; j++) 354 shuffle_input_keys(¶ms); 355 356 if (timed_lookups(¶ms) < 0) 357 return exit_with_fail("timed_lookups", ¶ms, i); 358 359 if (timed_lookups_multi(¶ms) < 0) 360 return exit_with_fail("timed_lookups_multi", ¶ms, i); 361 362 if (timed_deletes(¶ms) < 0) 363 return exit_with_fail("timed_deletes", ¶ms, i); 364 365 /* Print a dot to show progress on operations */ 366 printf("."); 367 fflush(stdout); 368 369 perform_frees(¶ms); 370 } 371 372 printf("\nResults (in CPU cycles/operation)\n"); 373 printf("-----------------------------------\n"); 374 printf("\n%-18s%-18s%-18s%-18s%-18s\n", 375 "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete"); 376 for (i = 0; i < NUM_KEYSIZES; i++) { 377 printf("%-18d", hashtest_key_lens[i]); 378 for (j = 0; j < NUM_OPERATIONS; j++) 379 printf("%-18"PRIu64, cycles[i][j]); 380 printf("\n"); 381 } 382 return 0; 383 } 384 385 static int 386 test_efd_perf(void) 387 { 388 389 if (run_all_tbl_perf_tests() < 0) 390 return -1; 391 392 return 0; 393 } 394 395 #endif /* !RTE_EXEC_ENV_WINDOWS */ 396 397 REGISTER_TEST_COMMAND(efd_perf_autotest, test_efd_perf); 398