xref: /dpdk/app/test/test_member_perf.c (revision e0a8442ccd15bafbb7eb150c35331c8e3b828c53)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include "test.h"
6 
7 #include <stdio.h>
8 #include <inttypes.h>
9 
10 #include <rte_lcore.h>
11 #include <rte_cycles.h>
12 #include <rte_malloc.h>
13 #include <rte_random.h>
14 #include <rte_memcpy.h>
15 #include <rte_thash.h>
16 #include <math.h>
17 
18 #ifdef RTE_EXEC_ENV_WINDOWS
19 static int
test_member_perf(void)20 test_member_perf(void)
21 {
22 	printf("member_perf not supported on Windows, skipping test\n");
23 	return TEST_SKIPPED;
24 }
25 
26 #else
27 
28 #include <rte_member.h>
29 
30 #define NUM_KEYSIZES RTE_DIM(hashtest_key_lens)
31 #define NUM_SHUFFLES 10
32 #define MAX_KEYSIZE 64
33 #define MAX_ENTRIES (1 << 19)
34 #define KEYS_TO_ADD (MAX_ENTRIES * 75 / 100) /* 75% table utilization */
35 #define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
36 #define VBF_SET_CNT 16
37 #define BURST_SIZE 64
38 #define VBF_FALSE_RATE 0.03
39 
40 /* for the heavy hitter detection */
41 #define SKETCH_LARGEST_KEY_SIZE (1<<15)
42 #define SKETCH_PKT_SIZE 16
43 #define TOP_K 100
44 #define SKETCH_ERROR_RATE 0.05
45 #define SKETCH_SAMPLE_RATE 0.001
46 #define NUM_ADDS (KEYS_TO_ADD * 20)
47 
48 static unsigned int test_socket_id;
49 
50 enum sstype {
51 	HT = 0,
52 	CACHE,
53 	VBF,
54 	SKETCH,
55 	SKETCH_BOUNDED,
56 	SKETCH_BYTE,
57 	NUM_TYPE
58 };
59 
60 enum operations {
61 	ADD = 0,
62 	LOOKUP,
63 	LOOKUP_BULK,
64 	LOOKUP_MULTI,
65 	LOOKUP_MULTI_BULK,
66 	DELETE,
67 	LOOKUP_MISS,
68 	NUM_OPERATIONS
69 };
70 
71 struct  member_perf_params {
72 	struct rte_member_setsum *setsum[NUM_TYPE];
73 	uint32_t key_size;
74 	unsigned int cycle;
75 };
76 
77 static uint32_t hashtest_key_lens[] = {
78 	/* standard key sizes */
79 	4, 8, 16, 32, 48, 64,
80 	/* IPv4 SRC + DST + protocol, unpadded */
81 	9,
82 	/* IPv4 5-tuple, unpadded */
83 	13,
84 	/* IPv6 5-tuple, unpadded */
85 	37,
86 	/* IPv6 5-tuple, padded to 8-byte boundary */
87 	40
88 };
89 
90 /* Array to store number of cycles per operation */
91 static uint64_t cycles[NUM_TYPE][NUM_KEYSIZES][NUM_OPERATIONS];
92 static uint64_t false_data[NUM_TYPE][NUM_KEYSIZES];
93 static uint64_t false_data_bulk[NUM_TYPE][NUM_KEYSIZES];
94 static uint64_t false_data_multi[NUM_TYPE][NUM_KEYSIZES];
95 static uint64_t false_data_multi_bulk[NUM_TYPE][NUM_KEYSIZES];
96 
97 static uint64_t false_hit[NUM_TYPE][NUM_KEYSIZES];
98 
99 static member_set_t data[NUM_TYPE][/* Array to store the data */KEYS_TO_ADD];
100 
101 /* Array to store all input keys */
102 static uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];
103 static uint8_t hh_keys[KEYS_TO_ADD][MAX_KEYSIZE];
104 
105 /* Shuffle the keys that have been added, so lookups will be totally random */
106 static void
shuffle_input_keys(struct member_perf_params * params)107 shuffle_input_keys(struct member_perf_params *params)
108 {
109 	member_set_t temp_data;
110 	unsigned int i, j;
111 	uint32_t swap_idx;
112 	uint8_t temp_key[MAX_KEYSIZE];
113 
114 	for (i = KEYS_TO_ADD - 1; i > 0; i--) {
115 		swap_idx = rte_rand() % i;
116 		memcpy(temp_key, keys[i], hashtest_key_lens[params->cycle]);
117 		memcpy(keys[i], keys[swap_idx],
118 			hashtest_key_lens[params->cycle]);
119 		memcpy(keys[swap_idx], temp_key,
120 			hashtest_key_lens[params->cycle]);
121 		for (j = 0; j < NUM_TYPE; j++) {
122 			temp_data = data[j][i];
123 			data[j][i] = data[j][swap_idx];
124 			data[j][swap_idx] = temp_data;
125 		}
126 	}
127 }
128 
key_compare(const void * key1,const void * key2)129 static int key_compare(const void *key1, const void *key2)
130 {
131 	return memcmp(key1, key2, MAX_KEYSIZE);
132 }
133 
134 struct rte_member_parameters member_params = {
135 		.num_keys = MAX_ENTRIES,	/* Total hash table entries. */
136 		.key_len = 4,			/* Length of hash key. */
137 
138 		/* num_set and false_positive_rate only relevant to vBF */
139 		.num_set = VBF_SET_CNT,
140 		.false_positive_rate = 0.03,
141 		.prim_hash_seed = 0,
142 		.sec_hash_seed = 1,
143 		.socket_id = 0,			/* NUMA Socket ID for memory. */
144 	};
145 
146 static int
setup_keys_and_data(struct member_perf_params * params,unsigned int cycle,int miss)147 setup_keys_and_data(struct member_perf_params *params, unsigned int cycle,
148 		int miss)
149 {
150 	unsigned int i, j;
151 	int num_duplicates;
152 	int distinct_key = 0;
153 	int count_down = SKETCH_LARGEST_KEY_SIZE;
154 	uint32_t swap_idx;
155 	uint8_t temp_key[MAX_KEYSIZE];
156 
157 	params->key_size = hashtest_key_lens[cycle];
158 	params->cycle = cycle;
159 
160 	/* Reset all arrays */
161 	for (i = 0; i < params->key_size; i++)
162 		keys[0][i] = 0;
163 
164 	/* Generate a list of keys, some of which may be duplicates */
165 	for (i = 0; i < KEYS_TO_ADD; i++) {
166 		for (j = 0; j < params->key_size; j++)
167 			keys[i][j] = rte_rand() & 0xFF;
168 
169 		data[HT][i] = data[CACHE][i] = (rte_rand() & 0x7FFE) + 1;
170 		data[VBF][i] = rte_rand() % VBF_SET_CNT + 1;
171 	}
172 
173 	/* Remove duplicates from the keys array */
174 	do {
175 		num_duplicates = 0;
176 
177 		/* Sort the list of keys to make it easier to find duplicates */
178 		qsort(keys, KEYS_TO_ADD, MAX_KEYSIZE, key_compare);
179 
180 		/* Sift through the list of keys and look for duplicates */
181 		for (i = 0; i < KEYS_TO_ADD - 1; i++) {
182 			if (memcmp(keys[i], keys[i + 1],
183 					params->key_size) == 0) {
184 				/* This key already exists, try again */
185 				num_duplicates++;
186 				for (j = 0; j < params->key_size; j++)
187 					keys[i][j] = rte_rand() & 0xFF;
188 			}
189 		}
190 	} while (num_duplicates != 0);
191 
192 	/* Shuffle the random values again */
193 	shuffle_input_keys(params);
194 
195 	for (i = 0; i < KEYS_TO_ADD; i++) {
196 		if (count_down == 0) {
197 			distinct_key++;
198 			count_down = ceil((double)SKETCH_LARGEST_KEY_SIZE /
199 					(distinct_key + 1));
200 		}
201 		memcpy(hh_keys[i], keys[distinct_key], params->key_size);
202 		count_down--;
203 	}
204 
205 	for (i = KEYS_TO_ADD - 1; i > 0; i--) {
206 		swap_idx = rte_rand() % i;
207 		memcpy(temp_key, hh_keys[i], params->key_size);
208 		memcpy(hh_keys[i], hh_keys[swap_idx], params->key_size);
209 		memcpy(hh_keys[swap_idx], temp_key, params->key_size);
210 	}
211 
212 	/* For testing miss lookup, we insert half and lookup the other half */
213 	unsigned int entry_cnt, bf_key_cnt;
214 	if (!miss) {
215 		entry_cnt = MAX_ENTRIES;
216 		bf_key_cnt = KEYS_TO_ADD;
217 	} else {
218 		entry_cnt = MAX_ENTRIES / 2;
219 		bf_key_cnt = KEYS_TO_ADD / 2;
220 	}
221 	member_params.false_positive_rate = VBF_FALSE_RATE;
222 	member_params.key_len = params->key_size;
223 	member_params.socket_id = test_socket_id;
224 	member_params.num_keys = entry_cnt;
225 	member_params.name = "test_member_ht";
226 	member_params.is_cache = 0;
227 	member_params.type = RTE_MEMBER_TYPE_HT;
228 	params->setsum[HT] = rte_member_create(&member_params);
229 	if (params->setsum[HT] == NULL)
230 		fprintf(stderr, "ht create fail\n");
231 
232 	member_params.name = "test_member_cache";
233 	member_params.is_cache = 1;
234 	params->setsum[CACHE] = rte_member_create(&member_params);
235 	if (params->setsum[CACHE] == NULL)
236 		fprintf(stderr, "CACHE create fail\n");
237 
238 	member_params.name = "test_member_vbf";
239 	member_params.type = RTE_MEMBER_TYPE_VBF;
240 	member_params.num_keys = bf_key_cnt;
241 	params->setsum[VBF] = rte_member_create(&member_params);
242 	if (params->setsum[VBF] == NULL)
243 		fprintf(stderr, "VBF create fail\n");
244 
245 	member_params.name = "test_member_sketch";
246 	member_params.key_len = params->key_size;
247 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
248 	member_params.error_rate = SKETCH_ERROR_RATE;
249 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
250 	member_params.extra_flag = 0;
251 	member_params.top_k = TOP_K;
252 	member_params.prim_hash_seed = rte_rdtsc();
253 	params->setsum[SKETCH] = rte_member_create(&member_params);
254 	if (params->setsum[SKETCH] == NULL)
255 		fprintf(stderr, "sketch create fail\n");
256 
257 	member_params.name = "test_member_sketch_bounded";
258 	member_params.key_len = params->key_size;
259 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
260 	member_params.error_rate = SKETCH_ERROR_RATE;
261 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
262 	member_params.extra_flag |= RTE_MEMBER_SKETCH_ALWAYS_BOUNDED;
263 	member_params.top_k = TOP_K;
264 	member_params.prim_hash_seed = rte_rdtsc();
265 	params->setsum[SKETCH_BOUNDED] = rte_member_create(&member_params);
266 	if (params->setsum[SKETCH_BOUNDED] == NULL)
267 		fprintf(stderr, "sketch create fail\n");
268 
269 	member_params.name = "test_member_sketch_byte";
270 	member_params.key_len = params->key_size;
271 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
272 	member_params.error_rate = SKETCH_ERROR_RATE;
273 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
274 	member_params.extra_flag |= RTE_MEMBER_SKETCH_COUNT_BYTE;
275 	member_params.top_k = TOP_K;
276 	member_params.prim_hash_seed = rte_rdtsc();
277 	params->setsum[SKETCH_BYTE] = rte_member_create(&member_params);
278 	if (params->setsum[SKETCH_BYTE] == NULL)
279 		fprintf(stderr, "sketch create fail\n");
280 
281 
282 	for (i = 0; i < NUM_TYPE; i++) {
283 		if (params->setsum[i] == NULL)
284 			return -1;
285 	}
286 
287 	return 0;
288 }
289 
290 static int
timed_adds(struct member_perf_params * params,int type)291 timed_adds(struct member_perf_params *params, int type)
292 {
293 	const uint64_t start_tsc = rte_rdtsc();
294 	unsigned int i, a;
295 	int32_t ret;
296 
297 	for (i = 0; i < KEYS_TO_ADD; i++) {
298 		ret = rte_member_add(params->setsum[type], &keys[i],
299 					data[type][i]);
300 		if (ret < 0) {
301 			printf("Error %d in rte_member_add - key=0x", ret);
302 			for (a = 0; a < params->key_size; a++)
303 				printf("%02x", keys[i][a]);
304 			printf(" value=%d, type: %d\n", data[type][i], type);
305 
306 			return -1;
307 		}
308 	}
309 
310 	const uint64_t end_tsc = rte_rdtsc();
311 	const uint64_t time_taken = end_tsc - start_tsc;
312 
313 	cycles[type][params->cycle][ADD] = time_taken / KEYS_TO_ADD;
314 	return 0;
315 }
316 
317 static int
timed_adds_sketch(struct member_perf_params * params,int type)318 timed_adds_sketch(struct member_perf_params *params, int type)
319 {
320 	const uint64_t start_tsc = rte_rdtsc();
321 	unsigned int i, j, a;
322 	int32_t ret;
323 
324 	for (i = 0; i < NUM_ADDS / KEYS_TO_ADD; i++) {
325 		for (j = 0; j < KEYS_TO_ADD; j++) {
326 			if (type == SKETCH_BYTE)
327 				ret = rte_member_add_byte_count(params->setsum[type],
328 						&hh_keys[j], SKETCH_PKT_SIZE);
329 			else
330 				ret = rte_member_add(params->setsum[type], &hh_keys[j], 1);
331 			if (ret < 0) {
332 				printf("Error %d in rte_member_add - key=0x", ret);
333 				for (a = 0; a < params->key_size; a++)
334 					printf("%02x", hh_keys[j][a]);
335 				printf("type: %d\n", type);
336 
337 				return -1;
338 			}
339 		}
340 	}
341 
342 	const uint64_t end_tsc = rte_rdtsc();
343 	const uint64_t time_taken = end_tsc - start_tsc;
344 
345 	cycles[type][params->cycle][ADD] = time_taken / NUM_ADDS;
346 
347 	return 0;
348 }
349 
350 static int
timed_lookups(struct member_perf_params * params,int type)351 timed_lookups(struct member_perf_params *params, int type)
352 {
353 	unsigned int i, j;
354 
355 	false_data[type][params->cycle] = 0;
356 
357 	const uint64_t start_tsc = rte_rdtsc();
358 	member_set_t result;
359 	int ret;
360 
361 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
362 		for (j = 0; j < KEYS_TO_ADD; j++) {
363 			ret = rte_member_lookup(params->setsum[type], &keys[j],
364 						&result);
365 			if (ret < 0) {
366 				printf("lookup wrong internally");
367 				return -1;
368 			}
369 			if (type == HT && result == RTE_MEMBER_NO_MATCH) {
370 				printf("HT mode shouldn't have false negative");
371 				return -1;
372 			}
373 			if (result != data[type][j])
374 				false_data[type][params->cycle]++;
375 		}
376 	}
377 
378 	const uint64_t end_tsc = rte_rdtsc();
379 	const uint64_t time_taken = end_tsc - start_tsc;
380 
381 	cycles[type][params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS;
382 
383 	return 0;
384 }
385 
386 static int
timed_lookups_sketch(struct member_perf_params * params,int type)387 timed_lookups_sketch(struct member_perf_params *params, int type)
388 {
389 	unsigned int i, j;
390 
391 	false_data[type][params->cycle] = 0;
392 
393 	const uint64_t start_tsc = rte_rdtsc();
394 	member_set_t result;
395 	int ret;
396 
397 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
398 		for (j = 0; j < KEYS_TO_ADD; j++) {
399 			ret = rte_member_lookup(params->setsum[type], &hh_keys[j],
400 						&result);
401 			if (ret < 0) {
402 				printf("lookup wrong internally");
403 				return -1;
404 			}
405 		}
406 	}
407 
408 	const uint64_t end_tsc = rte_rdtsc();
409 	const uint64_t time_taken = end_tsc - start_tsc;
410 
411 	cycles[type][params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS;
412 
413 	return 0;
414 }
415 
416 static int
timed_lookups_bulk(struct member_perf_params * params,int type)417 timed_lookups_bulk(struct member_perf_params *params, int type)
418 {
419 	unsigned int i, j, k;
420 	member_set_t result[BURST_SIZE] = {0};
421 	const void *keys_burst[BURST_SIZE];
422 	int ret;
423 
424 	false_data_bulk[type][params->cycle] = 0;
425 
426 	const uint64_t start_tsc = rte_rdtsc();
427 
428 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
429 		for (j = 0; j < KEYS_TO_ADD / BURST_SIZE; j++) {
430 			for (k = 0; k < BURST_SIZE; k++)
431 				keys_burst[k] = keys[j * BURST_SIZE + k];
432 
433 			ret = rte_member_lookup_bulk(params->setsum[type],
434 				keys_burst,
435 				BURST_SIZE,
436 				result);
437 			if  (ret <= 0) {
438 				printf("lookup bulk has wrong return value\n");
439 				return -1;
440 			}
441 			for (k = 0; k < BURST_SIZE; k++) {
442 				uint32_t data_idx = j * BURST_SIZE + k;
443 				if (type == HT && result[k] ==
444 						RTE_MEMBER_NO_MATCH) {
445 					printf("HT mode shouldn't have "
446 						"false negative");
447 					return -1;
448 				}
449 				if (result[k] != data[type][data_idx])
450 					false_data_bulk[type][params->cycle]++;
451 			}
452 		}
453 	}
454 
455 	const uint64_t end_tsc = rte_rdtsc();
456 	const uint64_t time_taken = end_tsc - start_tsc;
457 
458 	cycles[type][params->cycle][LOOKUP_BULK] = time_taken / NUM_LOOKUPS;
459 
460 	return 0;
461 }
462 
463 static int
timed_lookups_multimatch(struct member_perf_params * params,int type)464 timed_lookups_multimatch(struct member_perf_params *params, int type)
465 {
466 	unsigned int i, j;
467 	member_set_t result[RTE_MEMBER_BUCKET_ENTRIES] = {0};
468 	int ret;
469 	false_data_multi[type][params->cycle] = 0;
470 
471 	const uint64_t start_tsc = rte_rdtsc();
472 
473 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
474 		for (j = 0; j < KEYS_TO_ADD; j++) {
475 			ret = rte_member_lookup_multi(params->setsum[type],
476 				&keys[j], RTE_MEMBER_BUCKET_ENTRIES, result);
477 			if (type != CACHE && ret <= 0) {
478 				printf("lookup multi has wrong return value %d,"
479 					"type %d\n", ret, type);
480 			}
481 			if (type == HT && ret == 0) {
482 				printf("HT mode shouldn't have false negative");
483 				return -1;
484 			}
485 			/*
486 			 * For performance test purpose, we do not iterate all
487 			 * results here. We assume most likely each key can only
488 			 * find one match which is result[0].
489 			 */
490 			if (result[0] != data[type][j])
491 				false_data_multi[type][params->cycle]++;
492 		}
493 	}
494 
495 	const uint64_t end_tsc = rte_rdtsc();
496 	const uint64_t time_taken = end_tsc - start_tsc;
497 
498 	cycles[type][params->cycle][LOOKUP_MULTI] = time_taken / NUM_LOOKUPS;
499 
500 	return 0;
501 }
502 
503 static int
timed_lookups_multimatch_bulk(struct member_perf_params * params,int type)504 timed_lookups_multimatch_bulk(struct member_perf_params *params, int type)
505 {
506 	unsigned int i, j, k;
507 	member_set_t result[BURST_SIZE][RTE_MEMBER_BUCKET_ENTRIES] = {{0} };
508 	const void *keys_burst[BURST_SIZE];
509 	uint32_t match_count[BURST_SIZE];
510 	int ret;
511 
512 	false_data_multi_bulk[type][params->cycle] = 0;
513 
514 	const uint64_t start_tsc = rte_rdtsc();
515 
516 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
517 		for (j = 0; j < KEYS_TO_ADD / BURST_SIZE; j++) {
518 			for (k = 0; k < BURST_SIZE; k++)
519 				keys_burst[k] = keys[j * BURST_SIZE + k];
520 
521 			ret = rte_member_lookup_multi_bulk(
522 				params->setsum[type],
523 				keys_burst, BURST_SIZE,
524 				RTE_MEMBER_BUCKET_ENTRIES, match_count,
525 				(member_set_t *)result);
526 			if (ret < 0) {
527 				printf("lookup multimatch bulk has wrong return"
528 					" value\n");
529 				return -1;
530 			}
531 			for (k = 0; k < BURST_SIZE; k++) {
532 				if (type != CACHE && match_count[k] == 0) {
533 					printf("lookup multimatch bulk get "
534 						"wrong match count\n");
535 					return -1;
536 				}
537 				if (type == HT && match_count[k] == 0) {
538 					printf("HT mode shouldn't have "
539 						"false negative");
540 					return -1;
541 				}
542 				uint32_t data_idx = j * BURST_SIZE + k;
543 				if (result[k][0] != data[type][data_idx])
544 					false_data_multi_bulk[type][params->cycle]++;
545 			}
546 		}
547 	}
548 
549 	const uint64_t end_tsc = rte_rdtsc();
550 	const uint64_t time_taken = end_tsc - start_tsc;
551 
552 	cycles[type][params->cycle][LOOKUP_MULTI_BULK] = time_taken /
553 							NUM_LOOKUPS;
554 
555 	return 0;
556 }
557 
558 static int
timed_deletes(struct member_perf_params * params,int type)559 timed_deletes(struct member_perf_params *params, int type)
560 {
561 	unsigned int i;
562 	int32_t ret;
563 
564 	if (type == VBF)
565 		return 0;
566 	const uint64_t start_tsc = rte_rdtsc();
567 	for (i = 0; i < KEYS_TO_ADD; i++) {
568 		ret = rte_member_delete(params->setsum[type], &keys[i],
569 					data[type][i]);
570 		if (type != CACHE && ret < 0) {
571 			printf("delete error\n");
572 			return -1;
573 		}
574 	}
575 
576 	const uint64_t end_tsc = rte_rdtsc();
577 	const uint64_t time_taken = end_tsc - start_tsc;
578 
579 	cycles[type][params->cycle][DELETE] = time_taken / KEYS_TO_ADD;
580 
581 	return 0;
582 }
583 
584 static int
timed_miss_lookup(struct member_perf_params * params,int type)585 timed_miss_lookup(struct member_perf_params *params, int type)
586 {
587 	unsigned int i, j;
588 	int ret;
589 
590 	false_hit[type][params->cycle] = 0;
591 
592 	for (i = 0; i < KEYS_TO_ADD / 2; i++) {
593 		ret = rte_member_add(params->setsum[type], &keys[i],
594 					data[type][i]);
595 		if (ret < 0) {
596 			unsigned int a;
597 			printf("Error %d in rte_member_add - key=0x", ret);
598 			for (a = 0; a < params->key_size; a++)
599 				printf("%02x", keys[i][a]);
600 			printf(" value=%d, type: %d\n", data[type][i], type);
601 
602 			return -1;
603 		}
604 	}
605 
606 	const uint64_t start_tsc = rte_rdtsc();
607 	member_set_t result;
608 
609 	for (i = 0; i < 2 * NUM_LOOKUPS / KEYS_TO_ADD; i++) {
610 		for (j = KEYS_TO_ADD / 2; j < KEYS_TO_ADD; j++) {
611 			ret = rte_member_lookup(params->setsum[type], &keys[j],
612 						&result);
613 			if (ret < 0) {
614 				printf("lookup wrong internally");
615 				return -1;
616 			}
617 			if (result != RTE_MEMBER_NO_MATCH)
618 				false_hit[type][params->cycle]++;
619 		}
620 	}
621 
622 	const uint64_t end_tsc = rte_rdtsc();
623 	const uint64_t time_taken = end_tsc - start_tsc;
624 
625 	cycles[type][params->cycle][LOOKUP_MISS] = time_taken / NUM_LOOKUPS;
626 
627 	return 0;
628 }
629 
630 static void
perform_frees(struct member_perf_params * params)631 perform_frees(struct member_perf_params *params)
632 {
633 	int i;
634 	for (i = 0; i < NUM_TYPE; i++) {
635 		if (params->setsum[i] != NULL) {
636 			rte_member_free(params->setsum[i]);
637 			params->setsum[i] = NULL;
638 		}
639 	}
640 }
641 
642 static int
exit_with_fail(const char * testname,struct member_perf_params * params,unsigned int i,unsigned int j)643 exit_with_fail(const char *testname, struct member_perf_params *params,
644 		unsigned int i, unsigned int j)
645 {
646 	printf("<<<<<Test %s failed at keysize %d iteration %d type %d>>>>>\n",
647 			testname, hashtest_key_lens[params->cycle], i, j);
648 	perform_frees(params);
649 	return -1;
650 }
651 
652 static int
run_all_tbl_perf_tests(void)653 run_all_tbl_perf_tests(void)
654 {
655 	unsigned int i, j, k;
656 	struct member_perf_params params;
657 
658 	printf("Measuring performance, please wait\n");
659 	fflush(stdout);
660 
661 	test_socket_id = rte_socket_id();
662 
663 	for (i = 0; i < NUM_KEYSIZES; i++) {
664 		if (setup_keys_and_data(&params, i, 0) < 0) {
665 			printf("Could not create keys/data/table\n");
666 			return -1;
667 		}
668 		for (j = 0; j < SKETCH; j++) {
669 
670 			if (timed_adds(&params, j) < 0)
671 				return exit_with_fail("timed_adds", &params,
672 							i, j);
673 
674 			for (k = 0; k < NUM_SHUFFLES; k++)
675 				shuffle_input_keys(&params);
676 
677 			if (timed_lookups(&params, j) < 0)
678 				return exit_with_fail("timed_lookups", &params,
679 							i, j);
680 
681 			if (timed_lookups_bulk(&params, j) < 0)
682 				return exit_with_fail("timed_lookups_bulk",
683 						&params, i, j);
684 
685 			if (timed_lookups_multimatch(&params, j) < 0)
686 				return exit_with_fail("timed_lookups_multi",
687 						&params, i, j);
688 
689 			if (timed_lookups_multimatch_bulk(&params, j) < 0)
690 				return exit_with_fail("timed_lookups_multi_bulk",
691 							&params, i, j);
692 
693 			if (timed_deletes(&params, j) < 0)
694 				return exit_with_fail("timed_deletes", &params,
695 							i, j);
696 
697 			/* Print a dot to show progress on operations */
698 		}
699 
700 		for (j = SKETCH; j < NUM_TYPE; j++) {
701 			if (timed_adds_sketch(&params, j) < 0)
702 				return exit_with_fail
703 					("timed_adds_sketch", &params, i, j);
704 
705 			if (timed_lookups_sketch(&params, j) < 0)
706 				return exit_with_fail
707 					("timed_lookups_sketch", &params, i, j);
708 		}
709 
710 		printf(".");
711 		fflush(stdout);
712 
713 		perform_frees(&params);
714 	}
715 
716 	/* Test false positive rate using un-inserted keys */
717 	for (i = 0; i < NUM_KEYSIZES; i++) {
718 		if (setup_keys_and_data(&params, i, 1) < 0) {
719 			printf("Could not create keys/data/table\n");
720 			return -1;
721 			}
722 		for (j = 0; j < SKETCH; j++) {
723 			if (timed_miss_lookup(&params, j) < 0)
724 				return exit_with_fail("timed_miss_lookup",
725 						&params, i, j);
726 		}
727 		perform_frees(&params);
728 	}
729 
730 	printf("\nResults (in CPU cycles/operation)\n");
731 	printf("-----------------------------------\n");
732 	printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
733 			"Keysize", "type",  "Add", "Lookup", "Lookup_bulk",
734 			"lookup_multi", "lookup_multi_bulk", "Delete",
735 			"miss_lookup");
736 	for (i = 0; i < NUM_KEYSIZES; i++) {
737 		for (j = 0; j < NUM_TYPE; j++) {
738 			printf("%-18d", hashtest_key_lens[i]);
739 			printf("%-18d", j);
740 			for (k = 0; k < NUM_OPERATIONS; k++)
741 				printf("%-18"PRIu64, cycles[j][i][k]);
742 			printf("\n");
743 		}
744 	}
745 
746 	printf("\nFalse results rate (and false positive rate)\n");
747 	printf("-----------------------------------\n");
748 	printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
749 			"Keysize", "type",  "fr_single", "fr_bulk", "fr_multi",
750 			"fr_multi_bulk", "false_positive_rate");
751 	/* Key size not influence False rate so just print out one key size */
752 	for (i = 0; i < 1; i++) {
753 		for (j = 0; j < SKETCH; j++) {
754 			printf("%-18d", hashtest_key_lens[i]);
755 			printf("%-18d", j);
756 			printf("%-18f", (float)false_data[j][i] / NUM_LOOKUPS);
757 			printf("%-18f", (float)false_data_bulk[j][i] /
758 						NUM_LOOKUPS);
759 			printf("%-18f", (float)false_data_multi[j][i] /
760 						NUM_LOOKUPS);
761 			printf("%-18f", (float)false_data_multi_bulk[j][i] /
762 						NUM_LOOKUPS);
763 			printf("%-18f", (float)false_hit[j][i] /
764 						NUM_LOOKUPS);
765 			printf("\n");
766 		}
767 	}
768 	return 0;
769 }
770 
771 static int
test_member_perf(void)772 test_member_perf(void)
773 {
774 
775 	if (run_all_tbl_perf_tests() < 0)
776 		return -1;
777 
778 	return 0;
779 }
780 
781 #endif /* !RTE_EXEC_ENV_WINDOWS */
782 
783 REGISTER_PERF_TEST(member_perf_autotest, test_member_perf);
784