xref: /dpdk/app/test/test_member_perf.c (revision dc348f2e81a94dd3b8a32c2f882483227796905d)
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
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
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 
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
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 		int num_duplicates = 0;
182 		for (i = 0; i < KEYS_TO_ADD - 1; i++) {
183 			if (memcmp(keys[i], keys[i + 1],
184 					params->key_size) == 0) {
185 				/* This key already exists, try again */
186 				num_duplicates++;
187 				for (j = 0; j < params->key_size; j++)
188 					keys[i][j] = rte_rand() & 0xFF;
189 			}
190 		}
191 	} while (num_duplicates != 0);
192 
193 	/* Shuffle the random values again */
194 	shuffle_input_keys(params);
195 
196 	for (i = 0; i < KEYS_TO_ADD; i++) {
197 		if (count_down == 0) {
198 			distinct_key++;
199 			count_down = ceil((double)SKETCH_LARGEST_KEY_SIZE /
200 					(distinct_key + 1));
201 		}
202 		memcpy(hh_keys[i], keys[distinct_key], params->key_size);
203 		count_down--;
204 	}
205 
206 	for (i = KEYS_TO_ADD - 1; i > 0; i--) {
207 		swap_idx = rte_rand() % i;
208 		memcpy(temp_key, hh_keys[i], params->key_size);
209 		memcpy(hh_keys[i], hh_keys[swap_idx], params->key_size);
210 		memcpy(hh_keys[swap_idx], temp_key, params->key_size);
211 	}
212 
213 	/* For testing miss lookup, we insert half and lookup the other half */
214 	unsigned int entry_cnt, bf_key_cnt;
215 	if (!miss) {
216 		entry_cnt = MAX_ENTRIES;
217 		bf_key_cnt = KEYS_TO_ADD;
218 	} else {
219 		entry_cnt = MAX_ENTRIES / 2;
220 		bf_key_cnt = KEYS_TO_ADD / 2;
221 	}
222 	member_params.false_positive_rate = VBF_FALSE_RATE;
223 	member_params.key_len = params->key_size;
224 	member_params.socket_id = test_socket_id;
225 	member_params.num_keys = entry_cnt;
226 	member_params.name = "test_member_ht";
227 	member_params.is_cache = 0;
228 	member_params.type = RTE_MEMBER_TYPE_HT;
229 	params->setsum[HT] = rte_member_create(&member_params);
230 	if (params->setsum[HT] == NULL)
231 		fprintf(stderr, "ht create fail\n");
232 
233 	member_params.name = "test_member_cache";
234 	member_params.is_cache = 1;
235 	params->setsum[CACHE] = rte_member_create(&member_params);
236 	if (params->setsum[CACHE] == NULL)
237 		fprintf(stderr, "CACHE create fail\n");
238 
239 	member_params.name = "test_member_vbf";
240 	member_params.type = RTE_MEMBER_TYPE_VBF;
241 	member_params.num_keys = bf_key_cnt;
242 	params->setsum[VBF] = rte_member_create(&member_params);
243 	if (params->setsum[VBF] == NULL)
244 		fprintf(stderr, "VBF create fail\n");
245 
246 	member_params.name = "test_member_sketch";
247 	member_params.key_len = params->key_size;
248 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
249 	member_params.error_rate = SKETCH_ERROR_RATE;
250 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
251 	member_params.extra_flag = 0;
252 	member_params.top_k = TOP_K;
253 	member_params.prim_hash_seed = rte_rdtsc();
254 	params->setsum[SKETCH] = rte_member_create(&member_params);
255 	if (params->setsum[SKETCH] == NULL)
256 		fprintf(stderr, "sketch create fail\n");
257 
258 	member_params.name = "test_member_sketch_bounded";
259 	member_params.key_len = params->key_size;
260 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
261 	member_params.error_rate = SKETCH_ERROR_RATE;
262 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
263 	member_params.extra_flag |= RTE_MEMBER_SKETCH_ALWAYS_BOUNDED;
264 	member_params.top_k = TOP_K;
265 	member_params.prim_hash_seed = rte_rdtsc();
266 	params->setsum[SKETCH_BOUNDED] = rte_member_create(&member_params);
267 	if (params->setsum[SKETCH_BOUNDED] == NULL)
268 		fprintf(stderr, "sketch create fail\n");
269 
270 	member_params.name = "test_member_sketch_byte";
271 	member_params.key_len = params->key_size;
272 	member_params.type = RTE_MEMBER_TYPE_SKETCH;
273 	member_params.error_rate = SKETCH_ERROR_RATE;
274 	member_params.sample_rate = SKETCH_SAMPLE_RATE;
275 	member_params.extra_flag |= RTE_MEMBER_SKETCH_COUNT_BYTE;
276 	member_params.top_k = TOP_K;
277 	member_params.prim_hash_seed = rte_rdtsc();
278 	params->setsum[SKETCH_BYTE] = rte_member_create(&member_params);
279 	if (params->setsum[SKETCH_BYTE] == NULL)
280 		fprintf(stderr, "sketch create fail\n");
281 
282 
283 	for (i = 0; i < NUM_TYPE; i++) {
284 		if (params->setsum[i] == NULL)
285 			return -1;
286 	}
287 
288 	return 0;
289 }
290 
291 static int
292 timed_adds(struct member_perf_params *params, int type)
293 {
294 	const uint64_t start_tsc = rte_rdtsc();
295 	unsigned int i, a;
296 	int32_t ret;
297 
298 	for (i = 0; i < KEYS_TO_ADD; i++) {
299 		ret = rte_member_add(params->setsum[type], &keys[i],
300 					data[type][i]);
301 		if (ret < 0) {
302 			printf("Error %d in rte_member_add - key=0x", ret);
303 			for (a = 0; a < params->key_size; a++)
304 				printf("%02x", keys[i][a]);
305 			printf(" value=%d, type: %d\n", data[type][i], type);
306 
307 			return -1;
308 		}
309 	}
310 
311 	const uint64_t end_tsc = rte_rdtsc();
312 	const uint64_t time_taken = end_tsc - start_tsc;
313 
314 	cycles[type][params->cycle][ADD] = time_taken / KEYS_TO_ADD;
315 	return 0;
316 }
317 
318 static int
319 timed_adds_sketch(struct member_perf_params *params, int type)
320 {
321 	const uint64_t start_tsc = rte_rdtsc();
322 	unsigned int i, j, a;
323 	int32_t ret;
324 
325 	for (i = 0; i < NUM_ADDS / KEYS_TO_ADD; i++) {
326 		for (j = 0; j < KEYS_TO_ADD; j++) {
327 			if (type == SKETCH_BYTE)
328 				ret = rte_member_add_byte_count(params->setsum[type],
329 						&hh_keys[j], SKETCH_PKT_SIZE);
330 			else
331 				ret = rte_member_add(params->setsum[type], &hh_keys[j], 1);
332 			if (ret < 0) {
333 				printf("Error %d in rte_member_add - key=0x", ret);
334 				for (a = 0; a < params->key_size; a++)
335 					printf("%02x", hh_keys[j][a]);
336 				printf("type: %d\n", type);
337 
338 				return -1;
339 			}
340 		}
341 	}
342 
343 	const uint64_t end_tsc = rte_rdtsc();
344 	const uint64_t time_taken = end_tsc - start_tsc;
345 
346 	cycles[type][params->cycle][ADD] = time_taken / NUM_ADDS;
347 
348 	return 0;
349 }
350 
351 static int
352 timed_lookups(struct member_perf_params *params, int type)
353 {
354 	unsigned int i, j;
355 
356 	false_data[type][params->cycle] = 0;
357 
358 	const uint64_t start_tsc = rte_rdtsc();
359 	member_set_t result;
360 	int ret;
361 
362 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
363 		for (j = 0; j < KEYS_TO_ADD; j++) {
364 			ret = rte_member_lookup(params->setsum[type], &keys[j],
365 						&result);
366 			if (ret < 0) {
367 				printf("lookup wrong internally");
368 				return -1;
369 			}
370 			if (type == HT && result == RTE_MEMBER_NO_MATCH) {
371 				printf("HT mode shouldn't have false negative");
372 				return -1;
373 			}
374 			if (result != data[type][j])
375 				false_data[type][params->cycle]++;
376 		}
377 	}
378 
379 	const uint64_t end_tsc = rte_rdtsc();
380 	const uint64_t time_taken = end_tsc - start_tsc;
381 
382 	cycles[type][params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS;
383 
384 	return 0;
385 }
386 
387 static int
388 timed_lookups_sketch(struct member_perf_params *params, int type)
389 {
390 	unsigned int i, j;
391 
392 	false_data[type][params->cycle] = 0;
393 
394 	const uint64_t start_tsc = rte_rdtsc();
395 	member_set_t result;
396 	int ret;
397 
398 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
399 		for (j = 0; j < KEYS_TO_ADD; j++) {
400 			ret = rte_member_lookup(params->setsum[type], &hh_keys[j],
401 						&result);
402 			if (ret < 0) {
403 				printf("lookup wrong internally");
404 				return -1;
405 			}
406 		}
407 	}
408 
409 	const uint64_t end_tsc = rte_rdtsc();
410 	const uint64_t time_taken = end_tsc - start_tsc;
411 
412 	cycles[type][params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS;
413 
414 	return 0;
415 }
416 
417 static int
418 timed_lookups_bulk(struct member_perf_params *params, int type)
419 {
420 	unsigned int i, j, k;
421 	member_set_t result[BURST_SIZE] = {0};
422 	const void *keys_burst[BURST_SIZE];
423 	int ret;
424 
425 	false_data_bulk[type][params->cycle] = 0;
426 
427 	const uint64_t start_tsc = rte_rdtsc();
428 
429 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
430 		for (j = 0; j < KEYS_TO_ADD / BURST_SIZE; j++) {
431 			for (k = 0; k < BURST_SIZE; k++)
432 				keys_burst[k] = keys[j * BURST_SIZE + k];
433 
434 			ret = rte_member_lookup_bulk(params->setsum[type],
435 				keys_burst,
436 				BURST_SIZE,
437 				result);
438 			if  (ret <= 0) {
439 				printf("lookup bulk has wrong return value\n");
440 				return -1;
441 			}
442 			for (k = 0; k < BURST_SIZE; k++) {
443 				uint32_t data_idx = j * BURST_SIZE + k;
444 				if (type == HT && result[k] ==
445 						RTE_MEMBER_NO_MATCH) {
446 					printf("HT mode shouldn't have "
447 						"false negative");
448 					return -1;
449 				}
450 				if (result[k] != data[type][data_idx])
451 					false_data_bulk[type][params->cycle]++;
452 			}
453 		}
454 	}
455 
456 	const uint64_t end_tsc = rte_rdtsc();
457 	const uint64_t time_taken = end_tsc - start_tsc;
458 
459 	cycles[type][params->cycle][LOOKUP_BULK] = time_taken / NUM_LOOKUPS;
460 
461 	return 0;
462 }
463 
464 static int
465 timed_lookups_multimatch(struct member_perf_params *params, int type)
466 {
467 	unsigned int i, j;
468 	member_set_t result[RTE_MEMBER_BUCKET_ENTRIES] = {0};
469 	int ret;
470 	false_data_multi[type][params->cycle] = 0;
471 
472 	const uint64_t start_tsc = rte_rdtsc();
473 
474 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
475 		for (j = 0; j < KEYS_TO_ADD; j++) {
476 			ret = rte_member_lookup_multi(params->setsum[type],
477 				&keys[j], RTE_MEMBER_BUCKET_ENTRIES, result);
478 			if (type != CACHE && ret <= 0) {
479 				printf("lookup multi has wrong return value %d,"
480 					"type %d\n", ret, type);
481 			}
482 			if (type == HT && ret == 0) {
483 				printf("HT mode shouldn't have false negative");
484 				return -1;
485 			}
486 			/*
487 			 * For performance test purpose, we do not iterate all
488 			 * results here. We assume most likely each key can only
489 			 * find one match which is result[0].
490 			 */
491 			if (result[0] != data[type][j])
492 				false_data_multi[type][params->cycle]++;
493 		}
494 	}
495 
496 	const uint64_t end_tsc = rte_rdtsc();
497 	const uint64_t time_taken = end_tsc - start_tsc;
498 
499 	cycles[type][params->cycle][LOOKUP_MULTI] = time_taken / NUM_LOOKUPS;
500 
501 	return 0;
502 }
503 
504 static int
505 timed_lookups_multimatch_bulk(struct member_perf_params *params, int type)
506 {
507 	unsigned int i, j, k;
508 	member_set_t result[BURST_SIZE][RTE_MEMBER_BUCKET_ENTRIES] = {{0} };
509 	const void *keys_burst[BURST_SIZE];
510 	uint32_t match_count[BURST_SIZE];
511 	int ret;
512 
513 	false_data_multi_bulk[type][params->cycle] = 0;
514 
515 	const uint64_t start_tsc = rte_rdtsc();
516 
517 	for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) {
518 		for (j = 0; j < KEYS_TO_ADD / BURST_SIZE; j++) {
519 			for (k = 0; k < BURST_SIZE; k++)
520 				keys_burst[k] = keys[j * BURST_SIZE + k];
521 
522 			ret = rte_member_lookup_multi_bulk(
523 				params->setsum[type],
524 				keys_burst, BURST_SIZE,
525 				RTE_MEMBER_BUCKET_ENTRIES, match_count,
526 				(member_set_t *)result);
527 			if (ret < 0) {
528 				printf("lookup multimatch bulk has wrong return"
529 					" value\n");
530 				return -1;
531 			}
532 			for (k = 0; k < BURST_SIZE; k++) {
533 				if (type != CACHE && match_count[k] == 0) {
534 					printf("lookup multimatch bulk get "
535 						"wrong match count\n");
536 					return -1;
537 				}
538 				if (type == HT && match_count[k] == 0) {
539 					printf("HT mode shouldn't have "
540 						"false negative");
541 					return -1;
542 				}
543 				uint32_t data_idx = j * BURST_SIZE + k;
544 				if (result[k][0] != data[type][data_idx])
545 					false_data_multi_bulk[type][params->cycle]++;
546 			}
547 		}
548 	}
549 
550 	const uint64_t end_tsc = rte_rdtsc();
551 	const uint64_t time_taken = end_tsc - start_tsc;
552 
553 	cycles[type][params->cycle][LOOKUP_MULTI_BULK] = time_taken /
554 							NUM_LOOKUPS;
555 
556 	return 0;
557 }
558 
559 static int
560 timed_deletes(struct member_perf_params *params, int type)
561 {
562 	unsigned int i;
563 	int32_t ret;
564 
565 	if (type == VBF)
566 		return 0;
567 	const uint64_t start_tsc = rte_rdtsc();
568 	for (i = 0; i < KEYS_TO_ADD; i++) {
569 		ret = rte_member_delete(params->setsum[type], &keys[i],
570 					data[type][i]);
571 		if (type != CACHE && ret < 0) {
572 			printf("delete error\n");
573 			return -1;
574 		}
575 	}
576 
577 	const uint64_t end_tsc = rte_rdtsc();
578 	const uint64_t time_taken = end_tsc - start_tsc;
579 
580 	cycles[type][params->cycle][DELETE] = time_taken / KEYS_TO_ADD;
581 
582 	return 0;
583 }
584 
585 static int
586 timed_miss_lookup(struct member_perf_params *params, int type)
587 {
588 	unsigned int i, j;
589 	int ret;
590 
591 	false_hit[type][params->cycle] = 0;
592 
593 	for (i = 0; i < KEYS_TO_ADD / 2; i++) {
594 		ret = rte_member_add(params->setsum[type], &keys[i],
595 					data[type][i]);
596 		if (ret < 0) {
597 			unsigned int a;
598 			printf("Error %d in rte_member_add - key=0x", ret);
599 			for (a = 0; a < params->key_size; a++)
600 				printf("%02x", keys[i][a]);
601 			printf(" value=%d, type: %d\n", data[type][i], type);
602 
603 			return -1;
604 		}
605 	}
606 
607 	const uint64_t start_tsc = rte_rdtsc();
608 	member_set_t result;
609 
610 	for (i = 0; i < 2 * NUM_LOOKUPS / KEYS_TO_ADD; i++) {
611 		for (j = KEYS_TO_ADD / 2; j < KEYS_TO_ADD; j++) {
612 			ret = rte_member_lookup(params->setsum[type], &keys[j],
613 						&result);
614 			if (ret < 0) {
615 				printf("lookup wrong internally");
616 				return -1;
617 			}
618 			if (result != RTE_MEMBER_NO_MATCH)
619 				false_hit[type][params->cycle]++;
620 		}
621 	}
622 
623 	const uint64_t end_tsc = rte_rdtsc();
624 	const uint64_t time_taken = end_tsc - start_tsc;
625 
626 	cycles[type][params->cycle][LOOKUP_MISS] = time_taken / NUM_LOOKUPS;
627 
628 	return 0;
629 }
630 
631 static void
632 perform_frees(struct member_perf_params *params)
633 {
634 	int i;
635 	for (i = 0; i < NUM_TYPE; i++) {
636 		if (params->setsum[i] != NULL) {
637 			rte_member_free(params->setsum[i]);
638 			params->setsum[i] = NULL;
639 		}
640 	}
641 }
642 
643 static int
644 exit_with_fail(const char *testname, struct member_perf_params *params,
645 		unsigned int i, unsigned int j)
646 {
647 	printf("<<<<<Test %s failed at keysize %d iteration %d type %d>>>>>\n",
648 			testname, hashtest_key_lens[params->cycle], i, j);
649 	perform_frees(params);
650 	return -1;
651 }
652 
653 static int
654 run_all_tbl_perf_tests(void)
655 {
656 	unsigned int i, j, k;
657 	struct member_perf_params params;
658 
659 	printf("Measuring performance, please wait\n");
660 	fflush(stdout);
661 
662 	test_socket_id = rte_socket_id();
663 
664 	for (i = 0; i < NUM_KEYSIZES; i++) {
665 		if (setup_keys_and_data(&params, i, 0) < 0) {
666 			printf("Could not create keys/data/table\n");
667 			return -1;
668 		}
669 		for (j = 0; j < SKETCH; j++) {
670 
671 			if (timed_adds(&params, j) < 0)
672 				return exit_with_fail("timed_adds", &params,
673 							i, j);
674 
675 			for (k = 0; k < NUM_SHUFFLES; k++)
676 				shuffle_input_keys(&params);
677 
678 			if (timed_lookups(&params, j) < 0)
679 				return exit_with_fail("timed_lookups", &params,
680 							i, j);
681 
682 			if (timed_lookups_bulk(&params, j) < 0)
683 				return exit_with_fail("timed_lookups_bulk",
684 						&params, i, j);
685 
686 			if (timed_lookups_multimatch(&params, j) < 0)
687 				return exit_with_fail("timed_lookups_multi",
688 						&params, i, j);
689 
690 			if (timed_lookups_multimatch_bulk(&params, j) < 0)
691 				return exit_with_fail("timed_lookups_multi_bulk",
692 							&params, i, j);
693 
694 			if (timed_deletes(&params, j) < 0)
695 				return exit_with_fail("timed_deletes", &params,
696 							i, j);
697 
698 			/* Print a dot to show progress on operations */
699 		}
700 
701 		for (j = SKETCH; j < NUM_TYPE; j++) {
702 			if (timed_adds_sketch(&params, j) < 0)
703 				return exit_with_fail
704 					("timed_adds_sketch", &params, i, j);
705 
706 			if (timed_lookups_sketch(&params, j) < 0)
707 				return exit_with_fail
708 					("timed_lookups_sketch", &params, i, j);
709 		}
710 
711 		printf(".");
712 		fflush(stdout);
713 
714 		perform_frees(&params);
715 	}
716 
717 	/* Test false positive rate using un-inserted keys */
718 	for (i = 0; i < NUM_KEYSIZES; i++) {
719 		if (setup_keys_and_data(&params, i, 1) < 0) {
720 			printf("Could not create keys/data/table\n");
721 			return -1;
722 			}
723 		for (j = 0; j < SKETCH; j++) {
724 			if (timed_miss_lookup(&params, j) < 0)
725 				return exit_with_fail("timed_miss_lookup",
726 						&params, i, j);
727 		}
728 		perform_frees(&params);
729 	}
730 
731 	printf("\nResults (in CPU cycles/operation)\n");
732 	printf("-----------------------------------\n");
733 	printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
734 			"Keysize", "type",  "Add", "Lookup", "Lookup_bulk",
735 			"lookup_multi", "lookup_multi_bulk", "Delete",
736 			"miss_lookup");
737 	for (i = 0; i < NUM_KEYSIZES; i++) {
738 		for (j = 0; j < NUM_TYPE; j++) {
739 			printf("%-18d", hashtest_key_lens[i]);
740 			printf("%-18d", j);
741 			for (k = 0; k < NUM_OPERATIONS; k++)
742 				printf("%-18"PRIu64, cycles[j][i][k]);
743 			printf("\n");
744 		}
745 	}
746 
747 	printf("\nFalse results rate (and false positive rate)\n");
748 	printf("-----------------------------------\n");
749 	printf("\n%-18s%-18s%-18s%-18s%-18s%-18s%-18s\n",
750 			"Keysize", "type",  "fr_single", "fr_bulk", "fr_multi",
751 			"fr_multi_bulk", "false_positive_rate");
752 	/* Key size not influence False rate so just print out one key size */
753 	for (i = 0; i < 1; i++) {
754 		for (j = 0; j < SKETCH; j++) {
755 			printf("%-18d", hashtest_key_lens[i]);
756 			printf("%-18d", j);
757 			printf("%-18f", (float)false_data[j][i] / NUM_LOOKUPS);
758 			printf("%-18f", (float)false_data_bulk[j][i] /
759 						NUM_LOOKUPS);
760 			printf("%-18f", (float)false_data_multi[j][i] /
761 						NUM_LOOKUPS);
762 			printf("%-18f", (float)false_data_multi_bulk[j][i] /
763 						NUM_LOOKUPS);
764 			printf("%-18f", (float)false_hit[j][i] /
765 						NUM_LOOKUPS);
766 			printf("\n");
767 		}
768 	}
769 	return 0;
770 }
771 
772 static int
773 test_member_perf(void)
774 {
775 
776 	if (run_all_tbl_perf_tests() < 0)
777 		return -1;
778 
779 	return 0;
780 }
781 
782 #endif /* !RTE_EXEC_ENV_WINDOWS */
783 
784 REGISTER_TEST_COMMAND(member_perf_autotest, test_member_perf);
785