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