numam-dpdk/app/test-compress-perf/main.c
Artur Trybula 6f1e5d809a app/compress-perf: improve results report
This patch adds extra features to the compress performance
test. Some important parameters (memory allocation,
number of ops, number of segments) are calculated and
printed out.
Information about threads, cores, devices and queue-pairs
is also printed.

Signed-off-by: Artur Trybula <arturx.trybula@intel.com>
Signed-off-by: Adam Dybkowski <adamx.dybkowski@intel.com>
Acked-by: Fiona Trahe <fiona.trahe@intel.com>
2019-07-26 12:03:51 +02:00

510 lines
12 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2018 Intel Corporation
*/
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <rte_malloc.h>
#include <rte_eal.h>
#include <rte_log.h>
#include <rte_compressdev.h>
#include "comp_perf_options.h"
#include "comp_perf_test_verify.h"
#include "comp_perf_test_benchmark.h"
#include "comp_perf.h"
#include "comp_perf_test_common.h"
#define NUM_MAX_XFORMS 16
#define NUM_MAX_INFLIGHT_OPS 512
__extension__
const char *cperf_test_type_strs[] = {
[CPERF_TEST_TYPE_BENCHMARK] = "benchmark",
[CPERF_TEST_TYPE_VERIFY] = "verify"
};
__extension__
static const struct cperf_test cperf_testmap[] = {
[CPERF_TEST_TYPE_BENCHMARK] = {
cperf_benchmark_test_constructor,
cperf_benchmark_test_runner,
cperf_benchmark_test_destructor
},
[CPERF_TEST_TYPE_VERIFY] = {
cperf_verify_test_constructor,
cperf_verify_test_runner,
cperf_verify_test_destructor
}
};
static struct comp_test_data *test_data;
static int
comp_perf_check_capabilities(struct comp_test_data *test_data, uint8_t cdev_id)
{
const struct rte_compressdev_capabilities *cap;
cap = rte_compressdev_capability_get(cdev_id,
RTE_COMP_ALGO_DEFLATE);
if (cap == NULL) {
RTE_LOG(ERR, USER1,
"Compress device does not support DEFLATE\n");
return -1;
}
uint64_t comp_flags = cap->comp_feature_flags;
/* Huffman enconding */
if (test_data->huffman_enc == RTE_COMP_HUFFMAN_FIXED &&
(comp_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0) {
RTE_LOG(ERR, USER1,
"Compress device does not supported Fixed Huffman\n");
return -1;
}
if (test_data->huffman_enc == RTE_COMP_HUFFMAN_DYNAMIC &&
(comp_flags & RTE_COMP_FF_HUFFMAN_DYNAMIC) == 0) {
RTE_LOG(ERR, USER1,
"Compress device does not supported Dynamic Huffman\n");
return -1;
}
/* Window size */
if (test_data->window_sz != -1) {
if (param_range_check(test_data->window_sz, &cap->window_size)
< 0) {
RTE_LOG(ERR, USER1,
"Compress device does not support "
"this window size\n");
return -1;
}
} else
/* Set window size to PMD maximum if none was specified */
test_data->window_sz = cap->window_size.max;
/* Check if chained mbufs is supported */
if (test_data->max_sgl_segs > 1 &&
(comp_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) == 0) {
RTE_LOG(INFO, USER1, "Compress device does not support "
"chained mbufs. Max SGL segments set to 1\n");
test_data->max_sgl_segs = 1;
}
/* Level 0 support */
if (test_data->level_lst.min == 0 &&
(comp_flags & RTE_COMP_FF_NONCOMPRESSED_BLOCKS) == 0) {
RTE_LOG(ERR, USER1, "Compress device does not support "
"level 0 (no compression)\n");
return -1;
}
return 0;
}
static int
comp_perf_initialize_compressdev(struct comp_test_data *test_data,
uint8_t *enabled_cdevs)
{
uint8_t enabled_cdev_count, nb_lcores, cdev_id;
unsigned int i, j;
int ret;
enabled_cdev_count = rte_compressdev_devices_get(test_data->driver_name,
enabled_cdevs, RTE_COMPRESS_MAX_DEVS);
if (enabled_cdev_count == 0) {
RTE_LOG(ERR, USER1, "No compress devices type %s available\n",
test_data->driver_name);
return -EINVAL;
}
nb_lcores = rte_lcore_count() - 1;
/*
* Use fewer devices,
* if there are more available than cores.
*/
if (enabled_cdev_count > nb_lcores) {
enabled_cdev_count = nb_lcores;
RTE_LOG(INFO, USER1,
" There's more available devices than cores!"
" The number of devices has been aligned to %d cores\n",
nb_lcores);
}
/*
* Calculate number of needed queue pairs, based on the amount
* of available number of logical cores and compression devices.
* For instance, if there are 4 cores and 2 compression devices,
* 2 queue pairs will be set up per device.
* One queue pair per one core.
* if e.g.: there're 3 cores and 2 compression devices,
* 2 queue pairs will be set up per device but one queue pair
* will left unused in the last one device
*/
test_data->nb_qps = (nb_lcores % enabled_cdev_count) ?
(nb_lcores / enabled_cdev_count) + 1 :
nb_lcores / enabled_cdev_count;
for (i = 0; i < enabled_cdev_count &&
i < RTE_COMPRESS_MAX_DEVS; i++,
nb_lcores -= test_data->nb_qps) {
cdev_id = enabled_cdevs[i];
struct rte_compressdev_info cdev_info;
uint8_t socket_id = rte_compressdev_socket_id(cdev_id);
rte_compressdev_info_get(cdev_id, &cdev_info);
if (cdev_info.max_nb_queue_pairs &&
test_data->nb_qps > cdev_info.max_nb_queue_pairs) {
RTE_LOG(ERR, USER1,
"Number of needed queue pairs is higher "
"than the maximum number of queue pairs "
"per device.\n");
RTE_LOG(ERR, USER1,
"Lower the number of cores or increase "
"the number of crypto devices\n");
return -EINVAL;
}
if (comp_perf_check_capabilities(test_data, cdev_id) < 0)
return -EINVAL;
/* Configure compressdev */
struct rte_compressdev_config config = {
.socket_id = socket_id,
.nb_queue_pairs = nb_lcores > test_data->nb_qps
? test_data->nb_qps : nb_lcores,
.max_nb_priv_xforms = NUM_MAX_XFORMS,
.max_nb_streams = 0
};
if (rte_compressdev_configure(cdev_id, &config) < 0) {
RTE_LOG(ERR, USER1, "Device configuration failed\n");
return -EINVAL;
}
for (j = 0; j < test_data->nb_qps; j++) {
ret = rte_compressdev_queue_pair_setup(cdev_id, j,
NUM_MAX_INFLIGHT_OPS, socket_id);
if (ret < 0) {
RTE_LOG(ERR, USER1,
"Failed to setup queue pair %u on compressdev %u",
j, cdev_id);
return -EINVAL;
}
}
ret = rte_compressdev_start(cdev_id);
if (ret < 0) {
RTE_LOG(ERR, USER1,
"Failed to start device %u: error %d\n",
cdev_id, ret);
return -EPERM;
}
}
return enabled_cdev_count;
}
static int
comp_perf_dump_input_data(struct comp_test_data *test_data)
{
FILE *f = fopen(test_data->input_file, "r");
int ret = -1;
if (f == NULL) {
RTE_LOG(ERR, USER1, "Input file could not be opened\n");
return -1;
}
if (fseek(f, 0, SEEK_END) != 0) {
RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
goto end;
}
size_t actual_file_sz = ftell(f);
/* If extended input data size has not been set,
* input data size = file size
*/
if (test_data->input_data_sz == 0)
test_data->input_data_sz = actual_file_sz;
if (test_data->input_data_sz <= 0 || actual_file_sz <= 0 ||
fseek(f, 0, SEEK_SET) != 0) {
RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
goto end;
}
test_data->input_data = rte_zmalloc_socket(NULL,
test_data->input_data_sz, 0, rte_socket_id());
if (test_data->input_data == NULL) {
RTE_LOG(ERR, USER1, "Memory to hold the data from the input "
"file could not be allocated\n");
goto end;
}
size_t remaining_data = test_data->input_data_sz;
uint8_t *data = test_data->input_data;
while (remaining_data > 0) {
size_t data_to_read = RTE_MIN(remaining_data, actual_file_sz);
if (fread(data, data_to_read, 1, f) != 1) {
RTE_LOG(ERR, USER1, "Input file could not be read\n");
goto end;
}
if (fseek(f, 0, SEEK_SET) != 0) {
RTE_LOG(ERR, USER1,
"Size of input could not be calculated\n");
goto end;
}
remaining_data -= data_to_read;
data += data_to_read;
}
if (test_data->input_data_sz > actual_file_sz)
RTE_LOG(INFO, USER1,
"%zu bytes read from file %s, extending the file %.2f times\n",
test_data->input_data_sz, test_data->input_file,
(double)test_data->input_data_sz/actual_file_sz);
else
RTE_LOG(INFO, USER1,
"%zu bytes read from file %s\n",
test_data->input_data_sz, test_data->input_file);
ret = 0;
end:
fclose(f);
return ret;
}
static void
comp_perf_cleanup_on_signal(int signalNumber __rte_unused)
{
test_data->perf_comp_force_stop = 1;
}
static void
comp_perf_register_cleanup_on_signal(void)
{
signal(SIGTERM, comp_perf_cleanup_on_signal);
signal(SIGINT, comp_perf_cleanup_on_signal);
}
int
main(int argc, char **argv)
{
uint8_t level_idx = 0;
int ret, i;
void *ctx[RTE_MAX_LCORE] = {};
uint8_t enabled_cdevs[RTE_COMPRESS_MAX_DEVS];
int nb_compressdevs = 0;
uint16_t total_nb_qps = 0;
uint8_t cdev_id;
uint32_t lcore_id;
/* Initialise DPDK EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
argc -= ret;
argv += ret;
test_data = rte_zmalloc_socket(NULL, sizeof(struct comp_test_data),
0, rte_socket_id());
if (test_data == NULL)
rte_exit(EXIT_FAILURE, "Cannot reserve memory in socket %d\n",
rte_socket_id());
comp_perf_register_cleanup_on_signal();
ret = EXIT_SUCCESS;
test_data->cleanup = ST_TEST_DATA;
comp_perf_options_default(test_data);
if (comp_perf_options_parse(test_data, argc, argv) < 0) {
RTE_LOG(ERR, USER1,
"Parsing one or more user options failed\n");
ret = EXIT_FAILURE;
goto end;
}
if (comp_perf_options_check(test_data) < 0) {
ret = EXIT_FAILURE;
goto end;
}
nb_compressdevs =
comp_perf_initialize_compressdev(test_data, enabled_cdevs);
if (nb_compressdevs < 1) {
ret = EXIT_FAILURE;
goto end;
}
test_data->cleanup = ST_COMPDEV;
if (comp_perf_dump_input_data(test_data) < 0) {
ret = EXIT_FAILURE;
goto end;
}
test_data->cleanup = ST_INPUT_DATA;
if (test_data->level_lst.inc != 0)
test_data->level = test_data->level_lst.min;
else
test_data->level = test_data->level_lst.list[0];
printf("App uses socket: %u\n", rte_socket_id());
printf("Burst size = %u\n", test_data->burst_sz);
printf("Input data size = %zu\n", test_data->input_data_sz);
test_data->cleanup = ST_DURING_TEST;
total_nb_qps = nb_compressdevs * test_data->nb_qps;
i = 0;
uint8_t qp_id = 0, cdev_index = 0;
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (i == total_nb_qps)
break;
cdev_id = enabled_cdevs[cdev_index];
ctx[i] = cperf_testmap[test_data->test].constructor(
cdev_id, qp_id,
test_data);
if (ctx[i] == NULL) {
RTE_LOG(ERR, USER1, "Test run constructor failed\n");
goto end;
}
qp_id = (qp_id + 1) % test_data->nb_qps;
if (qp_id == 0)
cdev_index++;
i++;
}
print_test_dynamics(); /* constructors must be executed first */
while (test_data->level <= test_data->level_lst.max) {
i = 0;
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (i == total_nb_qps)
break;
rte_eal_remote_launch(
cperf_testmap[test_data->test].runner,
ctx[i], lcore_id);
i++;
}
i = 0;
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (i == total_nb_qps)
break;
ret |= rte_eal_wait_lcore(lcore_id);
i++;
}
if (ret != EXIT_SUCCESS)
break;
if (test_data->level_lst.inc != 0)
test_data->level += test_data->level_lst.inc;
else {
if (++level_idx == test_data->level_lst.count)
break;
test_data->level = test_data->level_lst.list[level_idx];
}
}
end:
switch (test_data->cleanup) {
case ST_DURING_TEST:
i = 0;
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
if (i == total_nb_qps)
break;
if (ctx[i] && cperf_testmap[test_data->test].destructor)
cperf_testmap[test_data->test].destructor(
ctx[i]);
i++;
}
/* fallthrough */
case ST_INPUT_DATA:
rte_free(test_data->input_data);
/* fallthrough */
case ST_COMPDEV:
for (i = 0; i < nb_compressdevs &&
i < RTE_COMPRESS_MAX_DEVS; i++) {
rte_compressdev_stop(enabled_cdevs[i]);
rte_compressdev_close(enabled_cdevs[i]);
}
/* fallthrough */
case ST_TEST_DATA:
rte_free(test_data);
/* fallthrough */
case ST_CLEAR:
default:
i = rte_eal_cleanup();
if (i) {
RTE_LOG(ERR, USER1,
"Error from rte_eal_cleanup(), %d\n", i);
ret = i;
}
break;
}
return ret;
}
__rte_weak void *
cperf_benchmark_test_constructor(uint8_t dev_id __rte_unused,
uint16_t qp_id __rte_unused,
struct comp_test_data *options __rte_unused)
{
RTE_LOG(INFO, USER1, "Benchmark test is not supported yet\n");
return NULL;
}
__rte_weak void
cperf_benchmark_test_destructor(void *arg __rte_unused)
{
}
__rte_weak int
cperf_benchmark_test_runner(void *test_ctx __rte_unused)
{
return 0;
}
__rte_weak void *
cperf_verify_test_constructor(uint8_t dev_id __rte_unused,
uint16_t qp_id __rte_unused,
struct comp_test_data *options __rte_unused)
{
RTE_LOG(INFO, USER1, "Verify test is not supported yet\n");
return NULL;
}
__rte_weak void
cperf_verify_test_destructor(void *arg __rte_unused)
{
}
__rte_weak int
cperf_verify_test_runner(void *test_ctx __rte_unused)
{
return 0;
}