test/event: add asymmetric cases for crypto adapter
[dpdk.git] / app / test / test_efd_perf.c
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(&params, i) < 0) {
346                         printf("Could not create keys/data/table\n");
347                         return -1;
348                 }
349
350                 if (timed_adds(&params) < 0)
351                         return exit_with_fail("timed_adds", &params, i);
352
353                 for (j = 0; j < NUM_SHUFFLES; j++)
354                         shuffle_input_keys(&params);
355
356                 if (timed_lookups(&params) < 0)
357                         return exit_with_fail("timed_lookups", &params, i);
358
359                 if (timed_lookups_multi(&params) < 0)
360                         return exit_with_fail("timed_lookups_multi", &params, i);
361
362                 if (timed_deletes(&params) < 0)
363                         return exit_with_fail("timed_deletes", &params, i);
364
365                 /* Print a dot to show progress on operations */
366                 printf(".");
367                 fflush(stdout);
368
369                 perform_frees(&params);
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);