From: Hao Fang <fanghao11(a)huawei.com>
test_suit.c should be the main function file,
and these two files have the duplicate code.
Signed-off-by: Hao Fang <fanghao11(a)huawei.com>
---
 test/hisi_zip_test/Makefile.am     |   2 +-
 test/hisi_zip_test/test_sva_perf.c | 524 -----------------------------
 test/hisi_zip_test/testsuit.c      | 474 +++++++++++++++++++++++++-
 3 files changed, 474 insertions(+), 526 deletions(-)
 delete mode 100644 test/hisi_zip_test/test_sva_perf.c
diff --git a/test/hisi_zip_test/Makefile.am b/test/hisi_zip_test/Makefile.am
index 827a0d4c..92ef1de7 100644
--- a/test/hisi_zip_test/Makefile.am
+++ b/test/hisi_zip_test/Makefile.am
@@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = subdir-objects
 
 bin_PROGRAMS=zip_sva_perf
 
-zip_sva_perf_SOURCES=test_sva_perf.c test_lib.c	testsuit.c
+zip_sva_perf_SOURCES=testsuit.c test_lib.c
 
 if WD_STATIC_DRV
 zip_sva_perf_LDADD=../../.libs/libwd.a ../../.libs/libwd_comp.a \
diff --git a/test/hisi_zip_test/test_sva_perf.c b/test/hisi_zip_test/test_sva_perf.c
deleted file mode 100644
index 98670a5b..00000000
--- a/test/hisi_zip_test/test_sva_perf.c
+++ /dev/null
@@ -1,524 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-/*
- * Copyright 2020-2021 Huawei Technologies Co.,Ltd. All rights reserved.
- * Copyright 2020-2021 Linaro ltd.
- */
-
-/*
- * Test performance of the SVA API
- */
-#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 <linux/perf_event.h>
-
-#include "test_lib.h"
-#include "wd_sched.h"
-
-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];
-};
-
-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 main(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/test/hisi_zip_test/testsuit.c b/test/hisi_zip_test/testsuit.c
index ac1a5f68..e1b157a7 100644
--- a/test/hisi_zip_test/testsuit.c
+++ b/test/hisi_zip_test/testsuit.c
@@ -3,12 +3,22 @@
  * 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 "test_lib.h"
+#include "wd_sched.h"
 
 #define POLL_STRING_LEN		128
 
@@ -1370,3 +1380,465 @@ int run_cmd(struct test_options *opts)
 		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 main(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;
+}
\ No newline at end of file
-- 
2.33.0