e746e4708a1f5f1a44adbac14acb1c600a60a384
[dpdk.git] / app / test-compress-perf / main.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <signal.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8
9 #include <rte_malloc.h>
10 #include <rte_eal.h>
11 #include <rte_log.h>
12 #include <rte_compressdev.h>
13
14 #include "comp_perf_options.h"
15 #include "comp_perf_test_verify.h"
16 #include "comp_perf_test_benchmark.h"
17 #include "comp_perf.h"
18 #include "comp_perf_test_common.h"
19
20 #define NUM_MAX_XFORMS 16
21 #define NUM_MAX_INFLIGHT_OPS 512
22
23 __extension__
24 const char *cperf_test_type_strs[] = {
25         [CPERF_TEST_TYPE_BENCHMARK] = "benchmark",
26         [CPERF_TEST_TYPE_VERIFY] = "verify"
27 };
28
29 __extension__
30 static const struct cperf_test cperf_testmap[] = {
31         [CPERF_TEST_TYPE_BENCHMARK] = {
32                         cperf_benchmark_test_constructor,
33                         cperf_benchmark_test_runner,
34                         cperf_benchmark_test_destructor
35         },
36         [CPERF_TEST_TYPE_VERIFY] = {
37                         cperf_verify_test_constructor,
38                         cperf_verify_test_runner,
39                         cperf_verify_test_destructor
40         }
41 };
42
43 static struct comp_test_data *test_data;
44
45 static int
46 comp_perf_check_capabilities(struct comp_test_data *test_data, uint8_t cdev_id)
47 {
48         const struct rte_compressdev_capabilities *cap;
49
50         cap = rte_compressdev_capability_get(cdev_id,
51                                              RTE_COMP_ALGO_DEFLATE);
52
53         if (cap == NULL) {
54                 RTE_LOG(ERR, USER1,
55                         "Compress device does not support DEFLATE\n");
56                 return -1;
57         }
58
59         uint64_t comp_flags = cap->comp_feature_flags;
60
61         /* Huffman enconding */
62         if (test_data->huffman_enc == RTE_COMP_HUFFMAN_FIXED &&
63                         (comp_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0) {
64                 RTE_LOG(ERR, USER1,
65                         "Compress device does not supported Fixed Huffman\n");
66                 return -1;
67         }
68
69         if (test_data->huffman_enc == RTE_COMP_HUFFMAN_DYNAMIC &&
70                         (comp_flags & RTE_COMP_FF_HUFFMAN_DYNAMIC) == 0) {
71                 RTE_LOG(ERR, USER1,
72                         "Compress device does not supported Dynamic Huffman\n");
73                 return -1;
74         }
75
76         /* Window size */
77         if (test_data->window_sz != -1) {
78                 if (param_range_check(test_data->window_sz, &cap->window_size)
79                                 < 0) {
80                         RTE_LOG(ERR, USER1,
81                                 "Compress device does not support "
82                                 "this window size\n");
83                         return -1;
84                 }
85         } else
86                 /* Set window size to PMD maximum if none was specified */
87                 test_data->window_sz = cap->window_size.max;
88
89         /* Check if chained mbufs is supported */
90         if (test_data->max_sgl_segs > 1  &&
91                         (comp_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) == 0) {
92                 RTE_LOG(INFO, USER1, "Compress device does not support "
93                                 "chained mbufs. Max SGL segments set to 1\n");
94                 test_data->max_sgl_segs = 1;
95         }
96
97         /* Level 0 support */
98         if (test_data->level_lst.min == 0 &&
99                         (comp_flags & RTE_COMP_FF_NONCOMPRESSED_BLOCKS) == 0) {
100                 RTE_LOG(ERR, USER1, "Compress device does not support "
101                                 "level 0 (no compression)\n");
102                 return -1;
103         }
104
105         return 0;
106 }
107
108 static int
109 comp_perf_initialize_compressdev(struct comp_test_data *test_data,
110                                  uint8_t *enabled_cdevs)
111 {
112         uint8_t enabled_cdev_count, nb_lcores, cdev_id;
113         unsigned int i, j;
114         int ret;
115
116         enabled_cdev_count = rte_compressdev_devices_get(test_data->driver_name,
117                         enabled_cdevs, RTE_COMPRESS_MAX_DEVS);
118         if (enabled_cdev_count == 0) {
119                 RTE_LOG(ERR, USER1, "No compress devices type %s available\n",
120                                 test_data->driver_name);
121                 return -EINVAL;
122         }
123
124         nb_lcores = rte_lcore_count() - 1;
125         /*
126          * Use fewer devices,
127          * if there are more available than cores.
128          */
129         if (enabled_cdev_count > nb_lcores) {
130                 enabled_cdev_count = nb_lcores;
131                 RTE_LOG(INFO, USER1,
132                         " There's more available devices than cores!"
133                         " The number of devices has been aligned to %d cores\n",
134                         nb_lcores);
135         }
136
137         /*
138          * Calculate number of needed queue pairs, based on the amount
139          * of available number of logical cores and compression devices.
140          * For instance, if there are 4 cores and 2 compression devices,
141          * 2 queue pairs will be set up per device.
142          * One queue pair per one core.
143          * if e.g.: there're 3 cores and 2 compression devices,
144          * 2 queue pairs will be set up per device but one queue pair
145          * will left unused in the last one device
146          */
147         test_data->nb_qps = (nb_lcores % enabled_cdev_count) ?
148                                 (nb_lcores / enabled_cdev_count) + 1 :
149                                 nb_lcores / enabled_cdev_count;
150
151         for (i = 0; i < enabled_cdev_count &&
152                         i < RTE_COMPRESS_MAX_DEVS; i++,
153                                         nb_lcores -= test_data->nb_qps) {
154                 cdev_id = enabled_cdevs[i];
155
156                 struct rte_compressdev_info cdev_info;
157                 uint8_t socket_id = rte_compressdev_socket_id(cdev_id);
158
159                 rte_compressdev_info_get(cdev_id, &cdev_info);
160                 if (cdev_info.max_nb_queue_pairs &&
161                         test_data->nb_qps > cdev_info.max_nb_queue_pairs) {
162                         RTE_LOG(ERR, USER1,
163                                 "Number of needed queue pairs is higher "
164                                 "than the maximum number of queue pairs "
165                                 "per device.\n");
166                         RTE_LOG(ERR, USER1,
167                                 "Lower the number of cores or increase "
168                                 "the number of crypto devices\n");
169                         return -EINVAL;
170                 }
171
172                 if (comp_perf_check_capabilities(test_data, cdev_id) < 0)
173                         return -EINVAL;
174
175                 /* Configure compressdev */
176                 struct rte_compressdev_config config = {
177                         .socket_id = socket_id,
178                         .nb_queue_pairs = nb_lcores > test_data->nb_qps
179                                         ? test_data->nb_qps : nb_lcores,
180                         .max_nb_priv_xforms = NUM_MAX_XFORMS,
181                         .max_nb_streams = 0
182                 };
183
184                 if (rte_compressdev_configure(cdev_id, &config) < 0) {
185                         RTE_LOG(ERR, USER1, "Device configuration failed\n");
186                         return -EINVAL;
187                 }
188
189                 for (j = 0; j < test_data->nb_qps; j++) {
190                         ret = rte_compressdev_queue_pair_setup(cdev_id, j,
191                                         NUM_MAX_INFLIGHT_OPS, socket_id);
192                         if (ret < 0) {
193                                 RTE_LOG(ERR, USER1,
194                               "Failed to setup queue pair %u on compressdev %u",
195                                         j, cdev_id);
196                                 return -EINVAL;
197                         }
198                 }
199
200                 ret = rte_compressdev_start(cdev_id);
201                 if (ret < 0) {
202                         RTE_LOG(ERR, USER1,
203                                 "Failed to start device %u: error %d\n",
204                                 cdev_id, ret);
205                         return -EPERM;
206                 }
207         }
208
209         return enabled_cdev_count;
210 }
211
212 static int
213 comp_perf_dump_input_data(struct comp_test_data *test_data)
214 {
215         FILE *f = fopen(test_data->input_file, "r");
216         int ret = -1;
217
218         if (f == NULL) {
219                 RTE_LOG(ERR, USER1, "Input file could not be opened\n");
220                 return -1;
221         }
222
223         if (fseek(f, 0, SEEK_END) != 0) {
224                 RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
225                 goto end;
226         }
227         size_t actual_file_sz = ftell(f);
228         /* If extended input data size has not been set,
229          * input data size = file size
230          */
231
232         if (test_data->input_data_sz == 0)
233                 test_data->input_data_sz = actual_file_sz;
234
235         if (test_data->input_data_sz <= 0 || actual_file_sz <= 0 ||
236                         fseek(f, 0, SEEK_SET) != 0) {
237                 RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
238                 goto end;
239         }
240
241         test_data->input_data = rte_zmalloc_socket(NULL,
242                                 test_data->input_data_sz, 0, rte_socket_id());
243
244         if (test_data->input_data == NULL) {
245                 RTE_LOG(ERR, USER1, "Memory to hold the data from the input "
246                                 "file could not be allocated\n");
247                 goto end;
248         }
249
250         size_t remaining_data = test_data->input_data_sz;
251         uint8_t *data = test_data->input_data;
252
253         while (remaining_data > 0) {
254                 size_t data_to_read = RTE_MIN(remaining_data, actual_file_sz);
255
256                 if (fread(data, data_to_read, 1, f) != 1) {
257                         RTE_LOG(ERR, USER1, "Input file could not be read\n");
258                         goto end;
259                 }
260                 if (fseek(f, 0, SEEK_SET) != 0) {
261                         RTE_LOG(ERR, USER1,
262                                 "Size of input could not be calculated\n");
263                         goto end;
264                 }
265                 remaining_data -= data_to_read;
266                 data += data_to_read;
267         }
268
269         if (test_data->input_data_sz > actual_file_sz)
270                 RTE_LOG(INFO, USER1,
271                   "%zu bytes read from file %s, extending the file %.2f times\n",
272                         test_data->input_data_sz, test_data->input_file,
273                         (double)test_data->input_data_sz/actual_file_sz);
274         else
275                 RTE_LOG(INFO, USER1,
276                         "%zu bytes read from file %s\n",
277                         test_data->input_data_sz, test_data->input_file);
278
279         ret = 0;
280
281 end:
282         fclose(f);
283         return ret;
284 }
285
286 static void
287 comp_perf_cleanup_on_signal(int signalNumber __rte_unused)
288 {
289         test_data->perf_comp_force_stop = 1;
290 }
291
292 static void
293 comp_perf_register_cleanup_on_signal(void)
294 {
295         signal(SIGTERM, comp_perf_cleanup_on_signal);
296         signal(SIGINT, comp_perf_cleanup_on_signal);
297 }
298
299 int
300 main(int argc, char **argv)
301 {
302         uint8_t level_idx = 0;
303         int ret, i;
304         void *ctx[RTE_MAX_LCORE] = {};
305         uint8_t enabled_cdevs[RTE_COMPRESS_MAX_DEVS];
306         int nb_compressdevs = 0;
307         uint16_t total_nb_qps = 0;
308         uint8_t cdev_id;
309         uint32_t lcore_id;
310
311         /* Initialise DPDK EAL */
312         ret = rte_eal_init(argc, argv);
313         if (ret < 0)
314                 rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
315         argc -= ret;
316         argv += ret;
317
318         test_data = rte_zmalloc_socket(NULL, sizeof(struct comp_test_data),
319                                         0, rte_socket_id());
320
321         if (test_data == NULL)
322                 rte_exit(EXIT_FAILURE, "Cannot reserve memory in socket %d\n",
323                                 rte_socket_id());
324
325         comp_perf_register_cleanup_on_signal();
326
327         ret = EXIT_SUCCESS;
328         test_data->cleanup = ST_TEST_DATA;
329         comp_perf_options_default(test_data);
330
331         if (comp_perf_options_parse(test_data, argc, argv) < 0) {
332                 RTE_LOG(ERR, USER1,
333                         "Parsing one or more user options failed\n");
334                 ret = EXIT_FAILURE;
335                 goto end;
336         }
337
338         if (comp_perf_options_check(test_data) < 0) {
339                 ret = EXIT_FAILURE;
340                 goto end;
341         }
342
343         nb_compressdevs =
344                 comp_perf_initialize_compressdev(test_data, enabled_cdevs);
345
346         if (nb_compressdevs < 1) {
347                 ret = EXIT_FAILURE;
348                 goto end;
349         }
350
351         test_data->cleanup = ST_COMPDEV;
352         if (comp_perf_dump_input_data(test_data) < 0) {
353                 ret = EXIT_FAILURE;
354                 goto end;
355         }
356
357         test_data->cleanup = ST_INPUT_DATA;
358
359         if (test_data->level_lst.inc != 0)
360                 test_data->level = test_data->level_lst.min;
361         else
362                 test_data->level = test_data->level_lst.list[0];
363
364         printf("App uses socket: %u\n", rte_socket_id());
365         printf("Burst size = %u\n", test_data->burst_sz);
366         printf("File size = %zu\n", test_data->input_data_sz);
367
368         test_data->cleanup = ST_DURING_TEST;
369         total_nb_qps = nb_compressdevs * test_data->nb_qps;
370
371         i = 0;
372         uint8_t qp_id = 0, cdev_index = 0;
373
374         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
375
376                 if (i == total_nb_qps)
377                         break;
378
379                 cdev_id = enabled_cdevs[cdev_index];
380                 ctx[i] = cperf_testmap[test_data->test].constructor(
381                                                         cdev_id, qp_id,
382                                                         test_data);
383                 if (ctx[i] == NULL) {
384                         RTE_LOG(ERR, USER1, "Test run constructor failed\n");
385                         goto end;
386                 }
387                 qp_id = (qp_id + 1) % test_data->nb_qps;
388                 if (qp_id == 0)
389                         cdev_index++;
390                 i++;
391         }
392
393         while (test_data->level <= test_data->level_lst.max) {
394
395                 i = 0;
396                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
397
398                         if (i == total_nb_qps)
399                                 break;
400
401                         rte_eal_remote_launch(
402                                         cperf_testmap[test_data->test].runner,
403                                         ctx[i], lcore_id);
404                         i++;
405                 }
406                 i = 0;
407                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
408
409                         if (i == total_nb_qps)
410                                 break;
411                         ret |= rte_eal_wait_lcore(lcore_id);
412                         i++;
413                 }
414
415                 if (ret != EXIT_SUCCESS)
416                         break;
417
418                 if (test_data->level_lst.inc != 0)
419                         test_data->level += test_data->level_lst.inc;
420                 else {
421                         if (++level_idx == test_data->level_lst.count)
422                                 break;
423                         test_data->level = test_data->level_lst.list[level_idx];
424                 }
425         }
426
427 end:
428         switch (test_data->cleanup) {
429
430         case ST_DURING_TEST:
431                 i = 0;
432                 RTE_LCORE_FOREACH_SLAVE(lcore_id) {
433                         if (i == total_nb_qps)
434                                 break;
435
436                         if (ctx[i] && cperf_testmap[test_data->test].destructor)
437                                 cperf_testmap[test_data->test].destructor(
438                                                                         ctx[i]);
439                         i++;
440                 }
441                 /* fallthrough */
442         case ST_INPUT_DATA:
443                 rte_free(test_data->input_data);
444                 /* fallthrough */
445         case ST_COMPDEV:
446                 for (i = 0; i < nb_compressdevs &&
447                      i < RTE_COMPRESS_MAX_DEVS; i++) {
448                         rte_compressdev_stop(enabled_cdevs[i]);
449                         rte_compressdev_close(enabled_cdevs[i]);
450                 }
451                 /* fallthrough */
452         case ST_TEST_DATA:
453                 rte_free(test_data);
454                 /* fallthrough */
455         case ST_CLEAR:
456         default:
457                 i = rte_eal_cleanup();
458                 if (i) {
459                         RTE_LOG(ERR, USER1,
460                                 "Error from rte_eal_cleanup(), %d\n", i);
461                         ret = i;
462                 }
463                 break;
464         }
465         return ret;
466 }
467
468 __rte_weak void *
469 cperf_benchmark_test_constructor(uint8_t dev_id __rte_unused,
470                                  uint16_t qp_id __rte_unused,
471                                  struct comp_test_data *options __rte_unused)
472 {
473         RTE_LOG(INFO, USER1, "Benchmark test is not supported yet\n");
474         return NULL;
475 }
476
477 __rte_weak void
478 cperf_benchmark_test_destructor(void *arg __rte_unused)
479 {
480
481 }
482
483 __rte_weak int
484 cperf_benchmark_test_runner(void *test_ctx __rte_unused)
485 {
486         return 0;
487 }
488 __rte_weak void *
489 cperf_verify_test_constructor(uint8_t dev_id __rte_unused,
490                                  uint16_t qp_id __rte_unused,
491                                  struct comp_test_data *options __rte_unused)
492 {
493         RTE_LOG(INFO, USER1, "Verify test is not supported yet\n");
494         return NULL;
495 }
496
497 __rte_weak void
498 cperf_verify_test_destructor(void *arg __rte_unused)
499 {
500
501 }
502
503 __rte_weak int
504 cperf_verify_test_runner(void *test_ctx __rte_unused)
505 {
506         return 0;
507 }