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