From: Hao Fang fanghao11@huawei.com
Now the uadk_tool is the unified test tool but comp test is still in the test/hisi_zip_test, and out of maintained for a long time.
Change the directory is the first step for refactoring the test tool.
Use this cmd for help: uadk_tool test --m zip --help
Signed-off-by: Hao Fang fanghao11@huawei.com Signed-off-by: Qi Tao taoqi10@huawei.com --- uadk_tool/Makefile.am | 11 +- uadk_tool/test/comp_lib.c | 1871 ++++++++++++++++++++++++++++++++++++ uadk_tool/test/comp_lib.h | 352 +++++++ uadk_tool/test/comp_main.c | 1843 +++++++++++++++++++++++++++++++++++ uadk_tool/test/comp_main.h | 9 + uadk_tool/test/uadk_test.c | 8 +- 6 files changed, 4087 insertions(+), 7 deletions(-) create mode 100644 uadk_tool/test/comp_lib.c create mode 100644 uadk_tool/test/comp_lib.h create mode 100644 uadk_tool/test/comp_main.c create mode 100644 uadk_tool/test/comp_main.h
diff --git a/uadk_tool/Makefile.am b/uadk_tool/Makefile.am index 6fa0d9d..5e8d4c5 100644 --- a/uadk_tool/Makefile.am +++ b/uadk_tool/Makefile.am @@ -19,7 +19,8 @@ uadk_tool_SOURCES=uadk_tool.c dfx/uadk_dfx.c dfx/uadk_dfx.h \ benchmark/zip_wd_benchmark.c benchmark/zip_wd_benchmark.h \ benchmark/trng_wd_benchmark.c benchmark/trng_wd_benchmark.h \ test/uadk_test.c test/uadk_test.h \ - test/test_sec.c test/test_sec.h test/sec_template_tv.h + test/test_sec.c test/test_sec.h test/sec_template_tv.h \ + test/comp_main.c test/comp_main.h test/comp_lib.c test/comp_lib.h
if WD_STATIC_DRV AM_CFLAGS+=-Bstatic @@ -36,6 +37,14 @@ uadk_tool_LDADD=-L../.libs -l:libwd.so.2 -l:libwd_crypto.so.2 \ -l:libwd_comp.so.2 -lnuma endif
+# For statistics +uadk_tool_LDADD+=-lm + +if HAVE_ZLIB +uadk_tool_LDADD+=-lz +uadk_tool_CPPFLAGS=-DUSE_ZLIB +endif + if WITH_ZLIB_FSE_DIR AM_CFLAGS += -DZLIB_FSE uadk_tool_LDADD+= $(with_zlib_fse_dir)/libfse.a diff --git a/uadk_tool/test/comp_lib.c b/uadk_tool/test/comp_lib.c new file mode 100644 index 0000000..4009295 --- /dev/null +++ b/uadk_tool/test/comp_lib.c @@ -0,0 +1,1871 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved. + * Copyright 2020-2021 Linaro ltd. + */ + +#include <pthread.h> +#include <signal.h> +#include <math.h> +#include <sys/mman.h> +#include <zlib.h> + +#include "comp_lib.h" + +#define SCHED_RR_NAME "sched_rr" + +struct check_rand_ctx { + int off; + unsigned long global_off; + __u32 last; + unsigned short state[3]; +}; + +#define dbg(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__) + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_spinlock_t lock; +static int count = 0; + +static struct wd_ctx_config *g_conf; + +int sum_pend = 0, sum_thread_end = 0; + +__attribute__((constructor)) +void lock_constructor(void) +{ + if (pthread_spin_init(&lock, PTHREAD_PROCESS_SHARED) != 0) + exit(1); +} + +__attribute__((destructor)) +void lock_destructor(void) +{ + if (pthread_spin_destroy(&lock) != 0) + exit(1); +} + +void *mmap_alloc(size_t len) +{ + void *p; + long page_size = sysconf(_SC_PAGESIZE); + + if (len % page_size) + return malloc(len); + + p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (p == MAP_FAILED) + WD_ERR("Failed to allocate %zu bytes\n", len); + + return p == MAP_FAILED ? NULL : p; +} + +int mmap_free(void *addr, size_t len) +{ + long page_size = sysconf(_SC_PAGESIZE); + + if (len % page_size) { + free(addr); + return 0; + } + + return munmap(addr, len); +} + +static int hizip_check_rand(unsigned char *buf, unsigned int size, void *opaque) +{ + int i; + int *j; + __u32 n; + struct check_rand_ctx *rand_ctx = opaque; + + j = &rand_ctx->off; + for (i = 0; i < size; i += 4) { + if (*j) { + /* Something left from a previous run */ + n = rand_ctx->last; + } else { + n = nrand48(rand_ctx->state); + rand_ctx->last = n; + } + for (; *j < 4 && i + *j < size; (*j)++) { + char expected = (n >> (8 * *j)) & 0xff; + char actual = buf[i + *j]; + + if (expected != actual) { + WD_ERR("Invalid decompressed char at offset %lu: expected 0x%x != 0x%x\n", + rand_ctx->global_off + i + *j, expected, + actual); + return -EINVAL; + } + } + if (*j == 4) + *j = 0; + } + rand_ctx->global_off += size; + return 0; +} + +static struct wd_datalist *get_datalist(void *addr, __u32 size) +{ + int count = (int)ceil((double)size / SGE_SIZE); + struct wd_datalist *head, *cur, *tmp; + int i; + + head = calloc(1, sizeof(struct wd_datalist)); + if (!head) { + WD_ERR("failed to alloc datalist head\n"); + return NULL; + } + + cur = head; + + for (i = 0; i < count; i++) { + cur->data = addr; + cur->len = (size > SGE_SIZE) ? SGE_SIZE : size; + addr += SGE_SIZE; + size -= SGE_SIZE; + if (i != count - 1) { + tmp = calloc(1, sizeof(struct wd_datalist)); + cur->next = tmp; + cur = tmp; + } + } + + return head; +} + +/** + * compress() - compress memory buffer. + * @alg_type: alg_type. + * + * This function compress memory buffer. + */ +int hw_blk_compress(int alg_type, int blksize, __u8 data_fmt, void *priv, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen) +{ + handle_t h_sess; + struct wd_comp_sess_setup setup; + struct sched_params param = {0}; + struct wd_datalist *list; + struct wd_comp_req req; + int ret = 0; + + setup.alg_type = alg_type; + setup.op_type = WD_DIR_COMPRESS; + setup.comp_lv = WD_COMP_L8; + setup.win_sz = WD_COMP_WS_8K; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) { + fprintf(stderr,"fail to alloc comp sess!\n"); + return -EINVAL; + } + + if (data_fmt) { + WD_ERR("now sge size is %u\n", SGE_SIZE); + list = get_datalist(src, (__u32)srclen); + req.list_src = list; + list = get_datalist(dst, (__u32)*dstlen); + req.list_dst = list; + } else { + req.src = src; + req.dst = dst; + } + + req.src_len = srclen; + req.dst_len = *dstlen; + req.op_type = WD_DIR_COMPRESS; + req.cb = NULL; + req.data_fmt = data_fmt; + req.priv = priv; + + dbg("%s:input req: src_len: %d, dst_len:%d, data_fmt:%d\n", + __func__, req.src_len, req.dst_len, req.data_fmt); + + ret = wd_do_comp_sync(h_sess, &req); + if (ret < 0) { + fprintf(stderr,"fail to do comp sync(ret = %d)!\n", ret); + return ret; + } + + if (req.status) { + fprintf(stderr,"fail to do comp sync(status = %d)!\n", + req.status); + wd_comp_free_sess(h_sess); + return req.status; + } + *dstlen = req.dst_len; + + dbg("%s:input req: src_len: %d, dst_len:%d, data_fmt:%d\n", + __func__, req.src_len, req.dst_len, req.data_fmt); + + wd_comp_free_sess(h_sess); + + return ret; +} + +int hw_blk_decompress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen) +{ + handle_t h_sess; + struct wd_comp_sess_setup setup; + struct sched_params param = {0}; + struct wd_datalist *list; + struct wd_comp_req req; + int ret = 0; + + setup.alg_type = alg_type; + setup.op_type = WD_DIR_DECOMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) { + fprintf(stderr,"fail to alloc comp sess!\n"); + return -EINVAL; + } + + if (data_fmt) { + WD_ERR("now sge size is %u\n", SGE_SIZE); + list = get_datalist(src, (__u32)srclen); + req.list_src = list; + list = get_datalist(dst, (__u32)*dstlen); + req.list_dst = list; + } else { + req.src = src; + req.dst = dst; + } + + req.src_len = srclen; + req.dst_len = *dstlen; + req.op_type = WD_DIR_DECOMPRESS; + req.cb = NULL; + req.data_fmt = data_fmt; + + dbg("%s:input req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + + ret = wd_do_comp_sync(h_sess, &req); + if (ret < 0) { + fprintf(stderr,"fail to do comp sync(ret = %d)!\n", ret); + return ret; + } + + if (req.status) { + fprintf(stderr,"fail to do comp sync(status = %d)!\n", + req.status); + wd_comp_free_sess(h_sess); + return req.status; + } + *dstlen = req.dst_len; + + dbg("%s:output req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + wd_comp_free_sess(h_sess); + + return ret; +} + +int hw_stream_compress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen) +{ + handle_t h_sess; + struct wd_comp_sess_setup setup; + struct sched_params param = {0}; + struct wd_comp_req req; + int ret = 0; + + setup.alg_type = alg_type; + setup.op_type = WD_DIR_COMPRESS; + setup.comp_lv = WD_COMP_L8; + setup.win_sz = WD_COMP_WS_8K; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) { + fprintf(stderr,"fail to alloc comp sess!\n"); + return -EINVAL; + } + req.src = src; + req.src_len = srclen; + req.dst = dst; + req.dst_len = *dstlen; + req.op_type = WD_DIR_COMPRESS; + req.cb = NULL; + req.data_fmt = data_fmt; + + dbg("%s:input req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + ret = wd_do_comp_sync2(h_sess, &req); + if (ret < 0) { + fprintf(stderr,"fail to do comp sync(ret = %d)!\n", ret); + return ret; + } + + if (req.status) { + fprintf(stderr,"fail to do comp sync(status = %d)!\n", + req.status); + wd_comp_free_sess(h_sess); + return req.status; + } + *dstlen = req.dst_len; + + dbg("%s:output req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + wd_comp_free_sess(h_sess); + + return ret; +} + +int hw_stream_decompress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen) +{ + handle_t h_sess; + struct wd_comp_sess_setup setup; + struct sched_params param = {0}; + struct wd_comp_req req; + int ret = 0; + + + setup.alg_type = alg_type; + setup.op_type = WD_DIR_DECOMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) { + fprintf(stderr,"fail to alloc comp sess!\n"); + return -EINVAL; + } + req.src = src; + req.src_len = srclen; + req.dst = dst; + req.dst_len = *dstlen; + req.op_type = WD_DIR_DECOMPRESS; + req.cb = NULL; + req.data_fmt = data_fmt; + + dbg("%s:input req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + + ret = wd_do_comp_sync2(h_sess, &req); + if (ret < 0) { + fprintf(stderr,"fail to do comp sync(ret = %d)!\n", ret); + return ret; + } + + if (req.status) { + fprintf(stderr,"fail to do comp sync(status = %d)!\n", + req.status); + wd_comp_free_sess(h_sess); + return req.status; + } + *dstlen = req.dst_len; + + dbg("%s:output req: src:%p, dst:%p,src_len: %d, dst_len:%d\n", + __func__, req.src, req.dst, req.src_len, req.dst_len); + + wd_comp_free_sess(h_sess); + + return ret; +} + +void hizip_prepare_random_input_data(char *buf, size_t len, size_t block_size) +{ + __u32 seed = 0; + unsigned short rand_state[3] = {(seed >> 16) & 0xffff, seed & 0xffff, 0x330e}; + + unsigned long remain_size; + __u32 size; + size_t i, j; + + /* + * TODO: change state for each buffer, to make sure there is no TLB + * aliasing. + */ + remain_size = len; + + while (remain_size > 0) { + if (remain_size > block_size) + size = block_size; + else + size = remain_size; + /* + * Prepare the input buffer with a reproducible sequence of + * numbers. nrand48() returns a pseudo-random number in the + * interval [0; 2^31). It's not really possible to compress a + * pseudo-random stream using deflate, since it can't find any + * string repetition. As a result the output size is bigger, + * with a ratio of 1.041. + */ + for (i = 0; i < size; i += 4) { + __u64 n = nrand48(rand_state); + + for (j = 0; j < 4 && i + j < size; j++) + buf[i + j] = (n >> (8 * j)) & 0xff; + } + + buf += size; + remain_size -= size; + } +} + +int hizip_prepare_random_compressed_data(char *buf, size_t out_len, size_t in_len, + size_t *produced, + struct test_options *opts) +{ + off_t off; + int ret = -EINVAL; + void *init_buf = mmap_alloc(in_len); + size_t in_block_size = opts->block_size; + size_t out_block_size = 2 * in_block_size; + + if (!init_buf) + return -ENOMEM; + + hizip_prepare_random_input_data(init_buf, in_len, opts->block_size); + + /* Compress each chunk separately since we're working in stateless mode */ + for (off = 0; off < in_len; off += in_block_size) { + ret = zlib_deflate(buf, out_block_size, init_buf + off, + in_block_size, produced, opts->alg_type); + if (ret) + break; + buf += out_block_size; + } + + munmap(init_buf, in_len); + return ret; +} + +int hizip_verify_random_output(struct test_options *opts, + struct hizip_test_info *info, + size_t out_sz) +{ + int ret; + int seed = 0; + off_t off = 0; + size_t checked = 0; + size_t total_checked = 0; + struct check_rand_ctx rand_ctx = { + .state = {(seed >> 16) & 0xffff, seed & 0xffff, 0x330e}, + }; + + if (!opts->verify) + return 0; + + if (opts->op_type == WD_DIR_DECOMPRESS) + /* Check plain output */ + return hizip_check_rand((void *)info->out_buf, out_sz, + &rand_ctx); + + do { + ret = hizip_check_output(info->out_buf + off, out_sz, + &checked, hizip_check_rand, &rand_ctx); + if (ret) { + WD_ERR("Check output failed with %d\n", ret); + return ret; + } + total_checked += checked; + off += opts->block_size * EXPANSION_RATIO; + } while (!ret && total_checked < opts->total_len); + + if (rand_ctx.global_off != opts->total_len) { + WD_ERR("Invalid output size %lu != %lu\n", + rand_ctx.global_off, opts->total_len); + return -EINVAL; + } + return 0; +} + +static void *async_cb(struct wd_comp_req *req, void *data) +{ + return NULL; +} + +void *send_thread_func(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + size_t src_block_size, dst_block_size; + struct wd_comp_sess_setup setup; + struct sched_params param = {0}; + handle_t h_sess; + int j, ret; + size_t left; + + if (opts->op_type == WD_DIR_COMPRESS) { + src_block_size = opts->block_size; + dst_block_size = opts->block_size * EXPANSION_RATIO; + } else { + src_block_size = opts->block_size * EXPANSION_RATIO; + dst_block_size = opts->block_size; + } + + memset(&setup, 0, sizeof(struct wd_comp_sess_setup)); + setup.alg_type = opts->alg_type; + setup.op_type = opts->op_type; + setup.comp_lv = WD_COMP_L8; + setup.win_sz = WD_COMP_WS_8K; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_sess = wd_comp_alloc_sess(&setup); + if (!h_sess) + return NULL; + + for (j = 0; j < opts->compact_run_num; j++) { + if (opts->option & TEST_ZLIB) { + ret = zlib_deflate(info->out_buf, info->out_size, + info->in_buf, info->in_size, + &tdata->sum, opts->alg_type); + continue; + } + /* not TEST_ZLIB */ + left = opts->total_len; + tdata->req.op_type = opts->op_type; + tdata->req.src = info->in_buf; + tdata->req.dst = info->out_buf; + tdata->sum = 0; + while (left > 0) { + tdata->req.src_len = src_block_size; + tdata->req.dst_len = dst_block_size; + tdata->req.cb_param = &tdata->req; + if (opts->sync_mode) { + tdata->req.cb = async_cb; + count++; + ret = wd_do_comp_async(h_sess, &tdata->req); + } else { + tdata->req.cb = NULL; + ret = wd_do_comp_sync(h_sess, &tdata->req); + if (info->opts->faults & INJECT_SIG_WORK) + kill(getpid(), SIGTERM); + } + if (ret < 0) { + WD_ERR("do comp test fail with %d\n", ret); + return (void *)(uintptr_t)ret; + } else if (tdata->req.status) { + return (void *)(uintptr_t)tdata->req.status; + } + if (opts->op_type == WD_DIR_COMPRESS) + left -= src_block_size; + else + left -= dst_block_size; + tdata->req.src += src_block_size; + /* + * It's BLOCK (STATELESS) mode, so user needs to + * combine output buffer by himself. + */ + tdata->req.dst += dst_block_size; + tdata->sum += tdata->req.dst_len; + if (tdata->sum > info->out_size) { + fprintf(stderr, + "%s: exceed OUT limits (%ld > %ld)\n", + __func__, + tdata->sum, info->out_size); + break; + } + } + /* info->total_out are accessed by multiple threads */ + __atomic_add_fetch(&info->total_out, tdata->sum, + __ATOMIC_RELEASE); + } + wd_comp_free_sess(h_sess); + return NULL; +} + +int lib_poll_func(__u32 pos, __u32 expect, __u32 *count) +{ + int ret; + + ret = wd_comp_poll_ctx(pos, expect, count); + if (ret < 0) + return ret; + return 0; +} + +void *poll_thread_func(void *arg) +{ + struct hizip_test_info *info = (struct hizip_test_info *)arg; + int ret = 0, total = 0; + __u32 expected = 0, received; + + if (!info->opts->sync_mode) + return NULL; + while (1) { + if (info->opts->faults & INJECT_SIG_WORK) + kill(getpid(), SIGTERM); + + pthread_mutex_lock(&mutex); + if (!expected) + expected = 1; + if (count == 0) { + pthread_mutex_unlock(&mutex); + usleep(10); + continue; + } + expected = 1; + received = 0; + ret = wd_comp_poll(expected, &received); + if (ret == 0) + total += received; + if (count == total) { + pthread_mutex_unlock(&mutex); + break; + } else { + if (count > total) + expected = count - total; + pthread_mutex_unlock(&mutex); + usleep(10); + } + } + pthread_exit(NULL); +} + +int create_send_threads(struct test_options *opts, + struct hizip_test_info *info, + void *(*send_thread_func)(void *arg)) +{ + pthread_attr_t attr; + thread_data_t *tdatas; + int i, j, num, ret; + + num = opts->thread_num; + info->send_tds = calloc(1, sizeof(pthread_t) * num); + if (!info->send_tds) + return -ENOMEM; + info->send_tnum = num; + tdatas = calloc(1, sizeof(thread_data_t) * num); + if (!tdatas) { + ret = -ENOMEM; + goto out; + } + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + for (i = 0; i < num; i++) { + tdatas[i].info = info; + ret = pthread_create(&info->send_tds[i], &attr, + send_thread_func, &tdatas[i]); + if (ret < 0) { + fprintf(stderr, "Fail to create send thread %d (%d)\n", + i, ret); + goto out_thd; + } + } + pthread_attr_destroy(&attr); + g_conf = &info->ctx_conf; + return 0; +out_thd: + for (j = 0; j < i; j++) + pthread_cancel(info->send_tds[j]); + free(tdatas); +out: + free(info->send_tds); + return ret; +} + +int create_poll_threads(struct hizip_test_info *info, + void *(*poll_thread_func)(void *arg), + int num) +{ + struct test_options *opts = info->opts; + pthread_attr_t attr; + int i, ret; + + if (!opts->sync_mode) + return 0; + info->poll_tds = calloc(1, sizeof(pthread_t) * num); + if (!info->poll_tds) + return -ENOMEM; + info->poll_tnum = num; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + for (i = 0; i < num; i++) { + ret = pthread_create(&info->poll_tds[i], &attr, + poll_thread_func, info); + if (ret < 0) { + fprintf(stderr, "Fail to create send thread %d (%d)\n", + i, ret); + goto out; + } + } + pthread_attr_destroy(&attr); + count = 0; + return 0; +out: + free(info->poll_tds); + return ret; +} + +void free_threads(struct hizip_test_info *info) +{ + if (info->send_tds) + free(info->send_tds); + if (info->poll_tds) + free(info->poll_tds); +} + +int attach_threads(struct test_options *opts, struct hizip_test_info *info) +{ + int i, ret; + void *tret; + + if (opts->sync_mode) { + for (i = 0; i < info->poll_tnum; i++) { + ret = pthread_join(info->poll_tds[i], NULL); + if (ret < 0) + fprintf(stderr, "Fail on poll thread with %d\n", + ret); + } + } + for (i = 0; i < info->send_tnum; i++) { + ret = pthread_join(info->send_tds[i], &tret); + if (ret < 0) + fprintf(stderr, "Fail on send thread with %d\n", ret); + } + return (int)(uintptr_t)tret; +} + +void gen_random_data(void *buf, size_t len) +{ + int i; + uint32_t seed = 0; + unsigned short rand_state[3] = {(seed >> 16) & 0xffff, + seed & 0xffff, + 0x330e}; + + for (i = 0; i < len >> 3; i++) + *((uint64_t *)buf + i) = nrand48(rand_state); +} + +int calculate_md5(comp_md5_t *md5, const void *buf, size_t len) +{ + if (!md5 || !buf || !len) + return -EINVAL; + MD5_Init(&md5->md5_ctx); + MD5_Update(&md5->md5_ctx, buf, len); + MD5_Final(md5->md, &md5->md5_ctx); + return 0; +} + +void dump_md5(comp_md5_t *md5) +{ + int i; + + for (i = 0; i < MD5_DIGEST_LENGTH - 1; i++) + printf("%02x-", md5->md[i]); + printf("%02x\n", md5->md[i]); +} + +int cmp_md5(comp_md5_t *orig, comp_md5_t *final) +{ + int i; + + if (!orig || !final) + return -EINVAL; + for (i = 0; i < MD5_DIGEST_LENGTH; i++) { + if (orig->md[i] != final->md[i]) { + printf("Original MD5: "); + dump_md5(orig); + printf("Final MD5: "); + dump_md5(final); + return -EINVAL; + } + } + return 0; +} + +static void *async2_cb(struct wd_comp_req *req, void *data) +{ + sem_t *sem = (sem_t *)data; + + if (sem) + sem_post(sem); + return NULL; +} + +/* used in BATCH mode */ +static void *async5_cb(struct wd_comp_req *req, void *data) +{ + thread_data_t *tdata = (thread_data_t *)data; + + pthread_spin_lock(&lock); + tdata->pcnt++; + if (tdata->batch_flag && (tdata->pcnt == tdata->bcnt)) { + tdata->pcnt = 0; + tdata->bcnt = 0; + tdata->batch_flag = 0; + pthread_spin_unlock(&lock); + sem_post(&tdata->sem); + } else + pthread_spin_unlock(&lock); + return NULL; +} + +void init_chunk_list(chunk_list_t *list, void *buf, size_t buf_sz, + size_t chunk_sz) +{ + chunk_list_t *p = NULL; + int i, count; + size_t sum; + + count = (buf_sz + chunk_sz - 1) / chunk_sz; + for (i = 0, sum = 0, p = list; i < count && sum <= buf_sz; i++, p++) { + p->addr = buf + sum; + p->size = MIN(buf_sz - sum, chunk_sz); + if (i == count - 1) + p->next = NULL; + else + p->next = p + 1; + sum += p->size; + } +} + +chunk_list_t *create_chunk_list(void *buf, size_t buf_sz, size_t chunk_sz) +{ + chunk_list_t *list; + int count; + + count = (buf_sz + chunk_sz - 1) / chunk_sz; + if (count > HIZIP_CHUNK_LIST_ENTRIES) + count = HIZIP_CHUNK_LIST_ENTRIES; + if (buf_sz / chunk_sz > count) + return NULL; + /* allocate entries with additional one */ + list = malloc(sizeof(chunk_list_t) * (count + 1)); + if (!list) + return NULL; + init_chunk_list(list, buf, buf_sz, chunk_sz); + return list; +} + +void free_chunk_list(chunk_list_t *list) +{ + free(list); +} + +/* + * Deflate a data block with compressed header. + */ +static int chunk_deflate2(void *in, size_t in_sz, void *out, size_t *out_sz, + struct test_options *opts) +{ + int alg_type = opts->alg_type; + z_stream strm; + int windowBits; + int ret; + + switch (alg_type) { + case WD_ZLIB: + windowBits = 15; + break; + case WD_DEFLATE: + windowBits = -15; + break; + case WD_GZIP: + windowBits = 15 + 16; + break; + default: + printf("algorithm %d unsupported by zlib\n", alg_type); + return -EINVAL; + } + memset(&strm, 0, sizeof(z_stream)); + strm.next_in = in; + strm.avail_in = in_sz; + strm.next_out = out; + strm.avail_out = *out_sz; + + ret = deflateInit2(&strm, Z_BEST_SPEED, Z_DEFLATED, windowBits, + 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + printf("deflateInit2: %d\n", ret); + return -EINVAL; + } + + do { + ret = deflate(&strm, Z_FINISH); + if ((ret == Z_STREAM_ERROR) || (ret == Z_BUF_ERROR)) { + printf("defalte error %d - %s\n", ret, strm.msg); + ret = -ENOSR; + break; + } else if (!strm.avail_in) { + if (ret != Z_STREAM_END) + printf("deflate unexpected return: %d\n", ret); + ret = 0; + break; + } else if (!strm.avail_out) { + printf("deflate out of memory\n"); + ret = -ENOSPC; + break; + } + } while (ret == Z_OK); + + deflateEnd(&strm); + *out_sz = *out_sz - strm.avail_out; + return ret; +} + +/* + * This function is used in BLOCK mode. Each compressing in BLOCK mode + * produces compression header. + */ +static int chunk_inflate2(void *in, size_t in_sz, void *out, size_t *out_sz, + struct test_options *opts) +{ + z_stream strm; + int ret; + + memset(&strm, 0, sizeof(z_stream)); + /* Window size of 15, +32 for auto-decoding gzip/zlib */ + ret = inflateInit2(&strm, 15 + 32); + if (ret != Z_OK) { + printf("zlib inflateInit: %d\n", ret); + return -EINVAL; + } + + strm.next_in = in; + strm.avail_in = in_sz; + strm.next_out = out; + strm.avail_out = *out_sz; + do { + ret = inflate(&strm, Z_NO_FLUSH); + if ((ret < 0) || (ret == Z_NEED_DICT)) { + printf("zlib error %d - %s\n", ret, strm.msg); + goto out; + } + if (!strm.avail_out) { + if (!strm.avail_in || (ret == Z_STREAM_END)) + break; + printf("%s: avail_out is empty!\n", __func__); + goto out; + } + } while (strm.avail_in && (ret != Z_STREAM_END)); + inflateEnd(&strm); + *out_sz = *out_sz - strm.avail_out; + return 0; +out: + inflateEnd(&strm); + ret = -EINVAL; + return ret; +} + +/* + * Compress a list of chunk data and produce a list of chunk data by software. + * in_list & out_list should be formated first. + */ +int sw_deflate2(chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts) +{ + chunk_list_t *p, *q; + int ret = -EINVAL; + + for (p = in_list, q = out_list; p && q; p = p->next, q = q->next) { + ret = chunk_deflate2(p->addr, p->size, q->addr, &q->size, + opts); + if (ret) + return ret; + } + return ret; +} + +/* + * Compress a list of chunk data and produce a list of chunk data by software. + * in_list & out_list should be formated first. + */ +int sw_inflate2(chunk_list_t *in_list, chunk_list_t *out_list, + struct test_options *opts) +{ + chunk_list_t *p, *q; + int ret = -EINVAL; + + for (p = in_list, q = out_list; p && q; p = p->next, q = q->next) { + ret = chunk_inflate2(p->addr, p->size, q->addr, &q->size, + opts); + if (ret) + return ret; + } + return ret; +} + +int hw_deflate4(handle_t h_dfl, + chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts, + sem_t *sem) +{ + struct wd_comp_req *reqs; + chunk_list_t *p = in_list, *q = out_list; + int i, ret; + + if (!in_list || !out_list || !opts || !sem) + return -EINVAL; + /* reqs array could make async operations in parallel */ + reqs = malloc(sizeof(struct wd_comp_req) * HIZIP_CHUNK_LIST_ENTRIES); + if (!reqs) + return -ENOMEM; + + for (i = 0; p && q; p = p->next, q = q->next, i++) { + reqs[i].src = p->addr; + reqs[i].src_len = p->size; + reqs[i].dst = q->addr; + reqs[i].dst_len = q->size; + reqs[i].op_type = WD_DIR_COMPRESS; + + if (opts->sync_mode) { + reqs[i].cb = async2_cb; + reqs[i].cb_param = sem; + } + do { + if (opts->sync_mode) { + ret = wd_do_comp_async(h_dfl, &reqs[i]); + if (!ret) { + __atomic_add_fetch(&sum_pend, 1, + __ATOMIC_ACQ_REL); + sem_wait(sem); + } + } else + ret = wd_do_comp_sync(h_dfl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret) + goto out; + q->size = reqs[i].dst_len; + /* make sure olist has the same length with ilist */ + if (!p->next) + q->next = NULL; + i++; + } + free(reqs); + return 0; +out: + free(reqs); + return ret; +} + +int hw_inflate4(handle_t h_ifl, + chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts, + sem_t *sem) +{ + struct wd_comp_req *reqs; + chunk_list_t *p, *q; + int i = 0, ret; + + /* reqs array could make async operations in parallel */ + reqs = calloc(1, sizeof(struct wd_comp_req) * HIZIP_CHUNK_LIST_ENTRIES); + if (!reqs) + return -ENOMEM; + for (p = in_list, q = out_list; p && q; p = p->next, q = q->next) { + reqs[i].src = p->addr; + reqs[i].src_len = p->size; + reqs[i].dst = q->addr; + reqs[i].dst_len = q->size; + reqs[i].op_type = WD_DIR_DECOMPRESS; + if (opts->sync_mode) { + reqs[i].cb = async2_cb; + reqs[i].cb_param = sem; + } + do { + if (opts->sync_mode) { + ret = wd_do_comp_async(h_ifl, &reqs[i]); + if (!ret) { + __atomic_add_fetch(&sum_pend, 1, + __ATOMIC_ACQ_REL); + sem_wait(sem); + } + } else + ret = wd_do_comp_sync(h_ifl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret) + goto out; + q->size = reqs[i].dst_len; + /* make sure olist has the same length with ilist */ + if (!p->next) + q->next = NULL; + i++; + } + free(reqs); + return 0; +out: + free(reqs); + return ret; +} + +/* used in BATCH mode */ +int hw_deflate5(handle_t h_dfl, + chunk_list_t *in_list, + chunk_list_t *out_list, + thread_data_t *tdata) +{ + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_req *reqs = tdata->reqs; + chunk_list_t *p = in_list, *q = out_list; + int i = 0, ret = 0; + + if (!in_list || !out_list || !opts) + return -EINVAL; + for (p = in_list, q = out_list; p && q; p = p->next, q = q->next) { + reqs[i].src = p->addr; + reqs[i].src_len = p->size; + reqs[i].dst = q->addr; + reqs[i].dst_len = q->size; + reqs[i].op_type = WD_DIR_COMPRESS; + reqs[i].data_fmt = opts->data_fmt; + if (opts->sync_mode) { + reqs[i].cb = async5_cb; + reqs[i].cb_param = tdata; + } else { + reqs[i].cb = NULL; + reqs[i].cb_param = NULL; + } + if (opts->sync_mode) { + do { + ret = wd_do_comp_async(h_dfl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret < 0) + goto out; + __atomic_add_fetch(&sum_pend, 1, __ATOMIC_ACQ_REL); + pthread_spin_lock(&lock); + tdata->bcnt++; + if (((i + 1) == opts->batch_num) || !p->next) { + tdata->batch_flag = 1; + pthread_spin_unlock(&lock); + sem_wait(&tdata->sem); + } else + pthread_spin_unlock(&lock); + } else { + do { + ret = wd_do_comp_sync(h_dfl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret) + goto out; + } + q->size = reqs[i].dst_len; + i = (i + 1) % opts->batch_num; + /* make sure olist has the same length with ilist */ + if (!p->next) + q->next = NULL; + } + return 0; +out: + return ret; +} + +/* used in BATCH mode */ +int hw_inflate5(handle_t h_ifl, + chunk_list_t *in_list, + chunk_list_t *out_list, + thread_data_t *tdata) +{ + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_req *reqs = tdata->reqs; + chunk_list_t *p = in_list, *q = out_list; + int ret = 0, i = 0; + + if (!in_list || !out_list || !opts) + return -EINVAL; + for (p = in_list, q = out_list; p && q; p = p->next, q = q->next) { + reqs[i].src = p->addr; + reqs[i].src_len = p->size; + reqs[i].dst = q->addr; + reqs[i].dst_len = q->size; + reqs[i].op_type = WD_DIR_DECOMPRESS; + reqs[i].data_fmt = opts->data_fmt; + if (opts->sync_mode) { + reqs[i].cb = async5_cb; + reqs[i].cb_param = tdata; + } else { + reqs[i].cb = NULL; + reqs[i].cb_param = NULL; + } + if (opts->sync_mode) { + do { + ret = wd_do_comp_async(h_ifl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret < 0) + goto out; + __atomic_add_fetch(&sum_pend, 1, __ATOMIC_ACQ_REL); + pthread_spin_lock(&lock); + tdata->bcnt++; + if (((i + 1) == opts->batch_num) || !p->next) { + tdata->batch_flag = 1; + pthread_spin_unlock(&lock); + sem_wait(&tdata->sem); + } else + pthread_spin_unlock(&lock); + } else { + do { + ret = wd_do_comp_sync(h_ifl, &reqs[i]); + } while (ret == -WD_EBUSY); + if (ret) + goto out; + } + q->size = reqs[i].dst_len; + i = (i + 1) % opts->batch_num; + /* make sure olist has the same length with ilist */ + if (!p->next) + q->next = NULL; + } + return 0; +out: + return ret; +} + +/* + * info->in_buf & info->out_buf should be allocated first. + * Thread 0 shares info->out_buf. Other threads need to create its own + * dst buffer. + */ +int create_send_tdata(struct test_options *opts, + struct hizip_test_info *info) +{ + thread_data_t *tdata; + chunk_list_t *in_list, *out_list; + int i, j, num, ret; + + if (!opts || !info || !info->in_chunk_sz || !info->out_chunk_sz) + return -EINVAL; + num = opts->thread_num; + info->send_tds = calloc(1, sizeof(pthread_t) * num); + if (!info->send_tds) + return -ENOMEM; + info->send_tnum = num; + info->tdatas = calloc(1, sizeof(thread_data_t) * num); + if (!info->tdatas) { + ret = -ENOMEM; + goto out; + } + if (!opts->batch_num) + opts->batch_num = 1; + else if (opts->batch_num > HIZIP_CHUNK_LIST_ENTRIES) + opts->batch_num = HIZIP_CHUNK_LIST_ENTRIES; + if (opts->is_stream) { + in_list = create_chunk_list(info->in_buf, info->in_size, + info->in_size); + } else { + in_list = create_chunk_list(info->in_buf, info->in_size, + info->in_chunk_sz); + } + if (!in_list) { + ret = -EINVAL; + goto out_in; + } + if (opts->option & TEST_THP) { + ret = madvise(info->in_buf, info->in_size, MADV_HUGEPAGE); + if (ret) { + printf("madvise(MADV_HUGEPAGE)"); + goto out_in; + } + } + for (i = 0; i < num; i++) { + tdata = &info->tdatas[i]; + /* src address is shared among threads */ + tdata->tid = i; + tdata->src_sz = info->in_size; + tdata->src = info->in_buf; + tdata->in_list = in_list; + tdata->dst_sz = info->out_size; + tdata->dst = mmap_alloc(tdata->dst_sz); + if (!tdata->dst) { + ret = -ENOMEM; + goto out_dst; + } + if (opts->option & TEST_THP) { + ret = madvise(tdata->dst, tdata->dst_sz, MADV_HUGEPAGE); + if (ret) { + printf("madvise(MADV_HUGEPAGE)"); + goto out_dst; + } + } + /* + * Without memset, valgrind reports uninitialized buf + * for writing to file. + */ + memset(tdata->dst, 0, tdata->dst_sz); + if (opts->is_stream) { + out_list = create_chunk_list(tdata->dst, + tdata->dst_sz, + tdata->dst_sz); + } else { + out_list = create_chunk_list(tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + } + tdata->out_list = out_list; + if (!tdata->out_list) { + ret = -EINVAL; + goto out_list; + } + calculate_md5(&tdata->md5, tdata->src, tdata->src_sz); + tdata->reqs = malloc(sizeof(struct wd_comp_req) * + opts->batch_num); + if (!tdata->reqs) + goto out_list; + sem_init(&tdata->sem, 0, 0); + tdata->info = info; + } + return 0; +out_list: + mmap_free(tdata->dst, tdata->dst_sz); +out_dst: + for (j = 0; j < i; j++) { + pthread_cancel(info->send_tds[j]); + free_chunk_list(info->tdatas[j].out_list); + mmap_free(info->tdatas[j].dst, info->tdatas[j].dst_sz); + } + free_chunk_list(in_list); +out_in: + free(info->tdatas); +out: + free(info->send_tds); + return ret; +} + +int create_poll_tdata(struct test_options *opts, + struct hizip_test_info *info, + int poll_num) +{ + thread_data_t *tdatas; + int i, ret; + + if (opts->sync_mode == 0) + return 0; + else if (poll_num <= 0) + return -EINVAL; + info->poll_tnum = poll_num; + info->poll_tds = calloc(1, sizeof(pthread_t) * poll_num); + if (!info->poll_tds) + return -ENOMEM; + info->p_tdatas = calloc(1, sizeof(thread_data_t) * poll_num); + if (!info->p_tdatas) { + ret = -ENOMEM; + goto out; + } + tdatas = info->p_tdatas; + for (i = 0; i < poll_num; i++) { + tdatas[i].tid = i; + tdatas[i].info = info; + } + return 0; +out: + free(info->poll_tds); + return ret; +} + +/* + * Free source and destination buffer contained in sending threads. + * Free sending threads and polling threads. + */ +void free2_threads(struct hizip_test_info *info) +{ + thread_data_t *tdatas = info->tdatas; + int i; + + if (info->send_tds) + free(info->send_tds); + if (info->poll_tds) { + free(info->poll_tds); + free(info->p_tdatas); + } + free_chunk_list(tdatas[0].in_list); + for (i = 0; i < info->send_tnum; i++) { + free_chunk_list(tdatas[i].out_list); + free(tdatas[i].reqs); + } + /* info->out_buf is bound to tdatas[0].dst */ + for (i = 0; i < info->send_tnum; i++) + mmap_free(tdatas[i].dst, tdatas[i].dst_sz); + free(info->tdatas); + mmap_free(info->in_buf, info->in_size); +} + +int attach2_threads(struct test_options *opts, + struct hizip_test_info *info, + void *(*send_thread_func)(void *arg), + void *(*poll_thread_func)(void *arg)) +{ + int i, j, ret, num; + void *tret; + pthread_attr_t attr; + + num = opts->thread_num; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + for (i = 0; i < num; i++) { + ret = pthread_create(&info->send_tds[i], &attr, + send_thread_func, &info->tdatas[i]); + if (ret < 0) { + printf("Fail to create send thread %d (%d)\n", i, ret); + goto out; + } + } + if (opts->sync_mode && !opts->use_env) { + for (i = 0; i < opts->poll_num; i++) { + ret = pthread_create(&info->poll_tds[i], &attr, + poll_thread_func, + &info->tdatas[i]); + if (ret < 0) { + printf("Fail to create poll thread %d (%d)\n", + i, ret); + goto out_poll; + } + } + for (i = 0; i < info->poll_tnum; i++) { + ret = pthread_join(info->poll_tds[i], &tret); + if (ret < 0) { + fprintf(stderr, "Fail on poll thread with %d\n", + ret); + goto out_poll; + } + } + } + for (i = 0; i < info->send_tnum; i++) { + ret = pthread_join(info->send_tds[i], &tret); + if (ret < 0) { + fprintf(stderr, "Fail on send thread with %d\n", ret); + goto out_poll; + } + } + pthread_attr_destroy(&attr); + return (int)(uintptr_t)tret; +out_poll: + for (j = 0; j < i; j++) + pthread_cancel(info->poll_tds[j]); + i = opts->thread_num; +out: + for (j = 0; j < i; j++) + pthread_cancel(info->send_tds[j]); + pthread_attr_destroy(&attr); + return ret; +} + +void *poll2_thread_func(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + __u32 received; + int ret = 0; + struct timeval start_tvl, end_tvl; + int pending; + int end_threads; + + gettimeofday(&start_tvl, NULL); + while (1) { + end_threads = __atomic_load_n(&sum_thread_end, + __ATOMIC_ACQUIRE); + pending = __atomic_load_n(&sum_pend, __ATOMIC_ACQUIRE); + if ((end_threads == info->send_tnum) && (pending == 0)) + break; + else if (pending == 0) + continue; + received = 0; + ret = wd_comp_poll(pending, &received); + if (ret == 0) { + __atomic_sub_fetch(&sum_pend, + received, + __ATOMIC_ACQ_REL); + } + } + gettimeofday(&end_tvl, NULL); + timersub(&end_tvl, &start_tvl, &start_tvl); + pthread_exit(NULL); +} + +/* + * Choose a device and check whether it can afford the requested contexts. + * Return a list whose the first device is chosen. + */ +struct uacce_dev_list *get_dev_list(struct test_options *opts, + int children) +{ + struct uacce_dev_list *list, *p, *head = NULL, *prev = NULL; + int max_q_num; + + list = wd_get_accel_list("zlib"); + if (!list) + return NULL; + + p = list; + /* Find one device matching the requested contexts. */ + while (p) { + max_q_num = wd_get_avail_ctx(p->dev); + /* + * Check whether there's enough contexts. + * There may be multiple taskes running together. + * The number of multiple taskes is specified in children. + */ + if (max_q_num < 4 * opts->q_num * children) { + if (!head) + head = p; + prev = p; + p = p->next; + } else + break; + } + + if (!p) { + WD_ERR("Request too much contexts: %d\n", + opts->q_num * 4 * children); + goto out; + } + + /* Adjust p to the head of list if p is in the middle. */ + if (p && (p != list)) { + prev->next = p->next; + p->next = head; + return p; + } + return list; +out: + wd_free_list_accels(list); + return NULL; +} + +/* + * Initialize context numbers by the four times of opts->q_num. + * [sync, async] * [compress, decompress] = 4 + */ +int init_ctx_config(struct test_options *opts, void *priv, + struct wd_sched **sched) +{ + struct hizip_test_info *info = priv; + struct wd_ctx_config *ctx_conf = &info->ctx_conf; + struct sched_params param; + int i, j, ret = -EINVAL; + int q_num = opts->q_num; + + + __atomic_store_n(&sum_pend, 0, __ATOMIC_RELEASE); + __atomic_store_n(&sum_thread_end, 0, __ATOMIC_RELEASE); + *sched = wd_sched_rr_alloc(SCHED_POLICY_RR, 2, 2, lib_poll_func); + if (!*sched) { + WD_ERR("wd_sched_rr_alloc fail\n"); + goto out_sched; + } + + (*sched)->name = SCHED_RR_NAME; + + memset(ctx_conf, 0, sizeof(struct wd_ctx_config)); + ctx_conf->ctx_num = q_num * 4; + ctx_conf->ctxs = calloc(1, q_num * 4 * sizeof(struct wd_ctx)); + if (!ctx_conf->ctxs) { + WD_ERR("Not enough memory to allocate contexts.\n"); + ret = -ENOMEM; + goto out_ctx; + } + for (i = 0; i < ctx_conf->ctx_num; i++) { + ctx_conf->ctxs[i].ctx = wd_request_ctx(info->list->dev); + if (!ctx_conf->ctxs[i].ctx) { + WD_ERR("Fail to allocate context #%d\n", i); + ret = -EINVAL; + goto out_req; + } + } + /* + * All contexts for 2 modes & 2 types. + * The test only uses one kind of contexts at the same time. + */ + for (i = 0; i < q_num; i++) { + ctx_conf->ctxs[i].ctx_mode = 0; + ctx_conf->ctxs[i].op_type = 0; + } + param.numa_id = 0; + param.mode = 0; + param.type = 0; + param.begin = 0; + param.end = q_num - 1; + ret = wd_sched_rr_instance((const struct wd_sched *)*sched, ¶m); + if (ret < 0) { + WD_ERR("Fail to fill sched region.\n"); + goto out_fill; + } + for (i = q_num; i < q_num * 2; i++) { + ctx_conf->ctxs[i].ctx_mode = 0; + ctx_conf->ctxs[i].op_type = 1; + } + param.mode = 0; + param.type = 1; + param.begin = q_num; + param.end = q_num * 2 - 1; + ret = wd_sched_rr_instance((const struct wd_sched *)*sched, ¶m); + if (ret < 0) { + WD_ERR("Fail to fill sched region.\n"); + goto out_fill; + } + for (i = q_num * 2; i < q_num * 3; i++) { + ctx_conf->ctxs[i].ctx_mode = 1; + ctx_conf->ctxs[i].op_type = 0; + } + param.mode = 1; + param.type = 0; + param.begin = q_num * 2; + param.end = q_num * 3 - 1; + ret = wd_sched_rr_instance((const struct wd_sched *)*sched, ¶m); + if (ret < 0) { + WD_ERR("Fail to fill sched region.\n"); + goto out_fill; + } + for (i = q_num * 3; i < q_num * 4; i++) { + ctx_conf->ctxs[i].ctx_mode = 1; + ctx_conf->ctxs[i].op_type = 1; + } + param.mode = 1; + param.type = 1; + param.begin = q_num * 3; + param.end = q_num * 4 - 1; + ret = wd_sched_rr_instance((const struct wd_sched *)*sched, ¶m); + if (ret < 0) { + WD_ERR("Fail to fill sched region.\n"); + goto out_fill; + } + + ret = wd_comp_init(ctx_conf, *sched); + if (ret) + goto out_fill; + return ret; + +out_fill: + for (i = 0; i < ctx_conf->ctx_num; j++) + wd_release_ctx(ctx_conf->ctxs[i].ctx); +out_req: + free(ctx_conf->ctxs); +out_ctx: + wd_sched_rr_release(*sched); +out_sched: + return ret; +} + +void uninit_config(void *priv, struct wd_sched *sched) +{ + struct hizip_test_info *info = priv; + struct wd_ctx_config *ctx_conf = &info->ctx_conf; + int i; + + wd_comp_uninit(); + for (i = 0; i < ctx_conf->ctx_num; i++) + wd_release_ctx(ctx_conf->ctxs[i].ctx); + free(ctx_conf->ctxs); + wd_sched_rr_release(sched); +} + +int parse_common_option(const char opt, const char *optarg, + struct test_options *opts) +{ + switch (opt) { + case 'b': + opts->block_size = strtol(optarg, NULL, 0); + if (opts->block_size <= 0) + return 1; + break; + case 'l': + opts->compact_run_num = strtol(optarg, NULL, 0); + if (opts->compact_run_num <= 0) + return 1; + break; + case 'n': + opts->run_num = strtol(optarg, NULL, 0); + SYS_ERR_COND(opts->run_num > MAX_RUNS, + "No more than %d runs supported\n", MAX_RUNS); + if (opts->run_num <= 0) + return 1; + break; + case 'q': + opts->q_num = strtol(optarg, NULL, 0); + if (opts->q_num <= 0) + return 1; + break; + case 'd': + opts->op_type = WD_DIR_DECOMPRESS; + break; + case 'F': + opts->is_file = true; + break; + case 'S': + opts->is_stream = MODE_STREAM; + break; + case 's': + opts->total_len = strtol(optarg, NULL, 0); + SYS_ERR_COND(opts->total_len <= 0, "invalid size '%s'\n", + optarg); + break; + case 't': + opts->thread_num = strtol(optarg, NULL, 0); + SYS_ERR_COND(opts->thread_num < 0, "invalid thread num '%s'\n", + optarg); + break; + case 'm': + opts->sync_mode = strtol(optarg, NULL, 0); + SYS_ERR_COND(opts->sync_mode < 0 || opts->sync_mode > 1, + "invalid sync mode '%s'\n", optarg); + break; + case 'V': + opts->verify = true; + break; + case 'v': + opts->verbose = true; + break; + case 'a': + opts->alg_type = WD_DEFLATE; + break; + case 'z': + opts->alg_type = WD_ZLIB; + break; + case 'L': + opts->data_fmt = WD_SGL_BUF; + break; + case 'Z': + opts->alg_type = WD_LZ77_ZSTD; + break; + default: + return 1; + } + + return 0; +} + +#ifdef HAVE_ZLIB + +#include <zlib.h> + +/* + * Try to decompress a buffer using zLib's inflate(). Call compare_output with + * the decompressed stream as argument + * + * Return 0 on success, or an error. + */ +int hizip_check_output(void *buf, size_t size, size_t *checked, + check_output_fn compare_output, void *opaque) +{ + int ret, ret2; + unsigned char *out_buffer; + const size_t out_buf_size = 0x100000; + z_stream stream = { + .next_in = buf, + .avail_in = size, + }; + + out_buffer = calloc(1, out_buf_size); + if (!out_buffer) + return -ENOMEM; + + stream.next_out = out_buffer; + stream.avail_out = out_buf_size; + + /* Window size of 15, +32 for auto-decoding gzip/zlib */ + ret = inflateInit2(&stream, 15 + 32); + if (ret != Z_OK) { + WD_ERR("zlib inflateInit: %d\n", ret); + ret = -EINVAL; + goto out_free_buf; + } + + do { + ret = inflate(&stream, Z_NO_FLUSH); + if (ret < 0 || ret == Z_NEED_DICT) { + WD_ERR("zlib error %d - %s\n", ret, stream.msg); + ret = -ENOSR; + break; + } + + ret2 = compare_output(out_buffer, out_buf_size - + stream.avail_out, opaque); + /* compare_output should print diagnostic messages. */ + if (ret2) { + ret = Z_STREAM_ERROR; + break; + } + + if (!stream.avail_out) { + stream.next_out = out_buffer; + stream.avail_out = out_buf_size; + } + } while (ret != Z_STREAM_END); + + if (ret == Z_STREAM_END || ret == Z_OK) { + *checked = stream.total_out; + ret = 0; + } + + inflateEnd(&stream); +out_free_buf: + free(out_buffer); + return ret; +} + +int zlib_deflate(void *output, unsigned int out_size, + void *input, unsigned int in_size, + unsigned long *produced, int alg_type) +{ + int ret; + int windowBits; + z_stream stream = { + .next_in = input, + .avail_in = in_size, + .next_out = output, + .avail_out = out_size, + }; + + switch (alg_type) { + case WD_ZLIB: + windowBits = 15; + break; + case WD_DEFLATE: + windowBits = -15; + break; + case WD_GZIP: + windowBits = 15 + 16; + break; + default: + WD_ERR("algorithm %d unsupported by zlib\n", alg_type); + return -EINVAL; + } + + ret = deflateInit2(&stream, Z_BEST_SPEED, Z_DEFLATED, windowBits, 9, + Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + WD_ERR("zlib deflateInit: %d\n", ret); + return -EINVAL; + } + + do { + ret = deflate(&stream, Z_FINISH); + if (ret == Z_STREAM_ERROR || ret == Z_BUF_ERROR) { + WD_ERR("zlib error %d - %s\n", ret, stream.msg); + ret = -ENOSR; + break; + } else if (!stream.avail_in) { + if (ret != Z_STREAM_END) + WD_ERR("unexpected deflate return value %d\n", ret); + *produced = stream.total_out; + ret = 0; + break; + } else if (!stream.avail_out) { + WD_ERR("No more output available\n"); + ret = -ENOSPC; + break; + } + } while (ret == Z_OK); + + deflateEnd(&stream); + + return ret; +} +#endif diff --git a/uadk_tool/test/comp_lib.h b/uadk_tool/test/comp_lib.h new file mode 100644 index 0000000..95b5a31 --- /dev/null +++ b/uadk_tool/test/comp_lib.h @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved. + * Copyright 2020-2021 Linaro ltd. + */ + +#ifndef TEST_LIB_H_ +#define TEST_LIB_H_ + +#include <errno.h> +#include <openssl/md5.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/resource.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <unistd.h> +#include "config.h" +#include "include/wd_comp.h" +#include "include/wd_sched.h" + +#define SYS_ERR_COND(cond, msg, ...) \ +do { \ + if (cond) { \ + if (errno) \ + perror(msg); \ + else \ + fprintf(stderr, msg, ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } \ +} while (0) + +enum mode { + MODE_BLOCK, + MODE_STREAM, +}; + +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#define MIN(a, b) ((a < b) ? a : b) + +/* + * I observed a worst case of 1.041x expansion with random data, but let's say 2 + * just in case. TODO: reduce this + */ +#define EXPANSION_RATIO 2 +/* The INFLATION_RATIO is high for text file. */ +#define INFLATION_RATIO 24 + +#define SGE_SIZE (8 * 1024) + +#define HIZIP_CHUNK_LIST_ENTRIES 32768 + +struct test_options { + int alg_type; + int op_type; + + /* bytes of data for a request */ + int block_size; + int q_num; + unsigned long total_len; + +#define MAX_RUNS 1024 + int run_num; + /* tasks running in parallel */ + int compact_run_num; + + /* send thread number */ + int thread_num; + /* poll thread number -- ASYNC */ + int poll_num; + /* 0: sync mode, 1: async mode */ + int sync_mode; + /* + * positive value: the number of messages are sent at a time. + * 0: batch mode is disabled. + * batch mode is only valid for ASYNC operations. + */ + int batch_num; + /* input file */ + int fd_in; + /* output file */ + int fd_out; + /* inlist file */ + int fd_ilist; + /* outlist file */ + int fd_olist; + + /* 0: pbuffer, 1: sgl */ + __u8 data_fmt; + + bool verify; + bool verbose; + bool is_decomp; + bool is_stream; + bool is_file; + bool use_env; + + int warmup_num; + +#define PERFORMANCE (1UL << 0) +#define TEST_ZLIB (1UL << 1) +#define TEST_THP (1UL << 2) + unsigned long option; + +#define STATS_NONE 0 +#define STATS_PRETTY 1 +#define STATS_CSV 2 + unsigned long display_stats; + + /* bind test case related below */ + int children; + +#define INJECT_SIG_BIND (1UL << 0) +#define INJECT_SIG_WORK (1UL << 1) +#define INJECT_TLB_FAULT (1UL << 2) + unsigned long faults; + +}; + +typedef struct _comp_md5_t { + MD5_CTX md5_ctx; + unsigned char md[MD5_DIGEST_LENGTH]; +} comp_md5_t; + +typedef struct hizip_chunk_list { + void *addr; + size_t size; + struct hizip_chunk_list *next; +} chunk_list_t; + +typedef struct _thread_data_t { + struct hizip_test_info *info; + struct wd_comp_req req; + comp_md5_t md5; + void *src; + void *dst; + size_t src_sz; + size_t dst_sz; + size_t sum; /* produced bytes for OUT */ + int tid; /* thread ID */ + int bcnt; /* batch mode: count */ + int pcnt; /* batch mode: poll count */ + int flush_bcnt; /* batch mode: flush count that is less batch_num */ + /* + * batch mode: set flag and wait batch end in sending thread. + * Clear batch flag if pcnt == bcnt in polling thread. + * batch_flag could replace flush_bcnt. + */ + int batch_flag; + sem_t sem; + chunk_list_t *in_list; + chunk_list_t *out_list; + struct wd_comp_req *reqs; +} thread_data_t; + +struct hizip_test_info { + struct test_options *opts; + char *in_buf, *out_buf; + size_t in_size, out_size; + /* in_chunk_sz & out_chunk_sz are used to format entries in list */ + size_t in_chunk_sz, out_chunk_sz; + size_t total_out; + struct uacce_dev_list *list; + handle_t h_sess; + struct wd_ctx_config ctx_conf; + pthread_t *send_tds; + int send_tnum; + pthread_t *poll_tds; + int poll_tnum; + /* tdatas: send thread data array, p_tdatas: poll thread data array */ + thread_data_t *tdatas; + thread_data_t *p_tdatas; + struct hizip_stats *stats; + struct { + struct timespec setup_time; + struct timespec start_time; + struct timespec end_time; + struct timespec setup_cputime; + struct timespec start_cputime; + struct timespec end_cputime; + struct rusage setup_rusage; + struct rusage start_rusage; + struct rusage end_rusage; + } tv; +}; + +extern int sum_pend, sum_thread_end; + +void *send_thread_func(void *arg); +void *poll_thread_func(void *arg); +void *sw_dfl_sw_ifl(void *arg); +int create_send_threads(struct test_options *opts, + struct hizip_test_info *info, + void *(*send_thread_func)(void *arg)); +int create_poll_threads(struct hizip_test_info *info, + void *(*poll_thread_func)(void *arg), + int num); +void free_threads(struct hizip_test_info *info); +int attach_threads(struct test_options *opts, + struct hizip_test_info *info); + +void gen_random_data(void *buf, size_t len); +int calculate_md5(comp_md5_t *md5, const void *buf, size_t len); +void dump_md5(comp_md5_t *md5); +int cmp_md5(comp_md5_t *orig, comp_md5_t *final); +void init_chunk_list(chunk_list_t *list, void *buf, size_t buf_sz, + size_t chunk_sz); +chunk_list_t *create_chunk_list(void *buf, size_t buf_sz, size_t chunk_sz); +void free_chunk_list(chunk_list_t *list); +int sw_deflate2(chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts); +int sw_inflate2(chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts); +int hw_deflate4(handle_t h_dfl, + chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts, + sem_t *sem); +int hw_inflate4(handle_t h_ifl, + chunk_list_t *in_list, + chunk_list_t *out_list, + struct test_options *opts, + sem_t *sem); +int hw_deflate5(handle_t h_dfl, + chunk_list_t *in_list, + chunk_list_t *out_list, + thread_data_t *tdata); +int hw_inflate5(handle_t h_ifl, + chunk_list_t *in_list, + chunk_list_t *out_list, + thread_data_t *tdata); +int create_send_tdata(struct test_options *opts, + struct hizip_test_info *info); +int create_poll_tdata(struct test_options *opts, + struct hizip_test_info *info, + int poll_num); +void free2_threads(struct hizip_test_info *info); +int attach2_threads(struct test_options *opts, + struct hizip_test_info *info, + void *(*send_thread_func)(void *arg), + void *(*poll_thread_func)(void *arg)); +void *poll2_thread_func(void *arg); +int run_self_test(struct test_options *opts); +int run_cmd(struct test_options *opts); +int init_ctx_config(struct test_options *opts, + void *priv, + struct wd_sched **sched + ); +void uninit_config(void *priv, struct wd_sched *sched); +struct uacce_dev_list *get_dev_list(struct test_options *opts, int children); + +void hizip_prepare_random_input_data(char *buf, size_t len, size_t block_size); +int hizip_prepare_random_compressed_data(char *buf, size_t out_len, + size_t in_len, size_t *produced, + struct test_options *opts); + +int hizip_verify_random_output(struct test_options *opts, + struct hizip_test_info *info, + size_t out_sz); + +void *mmap_alloc(size_t len); +int mmap_free(void *addr, size_t len); + +int lib_poll_func(__u32 pos, __u32 expect, __u32 *count); +typedef int (*check_output_fn)(unsigned char *buf, unsigned int size, void *opaque); + +/* for block interface */ +int hw_blk_compress(int alg_type, int blksize, __u8 data_fmt, void *priv, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen); + +int hw_blk_decompress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen); + +/* for stream memory interface */ +int hw_stream_compress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen); + +int hw_stream_decompress(int alg_type, int blksize, __u8 data_fmt, + unsigned char *dst, __u32 *dstlen, + unsigned char *src, __u32 srclen); + +#ifdef USE_ZLIB +int hizip_check_output(void *buf, size_t size, size_t *checked, + check_output_fn check_output, void *opaque); +int zlib_deflate(void *output, unsigned int out_size, + void *input, unsigned int in_size, unsigned long *produced, + int alg_type); +#else +static inline int hizip_check_output(void *buf, size_t size, size_t *checked, + check_output_fn check_output, + void *opaque) +{ + static bool printed = false; + + if (!printed) { + WD_ERR("no zlib available, output buffer won't be checked\n"); + printed = true; + } + return -ENOSYS; +} +static inline int zlib_deflate(void *output, unsigned int out_size, void *input, + unsigned int in_size, unsigned long *produced, + int alg_type) +{ + WD_ERR("no zlib available\n"); + return -ENOSYS; +} +#endif + +static inline void hizip_test_adjust_len(struct test_options *opts) +{ + /* + * Align size to the next block. We allow non-power-of-two block sizes. + */ + opts->total_len = (opts->total_len + opts->block_size - 1) / + opts->block_size * opts->block_size; +} + +#define COMMON_OPTSTRING "hb:n:q:l:FSs:Vvzt:m:dacLZ" + +#define COMMON_HELP "%s [opts]\n" \ + " -b <size> block size\n" \ + " -n <num> number of runs\n" \ + " -q <num> number of queues\n" \ + " -l <num> number of compact runs\n" \ + " -F input file, default no input\n" \ + " -S stream mode, default block mode\n" \ + " -s <size> total size\n" \ + " -V verify output\n" \ + " -v display detailed performance information\n" \ + " -a test deflate algorithm, default gzip\n" \ + " -z test zlib algorithm, default gzip\n" \ + " -t <num> number of thread per process\n" \ + " -m <mode> mode of queues: 0 sync, 1 async\n" \ + " -d test decompression, default compression\n" \ + " -c use cpu to do zlib\n" \ + " -L test sgl type buffer, default pbuffer\n" \ + " -Z test lz77_zstd algorithm, default gzip\n" \ + "\n\n" + +int parse_common_option(const char opt, const char *optarg, + struct test_options *opts); +#endif /* TEST_LIB_H_ */ diff --git a/uadk_tool/test/comp_main.c b/uadk_tool/test/comp_main.c new file mode 100644 index 0000000..a21a952 --- /dev/null +++ b/uadk_tool/test/comp_main.c @@ -0,0 +1,1843 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved. + * Copyright 2020-2021 Linaro ltd. + */ +#include <linux/perf_event.h> +#include <asm/unistd.h> /* For __NR_perf_event_open */ +#include <fenv.h> +#include <getopt.h> +#include <inttypes.h> +#include <math.h> +#include <signal.h> +#include <time.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "comp_lib.h" + +#define POLL_STRING_LEN 128 + +enum hizip_stats_variable { + ST_SETUP_TIME, + ST_RUN_TIME, + ST_CPU_TIME, + + /* CPU usage */ + ST_USER_TIME, + ST_SYSTEM_TIME, + + /* Faults */ + ST_MINFLT, + ST_MAJFLT, + + /* Context switches */ + ST_INVCTX, + ST_VCTX, + + /* Signals */ + ST_SIGNALS, + + /* Aggregated */ + ST_SPEED, + ST_TOTAL_SPEED, + ST_CPU_IDLE, + ST_FAULTS, + ST_IOPF, + + ST_COMPRESSION_RATIO, + + NUM_STATS +}; + +struct hizip_stats { + double v[NUM_STATS]; +}; + +extern int perf_event_open(struct perf_event_attr *attr, + pid_t pid, int cpu, int group_fd, + unsigned long flags); +extern int perf_event_get(const char *event_name, int **perf_fds, int *nr_fds); +extern unsigned long long perf_event_put(int *perf_fds, int nr_fds); +extern void stat_setup(struct hizip_test_info *info); +extern void stat_start(struct hizip_test_info *info); +extern void stat_end(struct hizip_test_info *info); + +static size_t count_chunk_list_sz(chunk_list_t *list) +{ + size_t sum = 0; + chunk_list_t *p; + + for (p = list; p; p = p->next) + sum += p->size; + return sum; +} + +static void *sw_dfl_hw_ifl(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_ifl; + void *tbuf; + size_t tbuf_sz; + chunk_list_t *tlist; + comp_md5_t final_md5 = {{0}}; + int i, ret; + __u32 tout_sz; + + tbuf_sz = tdata->src_sz * EXPANSION_RATIO; + tbuf = mmap_alloc(tbuf_sz); + if (!tbuf) + return (void *)(uintptr_t)(-ENOMEM); + tlist = create_chunk_list(tbuf, tbuf_sz, + info->in_chunk_sz * EXPANSION_RATIO); + if (!tlist) { + ret = -ENOMEM; + goto out; + } + if (opts->option & PERFORMANCE) { + /* hack: + * memset buffer and trigger page fault early in the cpu + * instead of later in the SMMU + * Enhance performance in sva case + * no impact to non-sva case + */ + memset(tbuf, 5, tbuf_sz); + } + if (opts->is_stream) { + /* STREAM mode: only one entry in the list */ + init_chunk_list(tdata->in_list, tdata->src, + tdata->src_sz, tdata->src_sz); + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tlist, tbuf, tbuf_sz, tbuf_sz); + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, tdata->dst_sz); + ret = sw_deflate2(tdata->in_list, tlist, opts); + if (ret) { + printf("Fail to deflate by zlib: %d\n", ret); + goto out_strm; + } + tout_sz = tdata->dst_sz; + ret = hw_stream_decompress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tlist->addr, + tlist->size); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out_strm; + } + ret = calculate_md5(&tdata->md5, tdata->in_list->addr, + tdata->in_list->size); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_strm; + } + ret = calculate_md5(&final_md5, tdata->out_list->addr, + tout_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_strm; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out_strm; + } + } + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + return NULL; + } + + /* BLOCK mode */ + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_DECOMPRESS; + + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_ifl = wd_comp_alloc_sess(&setup); + if (!h_ifl) { + ret = -EINVAL; + goto out_strm; + } + + init_chunk_list(tdata->in_list, tdata->src, tdata->src_sz, + info->in_chunk_sz); + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tlist, tbuf, tbuf_sz, + info->in_chunk_sz * EXPANSION_RATIO); + init_chunk_list(tdata->out_list, tdata->dst, tdata->dst_sz, + info->out_chunk_sz); + ret = sw_deflate2(tdata->in_list, tlist, opts); + if (ret) { + printf("Fail to deflate by zlib: %d\n", ret); + goto out_run; + } + ret = hw_inflate4(h_ifl, tlist, tdata->out_list, opts, + &tdata->sem); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out_run; + } + ret = calculate_md5(&tdata->md5, tdata->src, tdata->src_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = calculate_md5(&final_md5, tdata->dst, tdata->dst_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out_run; + } + } + wd_comp_free_sess(h_ifl); + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out_run: + wd_comp_free_sess(h_ifl); +out_strm: + free_chunk_list(tlist); +out: + mmap_free(tbuf, tbuf_sz); + return (void *)(uintptr_t)(ret); +} + +static void *hw_dfl_sw_ifl(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_dfl; + void *tbuf; + size_t tbuf_sz; + chunk_list_t *tlist; + comp_md5_t final_md5 = {{0}}; + int i, ret; + __u32 tmp_sz; + + tbuf_sz = tdata->src_sz * EXPANSION_RATIO; + tbuf = mmap_alloc(tbuf_sz); + if (!tbuf) + return (void *)(uintptr_t)(-ENOMEM); + tlist = create_chunk_list(tbuf, tbuf_sz, + opts->block_size * EXPANSION_RATIO); + if (!tlist) { + ret = -ENOMEM; + goto out; + } + if (opts->option & PERFORMANCE) { + /* hack: + * memset buffer and trigger page fault early in the cpu + * instead of later in the SMMU + * Enhance performance in sva case + * no impact to non-sva case + */ + memset(tbuf, 5, tbuf_sz); + } + if (opts->is_stream) { + /* STREAM mode: only one entry in the list */ + init_chunk_list(tdata->in_list, tdata->src, + tdata->src_sz, tdata->src_sz); + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tlist, tbuf, tbuf_sz, tbuf_sz); + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, tdata->dst_sz); + tmp_sz = tbuf_sz; + ret = hw_stream_compress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tlist->addr, + &tmp_sz, + tdata->src, + tdata->src_sz); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out_strm; + } + tlist->size = tmp_sz; // write back + ret = sw_inflate2(tlist, tdata->out_list, opts); + if (ret) { + printf("Fail to inflate by zlib: %d\n", ret); + goto out_strm; + } + ret = calculate_md5(&tdata->md5, tdata->in_list->addr, + tdata->in_list->size); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_strm; + } + ret = calculate_md5(&final_md5, tdata->out_list->addr, + tdata->out_list->size); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_strm; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out_strm; + } + } + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + return NULL; + } + + /* BLOCK mode */ + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_COMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_dfl = wd_comp_alloc_sess(&setup); + if (!h_dfl) { + ret = -EINVAL; + goto out_strm; + } + + init_chunk_list(tdata->in_list, tdata->src, tdata->src_sz, + info->in_chunk_sz); + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tlist, tbuf, tbuf_sz, + opts->block_size * EXPANSION_RATIO); + init_chunk_list(tdata->out_list, tdata->dst, tdata->dst_sz, + info->out_chunk_sz); + ret = hw_deflate4(h_dfl, tdata->in_list, tlist, opts, + &tdata->sem); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out_run; + } + ret = sw_inflate2(tlist, tdata->out_list, opts); + if (ret) { + printf("Fail to inflate by zlib: %d\n", ret); + goto out_run; + } + ret = calculate_md5(&tdata->md5, tdata->src, tdata->src_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = calculate_md5(&final_md5, tdata->dst, tdata->dst_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out_run; + } + } + wd_comp_free_sess(h_dfl); + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out_run: + wd_comp_free_sess(h_dfl); +out_strm: + free_chunk_list(tlist); +out: + mmap_free(tbuf, tbuf_sz); + return (void *)(uintptr_t)(ret); +} + +static void *hw_dfl_hw_ifl(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_dfl, h_ifl; + void *tbuf; + size_t tbuf_sz; + chunk_list_t *tlist; + comp_md5_t final_md5 = {{0}}; + int i, ret; + __u32 tmp_sz, tout_sz; + + tbuf_sz = tdata->src_sz * EXPANSION_RATIO; + tbuf = mmap_alloc(tbuf_sz); + if (!tbuf) + return (void *)(uintptr_t)(-ENOMEM); + if (opts->option & PERFORMANCE) { + /* hack: + * memset buffer and trigger page fault early in the cpu + * instead of later in the SMMU + * Enhance performance in sva case + * no impact to non-sva case + */ + memset(tbuf, 5, tbuf_sz); + } + if (opts->is_stream) { + for (i = 0; i < opts->compact_run_num; i++) { + tmp_sz = tbuf_sz; + ret = hw_stream_compress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tbuf, + &tmp_sz, + tdata->src, + tdata->src_sz); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out; + } + tout_sz = tdata->dst_sz; + ret = hw_stream_decompress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tbuf, + tmp_sz); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out; + } + ret = calculate_md5(&tdata->md5, tdata->in_list->addr, + tdata->in_list->size); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out; + } + ret = calculate_md5(&final_md5, tdata->dst, tout_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out; + } + } + mmap_free(tbuf, tbuf_sz); + return NULL; + } + + /* BLOCK mode */ + tlist = create_chunk_list(tbuf, tbuf_sz, + opts->block_size * EXPANSION_RATIO); + if (!tlist) { + ret = -ENOMEM; + goto out; + } + + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_COMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_dfl = wd_comp_alloc_sess(&setup); + if (!h_dfl) { + ret = -EINVAL; + goto out_dfl; + } + + setup.op_type = WD_DIR_DECOMPRESS; + param.type = setup.op_type; + setup.sched_param = ¶m; + h_ifl = wd_comp_alloc_sess(&setup); + if (!h_ifl) { + ret = -EINVAL; + goto out_ifl; + } + + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tlist, tbuf, tbuf_sz, + opts->block_size * EXPANSION_RATIO); + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + ret = hw_deflate4(h_dfl, tdata->in_list, tlist, opts, + &tdata->sem); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out_run; + } + ret = hw_inflate4(h_ifl, tlist, tdata->out_list, opts, + &tdata->sem); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out_run; + } + ret = calculate_md5(&tdata->md5, tdata->src, tdata->src_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = calculate_md5(&final_md5, tdata->dst, tdata->dst_sz); + if (ret) { + printf("Fail to generate MD5 (%d)\n", ret); + goto out_run; + } + ret = cmp_md5(&tdata->md5, &final_md5); + if (ret) { + printf("MD5 is unmatched (%d) at %dth times on " + "thread %d\n", ret, i, tdata->tid); + goto out_run; + } + } + wd_comp_free_sess(h_ifl); + wd_comp_free_sess(h_dfl); + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out_run: + wd_comp_free_sess(h_ifl); +out_ifl: + wd_comp_free_sess(h_dfl); +out_dfl: + free_chunk_list(tlist); +out: + mmap_free(tbuf, tbuf_sz); + return (void *)(uintptr_t)(ret); +} + +static void *hw_dfl_perf(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_dfl; + int i, ret; + uint32_t tout_sz; + + if (opts->is_stream) { + for (i = 0; i < opts->compact_run_num; i++) { + tout_sz = tdata->dst_sz; + ret = hw_stream_compress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tdata->src, + tdata->src_sz); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + return (void *)(uintptr_t)ret; + } + } + tdata->out_list->addr = tdata->dst; + tdata->out_list->size = tout_sz; + tdata->out_list->next = NULL; + return NULL; + } + + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_COMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_dfl = wd_comp_alloc_sess(&setup); + if (!h_dfl) + return (void *)(uintptr_t)(-EINVAL); + + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + ret = hw_deflate4(h_dfl, tdata->in_list, tdata->out_list, opts, + &tdata->sem); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out; + } + } + wd_comp_free_sess(h_dfl); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out: + wd_comp_free_sess(h_dfl); + return (void *)(uintptr_t)(ret); +} + +static void *hw_ifl_perf(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_ifl; + int i, ret; + uint32_t tout_sz; + + if (opts->is_stream) { + for (i = 0; i < opts->compact_run_num; i++) { + tout_sz = tdata->dst_sz; + ret = hw_stream_decompress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tdata->in_list->addr, + tdata->in_list->size); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + return (void *)(uintptr_t)ret; + } + tdata->out_list->addr = tdata->dst; + tdata->out_list->size = tout_sz; + tdata->out_list->next = NULL; + } + return NULL; + } + + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_DECOMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_ifl = wd_comp_alloc_sess(&setup); + if (!h_ifl) + return (void *)(uintptr_t)(-EINVAL); + + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + ret = hw_inflate4(h_ifl, tdata->in_list, tdata->out_list, opts, + &tdata->sem); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out; + } + } + wd_comp_free_sess(h_ifl); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out: + wd_comp_free_sess(h_ifl); + return (void *)(uintptr_t)(ret); +} + +/* BATCH mode is used */ +void *hw_dfl_perf3(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_dfl; + int i, ret; + uint32_t tout_sz; + + if (opts->is_stream) { + for (i = 0; i < opts->compact_run_num; i++) { + tout_sz = tdata->dst_sz; + ret = hw_stream_compress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tdata->src, + tdata->src_sz); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + return (void *)(uintptr_t)ret; + } + } + tdata->out_list->addr = tdata->dst; + tdata->out_list->size = tout_sz; + tdata->out_list->next = NULL; + return NULL; + } + + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_COMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_dfl = wd_comp_alloc_sess(&setup); + if (!h_dfl) + return (void *)(uintptr_t)(-EINVAL); + + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + ret = hw_deflate5(h_dfl, tdata->in_list, tdata->out_list, + tdata); + if (ret) { + printf("Fail to deflate by HW: %d\n", ret); + goto out; + } + } + wd_comp_free_sess(h_dfl); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out: + wd_comp_free_sess(h_dfl); + return (void *)(uintptr_t)(ret); +} + +/* BATCH mode is used */ +void *hw_ifl_perf3(void *arg) +{ + thread_data_t *tdata = (thread_data_t *)arg; + struct hizip_test_info *info = tdata->info; + struct test_options *opts = info->opts; + struct wd_comp_sess_setup setup = {0}; + struct sched_params param = {0}; + handle_t h_ifl; + int i, ret; + uint32_t tout_sz; + + if (opts->is_stream) { + for (i = 0; i < opts->compact_run_num; i++) { + tout_sz = tdata->dst_sz; + ret = hw_stream_decompress(opts->alg_type, + opts->block_size, + opts->data_fmt, + tdata->dst, + &tout_sz, + tdata->src, + tdata->src_sz); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + return (void *)(uintptr_t)ret; + } + tdata->out_list->addr = tdata->dst; + tdata->out_list->size = tout_sz; + tdata->out_list->next = NULL; + } + return NULL; + } + + setup.alg_type = opts->alg_type; + setup.op_type = WD_DIR_DECOMPRESS; + param.type = setup.op_type; + param.numa_id = 0; + setup.sched_param = ¶m; + h_ifl = wd_comp_alloc_sess(&setup); + if (!h_ifl) + return (void *)(uintptr_t)(-EINVAL); + + for (i = 0; i < opts->compact_run_num; i++) { + init_chunk_list(tdata->out_list, tdata->dst, + tdata->dst_sz, + info->out_chunk_sz); + ret = hw_inflate5(h_ifl, tdata->in_list, tdata->out_list, + tdata); + if (ret) { + printf("Fail to inflate by HW: %d\n", ret); + goto out; + } + } + wd_comp_free_sess(h_ifl); + /* mark sending thread to end */ + __atomic_add_fetch(&sum_thread_end, 1, __ATOMIC_ACQ_REL); + return NULL; +out: + wd_comp_free_sess(h_ifl); + return (void *)(uintptr_t)(ret); +} + +/* + * Load both ilist file. + */ +int load_ilist(struct hizip_test_info *info, char *model) +{ + struct test_options *opts = info->opts; + thread_data_t *tdata = &info->tdatas[0]; + chunk_list_t *p; + size_t sum = 0; + ssize_t file_sz = 0; + void *addr; + + if (!strcmp(model, "hw_ifl_perf")) { + if (!opts->is_stream) { + if (opts->fd_ilist < 0) { + printf("Missing IN list file!\n"); + return -EINVAL; + } + p = tdata->in_list; + addr = info->in_buf; + while (p) { + file_sz = read(opts->fd_ilist, p, + sizeof(chunk_list_t)); + if (file_sz < 0) + return -EFAULT; + p->addr = addr; + sum += file_sz; + if (p->next) + p->next = p + 1; + addr += p->size; + p = p->next; + } + } + } + return (int)sum; +} + +/* + * Load compression/decompression content. + */ +int load_file_data(struct hizip_test_info *info) +{ + struct test_options *opts = info->opts; + size_t file_sz; + + file_sz = read(opts->fd_in, info->in_buf, info->in_size); + if (file_sz < info->in_size) { + printf("Expect to read %ld bytes. " + "But only read %ld bytes!\n", + info->in_size, file_sz); + return -EFAULT; + } + return (int)file_sz; +} + +/* + * Store both olist file. opts->is_file must be enabled first. + */ +int store_olist(struct hizip_test_info *info, char *model) +{ + struct test_options *opts = info->opts; + thread_data_t *tdata = &info->tdatas[0]; + chunk_list_t *p; + size_t sum = 0; + ssize_t file_sz = 0; + + if (!opts->is_stream) { + if (opts->fd_olist >= 0) { + /* compress with BLOCK */ + p = tdata->out_list; + while (p) { + file_sz = write(opts->fd_olist, p, + sizeof(chunk_list_t)); + if (file_sz < sizeof(chunk_list_t)) + return -EFAULT; + file_sz = write(opts->fd_out, p->addr, + p->size); + if (file_sz < p->size) + return -EFAULT; + p = p->next; + sum += file_sz; + } + } else { + /* decompress with BLOCK */ + p = tdata->out_list; + while (p) { + file_sz = write(opts->fd_out, p->addr, + p->size); + if (file_sz < p->size) + return -EFAULT; + p = p->next; + sum += file_sz; + } + } + } else if (opts->is_stream) { + p = tdata->out_list; + file_sz = write(opts->fd_out, p->addr, p->size); + if (file_sz < p->size) + return -EFAULT; + sum = file_sz; + } + return (int)sum; +} + +static int nonenv_resource_init(struct test_options *opts, + struct hizip_test_info *info, + struct wd_sched **sched) +{ + int ret; + + info->list = get_dev_list(opts, 1); + if (!info->list) + return -EINVAL; + ret = init_ctx_config(opts, info, sched); + if (ret < 0) { + wd_free_list_accels(info->list); + return ret; + } + return 0; +} + +static void nonenv_resource_uninit(struct test_options *opts, + struct hizip_test_info *info, + struct wd_sched *sched) +{ + uninit_config(info, sched); + wd_free_list_accels(info->list); +} + +static bool event_unavailable = false; + +int test_hw(struct test_options *opts, char *model) +{ + struct hizip_test_info info = {0}; + struct wd_sched *sched = NULL; + double ilen, usec, speed; + char zbuf[120]; + int ret, zbuf_idx, ifl_flag = 0; + void *(*func)(void *); + size_t tbuf_sz = 0; + void *tbuf = NULL; + struct stat statbuf; + chunk_list_t *tlist = NULL; + int div; + __u32 num; + __u8 enable; + int nr_fds = 0; + int *perf_fds = NULL; + struct hizip_stats stats; + + if (!opts || !model) { + ret = -EINVAL; + goto out; + } + info.opts = opts; + info.stats = &stats; + + if (!event_unavailable && + perf_event_get("iommu/dev_fault", &perf_fds, &nr_fds)) { + printf("IOPF statistic unavailable\n"); + /* No need to retry and print an error on every run */ + event_unavailable = true; + } + stat_setup(&info); + + memset(zbuf, 0, 120); + if (!strcmp(model, "sw_dfl_hw_ifl")) { + func = sw_dfl_hw_ifl; + info.in_size = opts->total_len; + if (opts->is_stream) + info.out_size = opts->total_len; + else + info.out_size = opts->total_len; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size; + zbuf_idx = sprintf(zbuf, "Mix SW deflate and HW %s %s inflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + } else if (!strcmp(model, "hw_dfl_sw_ifl")) { + func = hw_dfl_sw_ifl; + info.in_size = opts->total_len; + info.out_size = opts->total_len; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size; + zbuf_idx = sprintf(zbuf, "Mix HW %s %s deflate and SW inflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + } else if (!strcmp(model, "hw_dfl_hw_ifl")) { + func = hw_dfl_hw_ifl; + info.in_size = opts->total_len; + if (opts->is_stream) + info.out_size = opts->total_len; + else + info.out_size = opts->total_len; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size; + zbuf_idx = sprintf(zbuf, + "Mix HW %s %s deflate and HW %s %s inflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + } else if (!strcmp(model, "hw_dfl_perf")) { + func = hw_dfl_perf; + info.in_size = opts->total_len; + info.out_size = opts->total_len * EXPANSION_RATIO; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size * EXPANSION_RATIO; + zbuf_idx = sprintf(zbuf, "HW %s %s deflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + } else if (!strcmp(model, "hw_dfl_perf3")) { + func = hw_dfl_perf3; + info.in_size = opts->total_len; + info.out_size = opts->total_len * EXPANSION_RATIO; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size * EXPANSION_RATIO; + zbuf_idx = sprintf(zbuf, "HW %s %s deflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + } else if (!strcmp(model, "hw_ifl_perf")) { + func = hw_ifl_perf; + info.in_size = opts->total_len; + info.out_size = opts->total_len * INFLATION_RATIO; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size * INFLATION_RATIO; + zbuf_idx = sprintf(zbuf, "HW %s %s inflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + ifl_flag = 1; + } else if (!strcmp(model, "hw_ifl_perf3")) { + func = hw_ifl_perf3; + info.in_size = opts->total_len * EXPANSION_RATIO; + info.out_size = opts->total_len; + info.in_chunk_sz = opts->block_size; + info.out_chunk_sz = opts->block_size * INFLATION_RATIO; + zbuf_idx = sprintf(zbuf, "HW %s %s inflate", + opts->sync_mode ? "ASYNC" : "SYNC", + opts->is_stream ? "STREAM" : "BLOCK"); + ifl_flag = 1; + } else { + printf("Wrong model is specified:%s\n", model); + ret = -EINVAL; + goto out; + } + + if (opts->use_env) + ret = wd_comp_env_init(NULL); + else + ret = nonenv_resource_init(opts, &info, &sched); + if (ret < 0) + goto out; + + if (opts->faults & INJECT_SIG_BIND) + kill(getpid(), SIGTERM); + + if (opts->use_env) { + ret = wd_comp_get_env_param(0, opts->op_type, opts->sync_mode, &num, &enable); + if (ret < 0) + goto out; + } + + if (opts->is_file) { + ret = fstat(opts->fd_in, &statbuf); + if (ret < 0) + goto out_src; + opts->total_len = statbuf.st_size; + info.in_size = opts->total_len; + if (ifl_flag) + info.out_size = opts->total_len * INFLATION_RATIO; + else + info.out_size = opts->total_len * EXPANSION_RATIO; + /* + * If fd_ilist exists, it's inflation. + * Make sure block inflation has enough room. + */ + if (opts->fd_ilist >= 0) { + ret = fstat(opts->fd_ilist, &statbuf); + if (!ret) { + div = statbuf.st_size / sizeof(chunk_list_t); + info.in_chunk_sz = (info.in_size + div - 1) / + div; + info.out_chunk_sz = (info.out_size + div - 1) / + div; + } + } + } + info.in_buf = mmap_alloc(info.in_size); + if (!info.in_buf) { + ret = -ENOMEM; + goto out_src; + } + ret = create_send_tdata(opts, &info); + if (ret) + goto out_send; + ret = create_poll_tdata(opts, &info, opts->poll_num); + if (ret) + goto out_poll; + if (opts->is_file) { + /* in_list is created by create_send3_threads(). */ + ret = load_file_data(&info); + if (ret < 0) + goto out_buf; + ret = load_ilist(&info, model); + if (ret < 0) + goto out_buf; + } else { + if (ifl_flag) { + thread_data_t *tdata = info.tdatas; + tbuf_sz = info.in_size / EXPANSION_RATIO; + tbuf = mmap_alloc(tbuf_sz); + if (!tbuf) { + ret = -ENOMEM; + goto out_buf; + } + tlist = create_chunk_list(tbuf, tbuf_sz, + opts->block_size / + EXPANSION_RATIO); + init_chunk_list(tlist, tbuf, tbuf_sz, + opts->block_size / EXPANSION_RATIO); + gen_random_data(tbuf, tbuf_sz); + ret = sw_deflate2(tlist, tdata[0].in_list, opts); + if (ret) { + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + goto out_buf; + } + free_chunk_list(tlist); + mmap_free(tbuf, tbuf_sz); + } else + gen_random_data(info.in_buf, info.in_size); + } + if (opts->faults & INJECT_TLB_FAULT) { + /* + * Now unmap the buffers and retry the access. Normally we + * should get an access fault, but if the TLB wasn't properly + * invalidated, the access succeeds and corrupts memory! + * This test requires small jobs, to make sure that we reuse + * the same TLB entry between the tests. Run for example with + * "-s 0x1000 -b 0x1000". + */ + ret = munmap(info.in_buf, info.in_size); + if (ret) { + printf("Failed to unmap."); + goto out_buf; + } + /* A warning if the parameters might produce false positives */ + if (opts->total_len > 0x54000) + fprintf(stderr, "NOTE: test might trash the TLB\n"); + } + stat_start(&info); + ret = attach2_threads(opts, &info, func, poll2_thread_func); + if (ret) + goto out_buf; + stat_end(&info); + info.stats->v[ST_IOPF] = perf_event_put(perf_fds, nr_fds); + if (opts->is_file) + store_olist(&info, model); + + usec = info.stats->v[ST_RUN_TIME] / 1000; + if (opts->op_type == WD_DIR_DECOMPRESS) + ilen = (float)count_chunk_list_sz(info.tdatas[0].out_list); + else + ilen = opts->total_len; + ilen *= opts->thread_num * opts->compact_run_num; + speed = ilen * 1000 * 1000 / 1024 / 1024 / usec; + if (opts->sync_mode) { + zbuf_idx += sprintf(zbuf + zbuf_idx, + " with %d send + %d poll threads", + opts->thread_num, + opts->poll_num); + } else { + zbuf_idx += sprintf(zbuf + zbuf_idx, + " with %d send threads", + opts->thread_num); + } + if (!strcmp(model, "hw_dfl_perf") || !strcmp(model, "hw_ifl_perf") || + !strcmp(model, "hw_dfl_perf3") || !strcmp(model, "hw_ifl_perf3")) { + printf("%s at %.2fMB/s in %f usec (BLK:%d, Bnum:%d).\n", + zbuf, speed, usec, opts->block_size, opts->batch_num); + } else { + printf("%s in %f usec (BLK:%d, Bnum:%d).\n", + zbuf, usec, opts->block_size, opts->batch_num); + } + free2_threads(&info); + if (opts->use_env) + wd_comp_env_uninit(); + else + nonenv_resource_uninit(opts, &info, sched); + usleep(1000); + return 0; +out_buf: +out_poll: + free2_threads(&info); + if (opts->use_env) + wd_comp_env_uninit(); + else + nonenv_resource_uninit(opts, &info, sched); + printf("Fail to run %s() (%d)!\n", model, ret); + return ret; +out_send: + mmap_free(info.in_buf, info.in_size); +out_src: + if (opts->use_env) + wd_comp_env_uninit(); + else + nonenv_resource_uninit(opts, &info, sched); +out: + printf("Fail to run %s() (%d)!\n", model, ret); + return ret; +} + +int run_self_test(struct test_options *opts) +{ + int i, f_ret = 0; + char poll_str[POLL_STRING_LEN]; + + printf("Start to run self test!\n"); + opts->alg_type = WD_ZLIB; + opts->data_fmt = WD_FLAT_BUF; + opts->sync_mode = 0; + opts->q_num = 16; + for (i = 0; i < 10; i++) { + opts->sync_mode = 0; + switch (i) { + case 0: + opts->thread_num = 1; + break; + case 1: + opts->thread_num = 2; + break; + case 2: + opts->thread_num = 4; + break; + case 3: + opts->thread_num = 8; + break; + case 4: + opts->thread_num = 16; + break; + case 5: + opts->thread_num = 1; + opts->is_stream = 1; + break; + case 6: + opts->thread_num = 2; + opts->is_stream = 1; + break; + case 7: + opts->thread_num = 4; + opts->is_stream = 1; + break; + case 8: + opts->thread_num = 8; + opts->is_stream = 1; + break; + case 9: + opts->thread_num = 16; + opts->is_stream = 1; + break; + } + f_ret |= test_hw(opts, "hw_dfl_perf"); + f_ret |= test_hw(opts, "hw_ifl_perf"); + } + opts->is_stream = 0; /* restore to BLOCK mode */ + for (i = 0; i < 5; i++) { + opts->thread_num = 8; + switch (i) { + case 0: + opts->sync_mode = 0; + break; + case 1: + opts->sync_mode = 1; opts->poll_num = 1; + break; + case 2: + opts->sync_mode = 1; opts->poll_num = 2; + break; + case 3: + opts->sync_mode = 1; opts->poll_num = 4; + break; + case 4: + opts->sync_mode = 1; opts->poll_num = 8; + break; + default: + return -EINVAL; + } + if (opts->use_env && opts->poll_num) { + memset(poll_str, 0, POLL_STRING_LEN); + sprintf(poll_str, + "sync-comp:8@0,sync-decomp:8@0," + "async-comp:8@0,async-decomp:8@0"); + setenv("WD_COMP_CTX_NUM", poll_str, 1); + memset(poll_str, 0, POLL_STRING_LEN); + sprintf(poll_str, "%d@0", opts->poll_num), + setenv("WD_COMP_ASYNC_POLL_NUM", poll_str, 1); + } + f_ret |= test_hw(opts, "sw_dfl_hw_ifl"); + f_ret |= test_hw(opts, "hw_dfl_sw_ifl"); + f_ret |= test_hw(opts, "hw_dfl_hw_ifl"); + f_ret |= test_hw(opts, "hw_dfl_perf"); + f_ret |= test_hw(opts, "hw_ifl_perf"); + } + if (!f_ret) + printf("Run self test successfully!\n"); + return f_ret; +} + +static int set_default_opts(struct test_options *opts) +{ + if (!opts->block_size) + opts->block_size = 8192; + if (!opts->total_len) { + if (opts->block_size) + opts->total_len = opts->block_size * 10; + else + opts->total_len = 8192 * 10; + } + if (!opts->thread_num) + opts->thread_num = 1; + if (!opts->q_num) + opts->q_num = opts->thread_num; + if (!opts->compact_run_num) + opts->compact_run_num = 1; + if (!opts->poll_num) + opts->poll_num = 1; + if (opts->alg_type == WD_COMP_ALG_MAX) + opts->alg_type = WD_GZIP; + return 0; +} + +static int run_one_cmd(struct test_options *opts) +{ + int ret; + + if (opts->op_type == WD_DIR_COMPRESS) { + if (opts->verify) + ret = test_hw(opts, "hw_dfl_sw_ifl"); + else + ret = test_hw(opts, "hw_dfl_perf"); + } else { + if (opts->verify) + ret = test_hw(opts, "sw_dfl_hw_ifl"); + else + ret = test_hw(opts, "hw_ifl_perf"); + } + return ret; +} + +int run_cmd(struct test_options *opts) +{ + int ret = 0, i; + int nr_children = 0, status; + pid_t pid, *pids = NULL; + bool success = true; + + set_default_opts(opts); + if (opts->children) { + pids = calloc(opts->children, sizeof(pid_t)); + if (!pids) + return -ENOMEM; + for (i = 0; i < opts->children; i++) { + pid = fork(); + if (pid < 0) { + printf("cannot fork: %d\n", errno); + success = false; + break; + } else if (pid > 0) { + /* Parent */ + pids[nr_children++] = pid; + continue; + } + /* Child */ + ret = run_one_cmd(opts); + return ret; + } + for (i = 0; i < nr_children; i++) { + pid = pids[i]; + ret = waitpid(pid, &status, 0); + if (ret < 0) { + printf("wait(pid=%d) error %d\n", pid, errno); + success = false; + continue; + } + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + if (ret) { + printf("child %d returned with %d\n", + pid, ret); + success = false; + } + } else if (WIFSIGNALED(status)) { + ret = WTERMSIG(status); + printf("child %d killed by sig %d\n", pid, ret); + success = false; + } else { + printf("unexpected status for child %d\n", pid); + success = false; + } + } + if (success == false) { + printf("Failed to run spawn test!\n"); + if (!ret) + ret = -EINVAL; + } + } else + ret = run_one_cmd(opts); + return ret; +} + +int perf_event_open(struct perf_event_attr *attr, + pid_t pid, int cpu, int group_fd, + unsigned long flags) +{ + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +unsigned long long perf_event_put(int *perf_fds, int nr_fds); + +int perf_event_get(const char *event_name, int **perf_fds, int *nr_fds) +{ + int ret; + int cpu; + FILE *fd; + int nr_cpus; + unsigned int event_id; + char event_id_file[256]; + struct perf_event_attr event = { + .type = PERF_TYPE_TRACEPOINT, + .size = sizeof(event), + .disabled = true, + }; + + *perf_fds = NULL; + *nr_fds = 0; + + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (nr_cpus <= 0) { + WD_ERR("invalid number of CPUs\n"); + return nr_cpus; + } + + ret = snprintf(event_id_file, sizeof(event_id_file), + "/sys/kernel/debug/tracing/events/%s/id", event_name); + if (ret >= sizeof(event_id_file)) { + WD_ERR("event_id buffer overflow\n"); + return -EOVERFLOW; + } + fd = fopen(event_id_file, "r"); + if (fd == NULL) { + ret = -errno; + WD_ERR("Couldn't open file %s\n", event_id_file); + return ret; + } + + if (fscanf(fd, "%d", &event_id) != 1) { + WD_ERR("Couldn't parse file %s\n", event_id_file); + return -EINVAL; + } + fclose(fd); + event.config = event_id; + + *perf_fds = calloc(nr_cpus, sizeof(int)); + if (!*perf_fds) + return -ENOMEM; + *nr_fds = nr_cpus; + + /* + * An event is bound to either a CPU or a PID. If we want both, we need + * to open the event on all CPUs. Note that we can't use a perf group + * since they have to be on the same CPU. + */ + for (cpu = 0; cpu < nr_cpus; cpu++) { + int fd = perf_event_open(&event, -1, cpu, -1, 0); + + if (fd < 0) { + WD_ERR("Couldn't get perf event %s on CPU%d: %d\n", + event_name, cpu, errno); + perf_event_put(*perf_fds, cpu); + return fd; + } + + ioctl(fd, PERF_EVENT_IOC_RESET, 0); + ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); + (*perf_fds)[cpu] = fd; + } + + return 0; +} + +/* + * Closes the perf fd and return the sample count. If it wasn't open, return 0. + */ +unsigned long long perf_event_put(int *perf_fds, int nr_fds) +{ + int ret; + int cpu; + uint64_t count, total = 0; + + if (!perf_fds) + return 0; + + for (cpu = 0; cpu < nr_fds; cpu++) { + int fd = perf_fds[cpu]; + + if (fd <= 0) { + WD_ERR("Invalid perf fd %d\n", cpu); + continue; + } + + ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); + + ret = read(fd, &count, sizeof(count)); + if (ret < sizeof(count)) + WD_ERR("Couldn't read perf event for CPU%d\n", cpu); + + total += count; + close(fd); + + } + + free(perf_fds); + return total; +} + +static void set_thp(struct test_options *opts) +{ + char *p; + char s[14]; + FILE *file; + + file = fopen("/sys/kernel/mm/transparent_hugepage/enabled", "r"); + if (!file) + goto out_err; + p = fgets(s, 14, file); + fclose(file); + if (!p) + goto out_err; + + if (strcmp(s, "never") == 0) { + printf("Cannot test THP with enable=never\n"); + return; + } + + file = fopen("/sys/kernel/mm/transparent_hugepage/defrag", "r"); + if (!file) + goto out_err; + p = fgets(s, 14, file); + fclose(file); + if (!p) + goto out_err; + + if (strcmp(s, "defer") == 0 || strcmp(s, "never") == 0) { + printf("Cannot test THP with defrag=%s\n", s); + return; + } + + return; +out_err: + printf("THP unsupported?\n"); +} + +void stat_setup(struct hizip_test_info *info) +{ + clock_gettime(CLOCK_MONOTONIC_RAW, &info->tv.setup_time); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &info->tv.setup_cputime); + getrusage(RUSAGE_SELF, &info->tv.setup_rusage); +} + +void stat_start(struct hizip_test_info *info) +{ + clock_gettime(CLOCK_MONOTONIC_RAW, &info->tv.start_time); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &info->tv.start_cputime); + getrusage(RUSAGE_SELF, &info->tv.start_rusage); +} + +void stat_end(struct hizip_test_info *info) +{ + struct test_options *opts = info->opts; + struct hizip_stats *stats = info->stats; + double v; + size_t total_out; + unsigned long total_len; + + total_out = __atomic_load_n(&info->total_out, __ATOMIC_ACQUIRE); + clock_gettime(CLOCK_MONOTONIC_RAW, &info->tv.end_time); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &info->tv.end_cputime); + getrusage(RUSAGE_SELF, &info->tv.end_rusage); + + stats->v[ST_SETUP_TIME] = (info->tv.start_time.tv_sec - + info->tv.setup_time.tv_sec) * 1000000000 + + info->tv.start_time.tv_nsec - + info->tv.setup_time.tv_nsec; + stats->v[ST_RUN_TIME] = (info->tv.end_time.tv_sec - + info->tv.start_time.tv_sec) * 1000000000 + + info->tv.end_time.tv_nsec - + info->tv.start_time.tv_nsec; + + stats->v[ST_CPU_TIME] = (info->tv.end_cputime.tv_sec - + info->tv.setup_cputime.tv_sec) * 1000000000 + + info->tv.end_cputime.tv_nsec - + info->tv.setup_cputime.tv_nsec; + stats->v[ST_USER_TIME] = (info->tv.end_rusage.ru_utime.tv_sec - + info->tv.setup_rusage.ru_utime.tv_sec) * + 1000000 + + info->tv.end_rusage.ru_utime.tv_usec - + info->tv.setup_rusage.ru_utime.tv_usec; + stats->v[ST_SYSTEM_TIME] = (info->tv.end_rusage.ru_stime.tv_sec - + info->tv.setup_rusage.ru_stime.tv_sec) * + 1000000 + + info->tv.end_rusage.ru_stime.tv_usec - + info->tv.setup_rusage.ru_stime.tv_usec; + + stats->v[ST_MINFLT] = info->tv.end_rusage.ru_minflt - + info->tv.setup_rusage.ru_minflt; + stats->v[ST_MAJFLT] = info->tv.end_rusage.ru_majflt - + info->tv.setup_rusage.ru_majflt; + + stats->v[ST_VCTX] = info->tv.end_rusage.ru_nvcsw - + info->tv.setup_rusage.ru_nvcsw; + stats->v[ST_INVCTX] = info->tv.end_rusage.ru_nivcsw - + info->tv.setup_rusage.ru_nivcsw; + + stats->v[ST_SIGNALS] = info->tv.end_rusage.ru_nsignals - + info->tv.setup_rusage.ru_nsignals; + + /* check last loop is enough, same as below hizip_verify_output */ + stats->v[ST_COMPRESSION_RATIO] = (double)opts->total_len / + total_out * 100; + + total_len = opts->total_len * opts->compact_run_num; + /* ST_RUN_TIME records nanoseconds */ + stats->v[ST_SPEED] = (total_len * opts->thread_num * 1000) / + (1.024 * 1.024 * stats->v[ST_RUN_TIME]); + + stats->v[ST_TOTAL_SPEED] = (total_len * opts->thread_num * 1000) / + ((stats->v[ST_RUN_TIME] + + stats->v[ST_SETUP_TIME]) * 1.024 * 1.024); + + v = stats->v[ST_RUN_TIME] + stats->v[ST_SETUP_TIME]; + stats->v[ST_CPU_IDLE] = (v - stats->v[ST_CPU_TIME]) / v * 100; + stats->v[ST_FAULTS] = stats->v[ST_MAJFLT] + stats->v[ST_MINFLT]; +} + +static void handle_sigbus(int sig) +{ + printf("SIGBUS!\n"); + _exit(0); +} + +int test_comp_entry(int argc, char *argv[]) +{ + struct test_options opts = { + .alg_type = WD_GZIP, + .op_type = WD_DIR_COMPRESS, + .q_num = 1, + .run_num = 1, + .compact_run_num = 1, + .thread_num = 1, + .sync_mode = 0, + .block_size = 512000, + .total_len = opts.block_size * 10, + .verify = false, + .verbose = false, + .is_decomp = false, + .is_stream = false, + .is_file = false, + .display_stats = STATS_PRETTY, + .children = 0, + .faults = 0, + .data_fmt = 0, + }; + struct option long_options[] = { + {"self", no_argument, 0, 0 }, + {"in", required_argument, 0, 0 }, + {"out", required_argument, 0, 0 }, + {"ilist", required_argument, 0, 0 }, + {"olist", required_argument, 0, 0 }, + {"env", no_argument, 0, 0 }, + {0, 0, 0, 0 }, + }; + int show_help = 0; + int opt, option_idx; + int self = 0; + + opts.fd_in = -1; + opts.fd_out = -1; + opts.fd_ilist = -1; + opts.fd_olist = -1; + opts.alg_type = WD_COMP_ALG_MAX; + while ((opt = getopt_long(argc, argv, COMMON_OPTSTRING "f:o:w:k:r:", + long_options, &option_idx)) != -1) { + switch (opt) { + case 0: + switch (option_idx) { + case 0: /* self */ + self = 1; + break; + case 1: /* in */ + if (optarg) { + opts.fd_in = open(optarg, O_RDONLY); + if (opts.fd_in < 0) { + printf("Fail to open %s\n", + optarg); + show_help = 1; + } else + opts.is_file = true; + } else { + printf("Input file is missing!\n"); + show_help = 1; + } + if (lseek(opts.fd_in, 0, SEEK_SET) < 0) { + printf("Fail on lseek()!\n"); + show_help = 1; + } + break; + case 2: /* out */ + if (optarg) { + opts.fd_out = open(optarg, + O_CREAT | O_WRONLY, + S_IWUSR | S_IRGRP | + S_IROTH); + if (opts.fd_out < 0) { + printf("Fail to open %s\n", + optarg); + show_help = 1; + } else + opts.is_file = true; + } else { + printf("Output file is missing!\n"); + show_help = 1; + } + if (lseek(opts.fd_out, 0, SEEK_SET) < 0) { + printf("Fail on lseek()!\n"); + show_help = 1; + } + break; + case 3: /* ilist */ + if (!optarg) { + printf("IN list file is missing!\n"); + show_help = 1; + break; + } + opts.fd_ilist = open(optarg, O_RDONLY); + if (opts.fd_ilist < 0) { + printf("Fail to open %s\n", optarg); + show_help = 1; + break; + } + opts.is_file = true; + if (lseek(opts.fd_ilist, 0, SEEK_SET) < 0) { + printf("Fail on lseek()!\n"); + show_help = 1; + break; + } + break; + case 4: /* olist */ + if (!optarg) { + printf("OUT list file is missing!\n"); + show_help = 1; + break; + } + opts.fd_olist = open(optarg, + O_CREAT | O_WRONLY, + S_IWUSR | S_IRGRP | + S_IROTH); + if (opts.fd_olist < 0) { + printf("Fail to open %s\n", optarg); + show_help = 1; + break; + } + opts.is_file = true; + if (lseek(opts.fd_olist, 0, SEEK_SET) < 0) { + printf("Fail on lseek()!\n"); + show_help = 1; + break; + } + break; + case 5: /* env */ + opts.use_env = true; + break; + default: + show_help = 1; + break; + } + break; + case 'f': + if (strcmp(optarg, "none") == 0) { + opts.display_stats = STATS_NONE; + } else if (strcmp(optarg, "csv") == 0) { + opts.display_stats = STATS_CSV; + } else if (strcmp(optarg, "pretty") == 0) { + opts.display_stats = STATS_PRETTY; + } else { + SYS_ERR_COND(1, "invalid argument to -f: '%s'\n", optarg); + break; + } + break; + case 'o': + switch (optarg[0]) { + case 'p': + opts.option |= PERFORMANCE; + break; + case 't': + opts.option |= TEST_THP; + set_thp(&opts); + break; + default: + SYS_ERR_COND(1, "invalid argument to -o: '%s'\n", optarg); + break; + } + break; + case 'c': + opts.option |= TEST_ZLIB; + break; + case 'r': + opts.children = strtol(optarg, NULL, 0); + if (opts.children < 0) + show_help = 1; + break; + case 'k': + switch (optarg[0]) { + case 'b': + opts.faults |= INJECT_SIG_BIND; + break; + case 't': + opts.faults |= INJECT_TLB_FAULT; + break; + case 'w': + opts.faults |= INJECT_SIG_WORK; + break; + default: + SYS_ERR_COND(1, "invalid argument to -k: '%s'\n", optarg); + break; + } + break; + default: + show_help = parse_common_option(opt, optarg, &opts); + break; + } + } + + signal(SIGBUS, handle_sigbus); + + if (!show_help) { + if (self) + return run_self_test(&opts); + return run_cmd(&opts); + } + + hizip_test_adjust_len(&opts); + + SYS_ERR_COND(show_help || optind > argc, + COMMON_HELP + " -f <format> output format for the statistics\n" + " 'none' do not output statistics\n" + " 'pretty' human readable format\n" + " 'csv' raw, machine readable\n" + " -o <mode> options\n" + " 'perf' prefaults the output pages\n" + " 'thp' try to enable transparent huge pages\n" + " 'zlib' use zlib instead of the device\n" + " -r <children> number of children to create\n" + " -k <mode> kill thread\n" + " 'bind' kills the process after bind\n" + " 'tlb' tries to access an unmapped buffer\n" + " 'work' kills the process while the queue is working\n", + argv[0] + ); + return 0; +} diff --git a/uadk_tool/test/comp_main.h b/uadk_tool/test/comp_main.h new file mode 100644 index 0000000..dcf3980 --- /dev/null +++ b/uadk_tool/test/comp_main.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef TEST_COMP_H +#define TEST_COMP_H + + +int test_comp_entry(int argc, char *argv[]); + +#endif /* TEST_COMP_H */ diff --git a/uadk_tool/test/uadk_test.c b/uadk_tool/test/uadk_test.c index 760cef9..cdb547b 100644 --- a/uadk_tool/test/uadk_test.c +++ b/uadk_tool/test/uadk_test.c @@ -11,6 +11,7 @@ #include <sys/ipc.h> #include <sys/shm.h>
+#include "comp_main.h" #include "test_sec.h"
enum uadk_test_op_type { @@ -23,11 +24,6 @@ int test_hpre_entry(int argc, char *argv[]) return 0; }
-int test_zip_entry(int argc, char *argv[]) -{ - return 0; -} - void print_test_help(void) { printf("NAME\n"); @@ -67,7 +63,7 @@ void acc_test_run(int argc, char *argv[]) } else if (!strcmp(input_module, "sec")) { (void)test_sec_entry(argc, argv); } else if (!strcmp(input_module, "zip")) { - (void)test_zip_entry(argc, argv); + (void)test_comp_entry(argc, argv); } else { print_test_help(); printf("failed to parse module parameter!\n");