xref: /spdk/examples/accel/perf/accel_perf.c (revision 975c1df918501aacbecc35a03c00b06ad8ec7415)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2020 Intel Corporation.
3*975c1df9SAlexey Marchuk  *   Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
49f51cf32Spaul luse  *   All rights reserved.
59f51cf32Spaul luse  */
69f51cf32Spaul luse 
79f51cf32Spaul luse #include "spdk/stdinc.h"
89f51cf32Spaul luse #include "spdk/thread.h"
99f51cf32Spaul luse #include "spdk/env.h"
109f51cf32Spaul luse #include "spdk/event.h"
119f51cf32Spaul luse #include "spdk/log.h"
129f51cf32Spaul luse #include "spdk/string.h"
13081f080aSBen Walker #include "spdk/accel.h"
14e69375bfSpaul luse #include "spdk/crc32.h"
150cecfcb1Spaul luse #include "spdk/util.h"
16a5d5ab27SArtur Paszkiewicz #include "spdk/xor.h"
1744bf79a8SKrzysztof Sprzaczkowski #include "spdk/dif.h"
189f51cf32Spaul luse 
19b9218b7aSpaul luse #define DATA_PATTERN 0x5a
200ef079c6Spaul luse #define ALIGN_4K 0x1000
216afbf3dbSpaul luse #define COMP_BUF_PAD_PERCENTAGE 1.1L
22b9218b7aSpaul luse 
239f51cf32Spaul luse static uint64_t	g_tsc_rate;
249f51cf32Spaul luse static uint64_t g_tsc_end;
259b189667Spaul luse static int g_rc;
269f51cf32Spaul luse static int g_xfer_size_bytes = 4096;
2744bf79a8SKrzysztof Sprzaczkowski static int g_block_size_bytes = 512;
2844bf79a8SKrzysztof Sprzaczkowski static int g_md_size_bytes = 8;
299f51cf32Spaul luse static int g_queue_depth = 32;
30e1bf63afSJim Harris /* g_allocate_depth indicates how many tasks we allocate per worker. It will
31e1bf63afSJim Harris  * be at least as much as the queue depth.
32e1bf63afSJim Harris  */
33e1bf63afSJim Harris static int g_allocate_depth = 0;
34445fe74eSpaul luse static int g_threads_per_core = 1;
359f51cf32Spaul luse static int g_time_in_sec = 5;
36e69375bfSpaul luse static uint32_t g_crc32c_seed = 0;
37850cd900Spaul luse static uint32_t g_chained_count = 1;
38b9218b7aSpaul luse static int g_fail_percent_goal = 0;
3989495464Spaul luse static uint8_t g_fill_pattern = 255;
40a5d5ab27SArtur Paszkiewicz static uint32_t g_xor_src_count = 2;
419f51cf32Spaul luse static bool g_verify = false;
422a0c66d0Spaul luse static const char *g_workload_type = NULL;
4384dbdf08STomasz Zawadzki static enum spdk_accel_opcode g_workload_selection = SPDK_ACCEL_OPC_LAST;
440a6b7098STomasz Zawadzki static const char *g_module_name = NULL;
459f51cf32Spaul luse static struct worker_thread *g_workers = NULL;
469f51cf32Spaul luse static int g_num_workers = 0;
4727e85f52SBen Walker static char *g_cd_file_in_name = NULL;
489f51cf32Spaul luse static pthread_mutex_t g_workers_lock = PTHREAD_MUTEX_INITIALIZER;
499260fa0cSpaul luse static struct spdk_app_opts g_opts = {};
50cdefd3d3Spaul luse 
5127e85f52SBen Walker struct ap_compress_seg {
5227e85f52SBen Walker 	void		*uncompressed_data;
5327e85f52SBen Walker 	uint32_t	uncompressed_len;
5427e85f52SBen Walker 	struct iovec	*uncompressed_iovs;
5527e85f52SBen Walker 	uint32_t	uncompressed_iovcnt;
5627e85f52SBen Walker 
5727e85f52SBen Walker 	void		*compressed_data;
5827e85f52SBen Walker 	uint32_t	compressed_len;
596afbf3dbSpaul luse 	uint32_t	compressed_len_padded;
6027e85f52SBen Walker 	struct iovec	*compressed_iovs;
6127e85f52SBen Walker 	uint32_t	compressed_iovcnt;
6227e85f52SBen Walker 
6327e85f52SBen Walker 	STAILQ_ENTRY(ap_compress_seg)	link;
6427e85f52SBen Walker };
6527e85f52SBen Walker 
6627e85f52SBen Walker static STAILQ_HEAD(, ap_compress_seg) g_compress_segs = STAILQ_HEAD_INITIALIZER(g_compress_segs);
6727e85f52SBen Walker 
68cdefd3d3Spaul luse struct worker_thread;
69cdefd3d3Spaul luse static void accel_done(void *ref, int status);
70cdefd3d3Spaul luse 
71445fe74eSpaul luse struct display_info {
72445fe74eSpaul luse 	int core;
73445fe74eSpaul luse 	int thread;
74445fe74eSpaul luse };
75445fe74eSpaul luse 
76cdefd3d3Spaul luse struct ap_task {
77cdefd3d3Spaul luse 	void			*src;
7828886ac3Spaul luse 	struct iovec		*src_iovs;
7928886ac3Spaul luse 	uint32_t		src_iovcnt;
80a5d5ab27SArtur Paszkiewicz 	void			**sources;
81850cd900Spaul luse 	struct iovec		*dst_iovs;
82850cd900Spaul luse 	uint32_t		dst_iovcnt;
8380dfab0aSKrzysztof Karas 	struct iovec		md_iov;
84cdefd3d3Spaul luse 	void			*dst;
85cdefd3d3Spaul luse 	void			*dst2;
8681beca34SMoshe Shahar 	uint32_t		*crc_dst;
8727e85f52SBen Walker 	uint32_t		compressed_sz;
8827e85f52SBen Walker 	struct ap_compress_seg *cur_seg;
89cdefd3d3Spaul luse 	struct worker_thread	*worker;
90cdefd3d3Spaul luse 	int			expected_status; /* used for the compare operation */
9144bf79a8SKrzysztof Sprzaczkowski 	uint32_t		num_blocks; /* used for the DIF related operations */
9244bf79a8SKrzysztof Sprzaczkowski 	struct spdk_dif_ctx	dif_ctx;
9344bf79a8SKrzysztof Sprzaczkowski 	struct spdk_dif_error	dif_err;
94cdefd3d3Spaul luse 	TAILQ_ENTRY(ap_task)	link;
95cdefd3d3Spaul luse };
969f51cf32Spaul luse 
979f51cf32Spaul luse struct worker_thread {
989f51cf32Spaul luse 	struct spdk_io_channel		*ch;
99e3babb2bSKonrad Sztyber 	struct spdk_accel_opcode_stats	stats;
1009f51cf32Spaul luse 	uint64_t			xfer_failed;
101b9218b7aSpaul luse 	uint64_t			injected_miscompares;
1029f51cf32Spaul luse 	uint64_t			current_queue_depth;
103ac9a1a83Spaul luse 	TAILQ_HEAD(, ap_task)		tasks_pool;
1049f51cf32Spaul luse 	struct worker_thread		*next;
1059f51cf32Spaul luse 	unsigned			core;
1069f51cf32Spaul luse 	struct spdk_thread		*thread;
1079f51cf32Spaul luse 	bool				is_draining;
1089f51cf32Spaul luse 	struct spdk_poller		*is_draining_poller;
1099f51cf32Spaul luse 	struct spdk_poller		*stop_poller;
110ac9a1a83Spaul luse 	void				*task_base;
111445fe74eSpaul luse 	struct display_info		display;
1125105dc5dSKonrad Sztyber 	enum spdk_accel_opcode		workload;
1139f51cf32Spaul luse };
1149f51cf32Spaul luse 
1159f51cf32Spaul luse static void
1169260fa0cSpaul luse dump_user_config(void)
1179f51cf32Spaul luse {
118712e8cb7SBen Walker 	const char *module_name = NULL;
1199260fa0cSpaul luse 	int rc;
1209260fa0cSpaul luse 
121712e8cb7SBen Walker 	rc = spdk_accel_get_opc_module_name(g_workload_selection, &module_name);
1229260fa0cSpaul luse 	if (rc) {
123712e8cb7SBen Walker 		printf("error getting module name (%d)\n", rc);
1249260fa0cSpaul luse 	}
1259260fa0cSpaul luse 
1269260fa0cSpaul luse 	printf("\nSPDK Configuration:\n");
1279260fa0cSpaul luse 	printf("Core mask:      %s\n\n", g_opts.reactor_mask);
1289f51cf32Spaul luse 	printf("Accel Perf Configuration:\n");
1292a0c66d0Spaul luse 	printf("Workload Type:  %s\n", g_workload_type);
1305105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
1315105dc5dSKonrad Sztyber 	    g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C) {
132b9218b7aSpaul luse 		printf("CRC-32C seed:   %u\n", g_crc32c_seed);
1335105dc5dSKonrad Sztyber 	} else if (g_workload_selection == SPDK_ACCEL_OPC_FILL) {
13489495464Spaul luse 		printf("Fill pattern:   0x%x\n", g_fill_pattern);
1355105dc5dSKonrad Sztyber 	} else if ((g_workload_selection == SPDK_ACCEL_OPC_COMPARE) && g_fail_percent_goal > 0) {
13689495464Spaul luse 		printf("Failure inject: %u percent\n", g_fail_percent_goal);
1375105dc5dSKonrad Sztyber 	} else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
138a5d5ab27SArtur Paszkiewicz 		printf("Source buffers: %u\n", g_xor_src_count);
139e69375bfSpaul luse 	}
14044bf79a8SKrzysztof Sprzaczkowski 	if (g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
141fbe2860eSKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
142ee2adf2eSKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
14380dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY ||
14480dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE ||
145fbe2860eSKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
146221eb3f4Spaul luse 		printf("Vector size:    %u bytes\n", g_xfer_size_bytes);
147850cd900Spaul luse 		printf("Transfer size:  %u bytes\n", g_xfer_size_bytes * g_chained_count);
148221eb3f4Spaul luse 	} else {
1499f51cf32Spaul luse 		printf("Transfer size:  %u bytes\n", g_xfer_size_bytes);
150221eb3f4Spaul luse 	}
151ee2adf2eSKrzysztof Sprzaczkowski 	if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
15280dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
15380dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE ||
15480dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY) {
15544bf79a8SKrzysztof Sprzaczkowski 		printf("Block size:     %u bytes\n", g_block_size_bytes);
15644bf79a8SKrzysztof Sprzaczkowski 		printf("Metadata size:  %u bytes\n", g_md_size_bytes);
15744bf79a8SKrzysztof Sprzaczkowski 	}
15844bf79a8SKrzysztof Sprzaczkowski 	printf("Vector count    %u\n", g_chained_count);
159712e8cb7SBen Walker 	printf("Module:         %s\n", module_name);
1605105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS ||
1615105dc5dSKonrad Sztyber 	    g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
16227e85f52SBen Walker 		printf("File Name:      %s\n", g_cd_file_in_name);
16327e85f52SBen Walker 	}
1649f51cf32Spaul luse 	printf("Queue depth:    %u\n", g_queue_depth);
165e1bf63afSJim Harris 	printf("Allocate depth: %u\n", g_allocate_depth);
166445fe74eSpaul luse 	printf("# threads/core: %u\n", g_threads_per_core);
1679f51cf32Spaul luse 	printf("Run time:       %u seconds\n", g_time_in_sec);
1689f51cf32Spaul luse 	printf("Verify:         %s\n\n", g_verify ? "Yes" : "No");
1699f51cf32Spaul luse }
1709f51cf32Spaul luse 
1719f51cf32Spaul luse static void
1729f51cf32Spaul luse usage(void)
1739f51cf32Spaul luse {
1749f51cf32Spaul luse 	printf("accel_perf options:\n");
1759f51cf32Spaul luse 	printf("\t[-h help message]\n");
176f17e6705Spaul luse 	printf("\t[-q queue depth per core]\n");
177850cd900Spaul luse 	printf("\t[-C for supported workloads, use this value to configure the io vector size to test (default 1)\n");
178445fe74eSpaul luse 	printf("\t[-T number of threads per core\n");
17927e85f52SBen Walker 	printf("\t[-o transfer size in bytes (default: 4KiB. For compress/decompress, 0 means the input file size)]\n");
1809f51cf32Spaul luse 	printf("\t[-t time in seconds]\n");
181ee2adf2eSKrzysztof Sprzaczkowski 	printf("\t[-w workload type must be one of these: copy, fill, crc32c, copy_crc32c, compare, compress, decompress, dualcast, xor,\n");
18280dfab0aSKrzysztof Karas 	printf("\t[                                       dif_verify, dif_verify_copy, dif_generate, dif_generate_copy, dix_generate, dix_verify\n");
1830a6b7098STomasz Zawadzki 	printf("\t[-M assign module to the operation, not compatible with accel_assign_opc RPC\n");
18427e85f52SBen Walker 	printf("\t[-l for compress/decompress workloads, name of uncompressed input file\n");
185436877a4SKonrad Sztyber 	printf("\t[-S for crc32c workload, use this seed value (default 0)\n");
186b9218b7aSpaul luse 	printf("\t[-P for compare workload, percentage of operations that should miscompare (percent, default 0)\n");
18789495464Spaul luse 	printf("\t[-f for fill workload, use this BYTE value (default 255)\n");
188a5d5ab27SArtur Paszkiewicz 	printf("\t[-x for xor workload, use this number of source buffers (default, minimum: 2)]\n");
1892a0c66d0Spaul luse 	printf("\t[-y verify result if this switch is on]\n");
190e1bf63afSJim Harris 	printf("\t[-a tasks to allocate per core (default: same value as -q)]\n");
191e1bf63afSJim Harris 	printf("\t\tCan be used to spread operations across a wider range of memory.\n");
1929f51cf32Spaul luse }
1939f51cf32Spaul luse 
1949f51cf32Spaul luse static int
195436877a4SKonrad Sztyber parse_args(int ch, char *arg)
1969f51cf32Spaul luse {
197358b84b4SZiye Yang 	int argval = 0;
198c82d5789SJim Harris 
199436877a4SKonrad Sztyber 	switch (ch) {
200e1bf63afSJim Harris 	case 'a':
201c82d5789SJim Harris 	case 'C':
202c82d5789SJim Harris 	case 'f':
203c82d5789SJim Harris 	case 'T':
204c82d5789SJim Harris 	case 'o':
205c82d5789SJim Harris 	case 'P':
206c82d5789SJim Harris 	case 'q':
207436877a4SKonrad Sztyber 	case 'S':
208c82d5789SJim Harris 	case 't':
209a5d5ab27SArtur Paszkiewicz 	case 'x':
210c82d5789SJim Harris 		argval = spdk_strtol(optarg, 10);
211c82d5789SJim Harris 		if (argval < 0) {
212436877a4SKonrad Sztyber 			fprintf(stderr, "-%c option must be non-negative.\n", ch);
213c82d5789SJim Harris 			usage();
214c82d5789SJim Harris 			return 1;
215c82d5789SJim Harris 		}
216c82d5789SJim Harris 		break;
217c82d5789SJim Harris 	default:
218c82d5789SJim Harris 		break;
219c82d5789SJim Harris 	};
220c82d5789SJim Harris 
221436877a4SKonrad Sztyber 	switch (ch) {
222e1bf63afSJim Harris 	case 'a':
223e1bf63afSJim Harris 		g_allocate_depth = argval;
224e1bf63afSJim Harris 		break;
22588754353SZiye Yang 	case 'C':
226850cd900Spaul luse 		g_chained_count = argval;
22788754353SZiye Yang 		break;
22827e85f52SBen Walker 	case 'l':
22927e85f52SBen Walker 		g_cd_file_in_name = optarg;
23027e85f52SBen Walker 		break;
23189495464Spaul luse 	case 'f':
232c82d5789SJim Harris 		g_fill_pattern = (uint8_t)argval;
23389495464Spaul luse 		break;
234445fe74eSpaul luse 	case 'T':
235c82d5789SJim Harris 		g_threads_per_core = argval;
236445fe74eSpaul luse 		break;
2379f51cf32Spaul luse 	case 'o':
238c82d5789SJim Harris 		g_xfer_size_bytes = argval;
2399f51cf32Spaul luse 		break;
240b9218b7aSpaul luse 	case 'P':
241c82d5789SJim Harris 		g_fail_percent_goal = argval;
242b9218b7aSpaul luse 		break;
2439f51cf32Spaul luse 	case 'q':
244c82d5789SJim Harris 		g_queue_depth = argval;
2459f51cf32Spaul luse 		break;
246436877a4SKonrad Sztyber 	case 'S':
247c82d5789SJim Harris 		g_crc32c_seed = argval;
248e69375bfSpaul luse 		break;
2499f51cf32Spaul luse 	case 't':
250c82d5789SJim Harris 		g_time_in_sec = argval;
2519f51cf32Spaul luse 		break;
252a5d5ab27SArtur Paszkiewicz 	case 'x':
253a5d5ab27SArtur Paszkiewicz 		g_xor_src_count = argval;
254a5d5ab27SArtur Paszkiewicz 		break;
2559f51cf32Spaul luse 	case 'y':
2569f51cf32Spaul luse 		g_verify = true;
2579f51cf32Spaul luse 		break;
2582a0c66d0Spaul luse 	case 'w':
2592a0c66d0Spaul luse 		g_workload_type = optarg;
260514be889Spaul luse 		if (!strcmp(g_workload_type, "copy")) {
2615105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_COPY;
262514be889Spaul luse 		} else if (!strcmp(g_workload_type, "fill")) {
2635105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_FILL;
264e69375bfSpaul luse 		} else if (!strcmp(g_workload_type, "crc32c")) {
2655105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_CRC32C;
266221eb3f4Spaul luse 		} else if (!strcmp(g_workload_type, "copy_crc32c")) {
2675105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_COPY_CRC32C;
268b9218b7aSpaul luse 		} else if (!strcmp(g_workload_type, "compare")) {
2695105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_COMPARE;
2700ef079c6Spaul luse 		} else if (!strcmp(g_workload_type, "dualcast")) {
2715105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_DUALCAST;
27227e85f52SBen Walker 		} else if (!strcmp(g_workload_type, "compress")) {
2735105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_COMPRESS;
27427e85f52SBen Walker 		} else if (!strcmp(g_workload_type, "decompress")) {
2755105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_DECOMPRESS;
276a5d5ab27SArtur Paszkiewicz 		} else if (!strcmp(g_workload_type, "xor")) {
2775105dc5dSKonrad Sztyber 			g_workload_selection = SPDK_ACCEL_OPC_XOR;
27844bf79a8SKrzysztof Sprzaczkowski 		} else if (!strcmp(g_workload_type, "dif_verify")) {
27944bf79a8SKrzysztof Sprzaczkowski 			g_workload_selection = SPDK_ACCEL_OPC_DIF_VERIFY;
28097457e44SKrzysztof Sprzaczkowski 		} else if (!strcmp(g_workload_type, "dif_verify_copy")) {
28197457e44SKrzysztof Sprzaczkowski 			g_workload_selection = SPDK_ACCEL_OPC_DIF_VERIFY_COPY;
282ee2adf2eSKrzysztof Sprzaczkowski 		} else if (!strcmp(g_workload_type, "dif_generate")) {
283ee2adf2eSKrzysztof Sprzaczkowski 			g_workload_selection = SPDK_ACCEL_OPC_DIF_GENERATE;
284fbe2860eSKrzysztof Sprzaczkowski 		} else if (!strcmp(g_workload_type, "dif_generate_copy")) {
285fbe2860eSKrzysztof Sprzaczkowski 			g_workload_selection = SPDK_ACCEL_OPC_DIF_GENERATE_COPY;
28680dfab0aSKrzysztof Karas 		} else if (!strcmp(g_workload_type, "dix_verify")) {
28780dfab0aSKrzysztof Karas 			g_workload_selection = SPDK_ACCEL_OPC_DIX_VERIFY;
28880dfab0aSKrzysztof Karas 		} else if (!strcmp(g_workload_type, "dix_generate")) {
28980dfab0aSKrzysztof Karas 			g_workload_selection = SPDK_ACCEL_OPC_DIX_GENERATE;
290b21221e1Spaul luse 		} else {
29184dbdf08STomasz Zawadzki 			fprintf(stderr, "Unsupported workload type: %s\n", optarg);
292b21221e1Spaul luse 			usage();
293b21221e1Spaul luse 			return 1;
294514be889Spaul luse 		}
2952a0c66d0Spaul luse 		break;
2960a6b7098STomasz Zawadzki 	case 'M':
2970a6b7098STomasz Zawadzki 		g_module_name = optarg;
2980a6b7098STomasz Zawadzki 		break;
2990a6b7098STomasz Zawadzki 
3009f51cf32Spaul luse 	default:
3019f51cf32Spaul luse 		usage();
3029f51cf32Spaul luse 		return 1;
3039f51cf32Spaul luse 	}
30488754353SZiye Yang 
3059f51cf32Spaul luse 	return 0;
3069f51cf32Spaul luse }
3079f51cf32Spaul luse 
308eea826a2Spaul luse static int dump_result(void);
3099f51cf32Spaul luse static void
3109f51cf32Spaul luse unregister_worker(void *arg1)
3119f51cf32Spaul luse {
3129f51cf32Spaul luse 	struct worker_thread *worker = arg1;
3139f51cf32Spaul luse 
31420b5c460STomasz Zawadzki 	if (worker->ch) {
315e3babb2bSKonrad Sztyber 		spdk_accel_get_opcode_stats(worker->ch, worker->workload,
316e3babb2bSKonrad Sztyber 					    &worker->stats, sizeof(worker->stats));
3179f51cf32Spaul luse 		spdk_put_io_channel(worker->ch);
31820b5c460STomasz Zawadzki 		worker->ch = NULL;
31920b5c460STomasz Zawadzki 	}
32020b5c460STomasz Zawadzki 	free(worker->task_base);
3210e7821e9SJim Harris 	spdk_thread_exit(spdk_get_thread());
3229f51cf32Spaul luse 	pthread_mutex_lock(&g_workers_lock);
3239f51cf32Spaul luse 	assert(g_num_workers >= 1);
3249f51cf32Spaul luse 	if (--g_num_workers == 0) {
3259f51cf32Spaul luse 		pthread_mutex_unlock(&g_workers_lock);
32620b5c460STomasz Zawadzki 		/* Only dump results on successful runs */
32720b5c460STomasz Zawadzki 		if (g_rc == 0) {
3289b189667Spaul luse 			g_rc = dump_result();
32920b5c460STomasz Zawadzki 		}
33020b5c460STomasz Zawadzki 		spdk_app_stop(g_rc);
331f042d6baSGangCao 	} else {
3329f51cf32Spaul luse 		pthread_mutex_unlock(&g_workers_lock);
3339f51cf32Spaul luse 	}
334f042d6baSGangCao }
3359f51cf32Spaul luse 
33627e85f52SBen Walker static void
33727e85f52SBen Walker accel_perf_construct_iovs(void *buf, uint64_t sz, struct iovec *iovs, uint32_t iovcnt)
33827e85f52SBen Walker {
33927e85f52SBen Walker 	uint64_t ele_size;
34027e85f52SBen Walker 	uint8_t *data;
34127e85f52SBen Walker 	uint32_t i;
34227e85f52SBen Walker 
34327e85f52SBen Walker 	ele_size = spdk_divide_round_up(sz, iovcnt);
34427e85f52SBen Walker 
34527e85f52SBen Walker 	data = buf;
34627e85f52SBen Walker 	for (i = 0; i < iovcnt; i++) {
34727e85f52SBen Walker 		ele_size = spdk_min(ele_size, sz);
34827e85f52SBen Walker 		assert(ele_size > 0);
34927e85f52SBen Walker 
35027e85f52SBen Walker 		iovs[i].iov_base = data;
35127e85f52SBen Walker 		iovs[i].iov_len = ele_size;
35227e85f52SBen Walker 
35327e85f52SBen Walker 		data += ele_size;
35427e85f52SBen Walker 		sz -= ele_size;
35527e85f52SBen Walker 	}
35627e85f52SBen Walker 	assert(sz == 0);
35727e85f52SBen Walker }
35827e85f52SBen Walker 
3598da995c4Spaul luse static int
3608da995c4Spaul luse _get_task_data_bufs(struct ap_task *task)
3618da995c4Spaul luse {
3628da995c4Spaul luse 	uint32_t align = 0;
36388754353SZiye Yang 	uint32_t i = 0;
36444bf79a8SKrzysztof Sprzaczkowski 	int src_buff_len = g_xfer_size_bytes;
365221eb3f4Spaul luse 	int dst_buff_len = g_xfer_size_bytes;
36680dfab0aSKrzysztof Karas 	int md_buff_len;
36744bf79a8SKrzysztof Sprzaczkowski 	struct spdk_dif_ctx_init_ext_opts dif_opts;
368fbe2860eSKrzysztof Sprzaczkowski 	uint32_t num_blocks, transfer_size_with_md;
36944bf79a8SKrzysztof Sprzaczkowski 	int rc;
3708da995c4Spaul luse 
3718da995c4Spaul luse 	/* For dualcast, the DSA HW requires 4K alignment on destination addresses but
372712e8cb7SBen Walker 	 * we do this for all modules to keep it simple.
3738da995c4Spaul luse 	 */
3745105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST) {
3758da995c4Spaul luse 		align = ALIGN_4K;
3768da995c4Spaul luse 	}
3778da995c4Spaul luse 
3785105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS ||
3795105dc5dSKonrad Sztyber 	    g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
38027e85f52SBen Walker 		task->cur_seg = STAILQ_FIRST(&g_compress_segs);
3816afbf3dbSpaul luse 
3825105dc5dSKonrad Sztyber 		if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
3836afbf3dbSpaul luse 			dst_buff_len = task->cur_seg->compressed_len_padded;
3846afbf3dbSpaul luse 		}
3856afbf3dbSpaul luse 
3866afbf3dbSpaul luse 		task->dst = spdk_dma_zmalloc(dst_buff_len, align, NULL);
3876afbf3dbSpaul luse 		if (task->dst == NULL) {
3886afbf3dbSpaul luse 			fprintf(stderr, "Unable to alloc dst buffer\n");
3896afbf3dbSpaul luse 			return -ENOMEM;
3906afbf3dbSpaul luse 		}
3916afbf3dbSpaul luse 
3926afbf3dbSpaul luse 		task->dst_iovs = calloc(g_chained_count, sizeof(struct iovec));
3936afbf3dbSpaul luse 		if (!task->dst_iovs) {
3946afbf3dbSpaul luse 			fprintf(stderr, "cannot allocate task->dst_iovs for task=%p\n", task);
3956afbf3dbSpaul luse 			return -ENOMEM;
3966afbf3dbSpaul luse 		}
3976afbf3dbSpaul luse 		task->dst_iovcnt = g_chained_count;
3986afbf3dbSpaul luse 		accel_perf_construct_iovs(task->dst, dst_buff_len, task->dst_iovs, task->dst_iovcnt);
3996afbf3dbSpaul luse 
4006afbf3dbSpaul luse 		return 0;
4016afbf3dbSpaul luse 	}
4026afbf3dbSpaul luse 
403fbe2860eSKrzysztof Sprzaczkowski 	if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
404fbe2860eSKrzysztof Sprzaczkowski 		task->dst_iovcnt = g_chained_count;
405fbe2860eSKrzysztof Sprzaczkowski 		task->dst_iovs = calloc(task->dst_iovcnt, sizeof(struct iovec));
406fbe2860eSKrzysztof Sprzaczkowski 		if (!task->dst_iovs) {
407fbe2860eSKrzysztof Sprzaczkowski 			fprintf(stderr, "cannot allocate task->dst_iovs for task=%p\n", task);
408fbe2860eSKrzysztof Sprzaczkowski 			return -ENOMEM;
409fbe2860eSKrzysztof Sprzaczkowski 		}
410fbe2860eSKrzysztof Sprzaczkowski 
411fbe2860eSKrzysztof Sprzaczkowski 		num_blocks = g_xfer_size_bytes / g_block_size_bytes;
412fbe2860eSKrzysztof Sprzaczkowski 		/* Add bytes for each block for metadata */
413fbe2860eSKrzysztof Sprzaczkowski 		transfer_size_with_md = g_xfer_size_bytes + (num_blocks * g_md_size_bytes);
414fbe2860eSKrzysztof Sprzaczkowski 		task->num_blocks = num_blocks;
415fbe2860eSKrzysztof Sprzaczkowski 
416fbe2860eSKrzysztof Sprzaczkowski 		for (i = 0; i < task->dst_iovcnt; i++) {
417fbe2860eSKrzysztof Sprzaczkowski 			task->dst_iovs[i].iov_base = spdk_dma_zmalloc(transfer_size_with_md, 0, NULL);
418fbe2860eSKrzysztof Sprzaczkowski 			if (task->dst_iovs[i].iov_base == NULL) {
419fbe2860eSKrzysztof Sprzaczkowski 				return -ENOMEM;
420fbe2860eSKrzysztof Sprzaczkowski 			}
421fbe2860eSKrzysztof Sprzaczkowski 			task->dst_iovs[i].iov_len = transfer_size_with_md;
422fbe2860eSKrzysztof Sprzaczkowski 		}
423fbe2860eSKrzysztof Sprzaczkowski 
424fbe2860eSKrzysztof Sprzaczkowski 		dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
425fbe2860eSKrzysztof Sprzaczkowski 		dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
426fbe2860eSKrzysztof Sprzaczkowski 
427fbe2860eSKrzysztof Sprzaczkowski 		rc = spdk_dif_ctx_init(&task->dif_ctx,
428fbe2860eSKrzysztof Sprzaczkowski 				       g_block_size_bytes + g_md_size_bytes,
429fbe2860eSKrzysztof Sprzaczkowski 				       g_md_size_bytes, true, true,
430fbe2860eSKrzysztof Sprzaczkowski 				       SPDK_DIF_TYPE1,
431fbe2860eSKrzysztof Sprzaczkowski 				       SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK,
432fbe2860eSKrzysztof Sprzaczkowski 				       0x123, 0xFFFF, 0x234, 0, 0, &dif_opts);
433fbe2860eSKrzysztof Sprzaczkowski 		if (rc != 0) {
4341940e7e4SKrzysztof Sprzaczkowski 			fprintf(stderr, "Initialization of DIF context failed, error (%d)\n", rc);
435fbe2860eSKrzysztof Sprzaczkowski 			return rc;
436fbe2860eSKrzysztof Sprzaczkowski 		}
437fbe2860eSKrzysztof Sprzaczkowski 	}
438fbe2860eSKrzysztof Sprzaczkowski 
43997457e44SKrzysztof Sprzaczkowski 	if (g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY_COPY) {
44097457e44SKrzysztof Sprzaczkowski 		/* Allocate source buffers */
44197457e44SKrzysztof Sprzaczkowski 		task->src_iovcnt = g_chained_count;
44297457e44SKrzysztof Sprzaczkowski 		task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
44397457e44SKrzysztof Sprzaczkowski 		if (!task->src_iovs) {
44497457e44SKrzysztof Sprzaczkowski 			fprintf(stderr, "cannot allocate task->src_iovs for task=%p\n", task);
44597457e44SKrzysztof Sprzaczkowski 			return -ENOMEM;
44697457e44SKrzysztof Sprzaczkowski 		}
44797457e44SKrzysztof Sprzaczkowski 
44897457e44SKrzysztof Sprzaczkowski 		num_blocks = g_xfer_size_bytes / g_block_size_bytes;
44997457e44SKrzysztof Sprzaczkowski 		/* Add bytes for each block for metadata */
45097457e44SKrzysztof Sprzaczkowski 		transfer_size_with_md = g_xfer_size_bytes + (num_blocks * g_md_size_bytes);
45197457e44SKrzysztof Sprzaczkowski 		task->num_blocks = num_blocks;
45297457e44SKrzysztof Sprzaczkowski 
45397457e44SKrzysztof Sprzaczkowski 		for (i = 0; i < task->src_iovcnt; i++) {
45497457e44SKrzysztof Sprzaczkowski 			task->src_iovs[i].iov_base = spdk_dma_zmalloc(transfer_size_with_md, 0, NULL);
45597457e44SKrzysztof Sprzaczkowski 			if (task->src_iovs[i].iov_base == NULL) {
45697457e44SKrzysztof Sprzaczkowski 				return -ENOMEM;
45797457e44SKrzysztof Sprzaczkowski 			}
45897457e44SKrzysztof Sprzaczkowski 			memset(task->src_iovs[i].iov_base, DATA_PATTERN, transfer_size_with_md);
45997457e44SKrzysztof Sprzaczkowski 			task->src_iovs[i].iov_len = transfer_size_with_md;
46097457e44SKrzysztof Sprzaczkowski 		}
46197457e44SKrzysztof Sprzaczkowski 
46297457e44SKrzysztof Sprzaczkowski 		/* Allocate destination buffers */
46397457e44SKrzysztof Sprzaczkowski 		task->dst_iovcnt = g_chained_count;
46497457e44SKrzysztof Sprzaczkowski 		task->dst_iovs = calloc(task->dst_iovcnt, sizeof(struct iovec));
46597457e44SKrzysztof Sprzaczkowski 		if (!task->dst_iovs) {
46697457e44SKrzysztof Sprzaczkowski 			fprintf(stderr, "cannot allocated task->dst_iovs fot task=%p\n", task);
46797457e44SKrzysztof Sprzaczkowski 			return -ENOMEM;
46897457e44SKrzysztof Sprzaczkowski 		}
46997457e44SKrzysztof Sprzaczkowski 
47097457e44SKrzysztof Sprzaczkowski 		for (i = 0; i < task->dst_iovcnt; i++) {
47197457e44SKrzysztof Sprzaczkowski 			task->dst_iovs[i].iov_base = spdk_dma_zmalloc(dst_buff_len, 0, NULL);
47297457e44SKrzysztof Sprzaczkowski 			if (task->dst_iovs[i].iov_base == NULL) {
47397457e44SKrzysztof Sprzaczkowski 				return -ENOMEM;
47497457e44SKrzysztof Sprzaczkowski 			}
47597457e44SKrzysztof Sprzaczkowski 			task->dst_iovs[i].iov_len = dst_buff_len;
47697457e44SKrzysztof Sprzaczkowski 		}
47797457e44SKrzysztof Sprzaczkowski 
47897457e44SKrzysztof Sprzaczkowski 		dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
47997457e44SKrzysztof Sprzaczkowski 		dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
48097457e44SKrzysztof Sprzaczkowski 
48197457e44SKrzysztof Sprzaczkowski 		/* Init DIF ctx */
48297457e44SKrzysztof Sprzaczkowski 		rc = spdk_dif_ctx_init(&task->dif_ctx,
48397457e44SKrzysztof Sprzaczkowski 				       g_block_size_bytes + g_md_size_bytes,
48497457e44SKrzysztof Sprzaczkowski 				       g_md_size_bytes, true, true,
48597457e44SKrzysztof Sprzaczkowski 				       SPDK_DIF_TYPE1,
48697457e44SKrzysztof Sprzaczkowski 				       SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK,
48797457e44SKrzysztof Sprzaczkowski 				       0x123, 0xFFFF, 0x234, 0, 0, &dif_opts);
48897457e44SKrzysztof Sprzaczkowski 		if (rc != 0) {
48997457e44SKrzysztof Sprzaczkowski 			fprintf(stderr, "Initialization of DIF context failed, error (%d)\n", rc);
49097457e44SKrzysztof Sprzaczkowski 			return rc;
49197457e44SKrzysztof Sprzaczkowski 		}
49297457e44SKrzysztof Sprzaczkowski 
49397457e44SKrzysztof Sprzaczkowski 		rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
49497457e44SKrzysztof Sprzaczkowski 		if (rc != 0) {
49597457e44SKrzysztof Sprzaczkowski 			fprintf(stderr, "Generation of DIF failed, error (%d)\n", rc);
49697457e44SKrzysztof Sprzaczkowski 			return rc;
49797457e44SKrzysztof Sprzaczkowski 		}
49897457e44SKrzysztof Sprzaczkowski 	}
49997457e44SKrzysztof Sprzaczkowski 
5005105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
50181beca34SMoshe Shahar 	    g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C) {
50281beca34SMoshe Shahar 		task->crc_dst = spdk_dma_zmalloc(sizeof(*task->crc_dst), 0, NULL);
50381beca34SMoshe Shahar 	}
50481beca34SMoshe Shahar 
50581beca34SMoshe Shahar 	if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
50644bf79a8SKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
507fbe2860eSKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
508ee2adf2eSKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
50980dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY ||
51080dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY ||
51180dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE) {
512850cd900Spaul luse 		assert(g_chained_count > 0);
513850cd900Spaul luse 		task->src_iovcnt = g_chained_count;
51428886ac3Spaul luse 		task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
51528886ac3Spaul luse 		if (!task->src_iovs) {
51628886ac3Spaul luse 			fprintf(stderr, "cannot allocated task->src_iovs fot task=%p\n", task);
51788754353SZiye Yang 			return -ENOMEM;
51888754353SZiye Yang 		}
51988754353SZiye Yang 
5205105dc5dSKonrad Sztyber 		if (g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C) {
521850cd900Spaul luse 			dst_buff_len = g_xfer_size_bytes * g_chained_count;
522221eb3f4Spaul luse 		}
523221eb3f4Spaul luse 
524ee2adf2eSKrzysztof Sprzaczkowski 		if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
525ee2adf2eSKrzysztof Sprzaczkowski 		    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) {
52644bf79a8SKrzysztof Sprzaczkowski 			src_buff_len += (g_xfer_size_bytes / g_block_size_bytes) * g_md_size_bytes;
52744bf79a8SKrzysztof Sprzaczkowski 		}
52844bf79a8SKrzysztof Sprzaczkowski 
52928886ac3Spaul luse 		for (i = 0; i < task->src_iovcnt; i++) {
53044bf79a8SKrzysztof Sprzaczkowski 			task->src_iovs[i].iov_base = spdk_dma_zmalloc(src_buff_len, 0, NULL);
53128886ac3Spaul luse 			if (task->src_iovs[i].iov_base == NULL) {
53288754353SZiye Yang 				return -ENOMEM;
53388754353SZiye Yang 			}
53444bf79a8SKrzysztof Sprzaczkowski 			memset(task->src_iovs[i].iov_base, DATA_PATTERN, src_buff_len);
53544bf79a8SKrzysztof Sprzaczkowski 			task->src_iovs[i].iov_len = src_buff_len;
53688754353SZiye Yang 		}
53780dfab0aSKrzysztof Karas 		if (g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE ||
53880dfab0aSKrzysztof Karas 		    g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY) {
53980dfab0aSKrzysztof Karas 			md_buff_len = (g_xfer_size_bytes / g_block_size_bytes) * g_md_size_bytes *
54080dfab0aSKrzysztof Karas 				      g_chained_count;
54180dfab0aSKrzysztof Karas 			task->md_iov.iov_base = spdk_dma_zmalloc(md_buff_len, 0, NULL);
54280dfab0aSKrzysztof Karas 			if (task->md_iov.iov_base == NULL) {
54380dfab0aSKrzysztof Karas 				return -ENOMEM;
54480dfab0aSKrzysztof Karas 			}
54580dfab0aSKrzysztof Karas 			task->md_iov.iov_len = md_buff_len;
54680dfab0aSKrzysztof Karas 		}
5475105dc5dSKonrad Sztyber 	} else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
548a5d5ab27SArtur Paszkiewicz 		assert(g_xor_src_count > 1);
549a5d5ab27SArtur Paszkiewicz 		task->sources = calloc(g_xor_src_count, sizeof(*task->sources));
550a5d5ab27SArtur Paszkiewicz 		if (!task->sources) {
551a5d5ab27SArtur Paszkiewicz 			return -ENOMEM;
552a5d5ab27SArtur Paszkiewicz 		}
55388754353SZiye Yang 
554a5d5ab27SArtur Paszkiewicz 		for (i = 0; i < g_xor_src_count; i++) {
555a5d5ab27SArtur Paszkiewicz 			task->sources[i] = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
556a5d5ab27SArtur Paszkiewicz 			if (!task->sources[i]) {
557a5d5ab27SArtur Paszkiewicz 				return -ENOMEM;
558a5d5ab27SArtur Paszkiewicz 			}
559a5d5ab27SArtur Paszkiewicz 			memset(task->sources[i], DATA_PATTERN, g_xfer_size_bytes);
560a5d5ab27SArtur Paszkiewicz 		}
56188754353SZiye Yang 	} else {
5628da995c4Spaul luse 		task->src = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
5638da995c4Spaul luse 		if (task->src == NULL) {
5648da995c4Spaul luse 			fprintf(stderr, "Unable to alloc src buffer\n");
5658da995c4Spaul luse 			return -ENOMEM;
5668da995c4Spaul luse 		}
56788754353SZiye Yang 
56888754353SZiye Yang 		/* For fill, set the entire src buffer so we can check if verify is enabled. */
5695105dc5dSKonrad Sztyber 		if (g_workload_selection == SPDK_ACCEL_OPC_FILL) {
57088754353SZiye Yang 			memset(task->src, g_fill_pattern, g_xfer_size_bytes);
57188754353SZiye Yang 		} else {
5728da995c4Spaul luse 			memset(task->src, DATA_PATTERN, g_xfer_size_bytes);
57388754353SZiye Yang 		}
57488754353SZiye Yang 	}
5758da995c4Spaul luse 
57644bf79a8SKrzysztof Sprzaczkowski 	if (g_workload_selection != SPDK_ACCEL_OPC_CRC32C &&
577fbe2860eSKrzysztof Sprzaczkowski 	    g_workload_selection != SPDK_ACCEL_OPC_DIF_VERIFY &&
578ee2adf2eSKrzysztof Sprzaczkowski 	    g_workload_selection != SPDK_ACCEL_OPC_DIF_GENERATE &&
57997457e44SKrzysztof Sprzaczkowski 	    g_workload_selection != SPDK_ACCEL_OPC_DIF_GENERATE_COPY &&
58080dfab0aSKrzysztof Karas 	    g_workload_selection != SPDK_ACCEL_OPC_DIF_VERIFY_COPY &&
58180dfab0aSKrzysztof Karas 	    g_workload_selection != SPDK_ACCEL_OPC_DIX_VERIFY &&
58280dfab0aSKrzysztof Karas 	    g_workload_selection != SPDK_ACCEL_OPC_DIX_GENERATE) {
583221eb3f4Spaul luse 		task->dst = spdk_dma_zmalloc(dst_buff_len, align, NULL);
5848da995c4Spaul luse 		if (task->dst == NULL) {
5858da995c4Spaul luse 			fprintf(stderr, "Unable to alloc dst buffer\n");
5868da995c4Spaul luse 			return -ENOMEM;
5878da995c4Spaul luse 		}
5888da995c4Spaul luse 
5898da995c4Spaul luse 		/* For compare we want the buffers to match, otherwise not. */
5905105dc5dSKonrad Sztyber 		if (g_workload_selection == SPDK_ACCEL_OPC_COMPARE) {
591221eb3f4Spaul luse 			memset(task->dst, DATA_PATTERN, dst_buff_len);
5928da995c4Spaul luse 		} else {
593221eb3f4Spaul luse 			memset(task->dst, ~DATA_PATTERN, dst_buff_len);
594221eb3f4Spaul luse 		}
5958da995c4Spaul luse 	}
5968da995c4Spaul luse 
59784162738Spaul luse 	/* For dualcast 2 buffers are needed for the operation.  */
5985105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST ||
5995105dc5dSKonrad Sztyber 	    (g_workload_selection == SPDK_ACCEL_OPC_XOR && g_verify)) {
6008da995c4Spaul luse 		task->dst2 = spdk_dma_zmalloc(g_xfer_size_bytes, align, NULL);
6018da995c4Spaul luse 		if (task->dst2 == NULL) {
6028da995c4Spaul luse 			fprintf(stderr, "Unable to alloc dst buffer\n");
6038da995c4Spaul luse 			return -ENOMEM;
6048da995c4Spaul luse 		}
6058da995c4Spaul luse 		memset(task->dst2, ~DATA_PATTERN, g_xfer_size_bytes);
6068da995c4Spaul luse 	}
6078da995c4Spaul luse 
608ee2adf2eSKrzysztof Sprzaczkowski 	if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
60997457e44SKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
61097457e44SKrzysztof Sprzaczkowski 	    g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY_COPY) {
61144bf79a8SKrzysztof Sprzaczkowski 		dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
61244bf79a8SKrzysztof Sprzaczkowski 		dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
61344bf79a8SKrzysztof Sprzaczkowski 
61444bf79a8SKrzysztof Sprzaczkowski 		task->num_blocks = (g_xfer_size_bytes * g_chained_count) / g_block_size_bytes;
61544bf79a8SKrzysztof Sprzaczkowski 
61644bf79a8SKrzysztof Sprzaczkowski 		rc = spdk_dif_ctx_init(&task->dif_ctx,
61744bf79a8SKrzysztof Sprzaczkowski 				       g_block_size_bytes + g_md_size_bytes,
61844bf79a8SKrzysztof Sprzaczkowski 				       g_md_size_bytes, true, true,
61944bf79a8SKrzysztof Sprzaczkowski 				       SPDK_DIF_TYPE1,
62044bf79a8SKrzysztof Sprzaczkowski 				       SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK,
62144bf79a8SKrzysztof Sprzaczkowski 				       16, 0xFFFF, 10, 0, 0, &dif_opts);
62244bf79a8SKrzysztof Sprzaczkowski 		if (rc != 0) {
62344bf79a8SKrzysztof Sprzaczkowski 			fprintf(stderr, "Initialization of DIF context failed, error (%d)\n", rc);
62444bf79a8SKrzysztof Sprzaczkowski 			return rc;
62544bf79a8SKrzysztof Sprzaczkowski 		}
62644bf79a8SKrzysztof Sprzaczkowski 
62797457e44SKrzysztof Sprzaczkowski 		if ((g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) ||
62897457e44SKrzysztof Sprzaczkowski 		    (g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY_COPY)) {
62944bf79a8SKrzysztof Sprzaczkowski 			rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
63044bf79a8SKrzysztof Sprzaczkowski 			if (rc != 0) {
63144bf79a8SKrzysztof Sprzaczkowski 				fprintf(stderr, "Generation of DIF failed, error (%d)\n", rc);
63244bf79a8SKrzysztof Sprzaczkowski 				return rc;
63344bf79a8SKrzysztof Sprzaczkowski 			}
63444bf79a8SKrzysztof Sprzaczkowski 		}
635ee2adf2eSKrzysztof Sprzaczkowski 	}
63680dfab0aSKrzysztof Karas 	if (g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE ||
63780dfab0aSKrzysztof Karas 	    g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY) {
63880dfab0aSKrzysztof Karas 		dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
63980dfab0aSKrzysztof Karas 		dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
64080dfab0aSKrzysztof Karas 
64180dfab0aSKrzysztof Karas 		task->num_blocks = (g_xfer_size_bytes * g_chained_count) / g_block_size_bytes;
64280dfab0aSKrzysztof Karas 
64380dfab0aSKrzysztof Karas 		rc = spdk_dif_ctx_init(&task->dif_ctx,
64480dfab0aSKrzysztof Karas 				       g_block_size_bytes,
64580dfab0aSKrzysztof Karas 				       g_md_size_bytes, false, true,
64680dfab0aSKrzysztof Karas 				       SPDK_DIF_TYPE1,
64780dfab0aSKrzysztof Karas 				       SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
64880dfab0aSKrzysztof Karas 				       SPDK_DIF_FLAGS_REFTAG_CHECK,
64980dfab0aSKrzysztof Karas 				       0x123, 0xFFFF, 0x234, 0, 0, &dif_opts);
65080dfab0aSKrzysztof Karas 		if (rc != 0) {
65180dfab0aSKrzysztof Karas 			fprintf(stderr, "Initialization of DIX context failed, error (%d)\n", rc);
65280dfab0aSKrzysztof Karas 			return rc;
65380dfab0aSKrzysztof Karas 		}
65480dfab0aSKrzysztof Karas 		if (g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY) {
65580dfab0aSKrzysztof Karas 			rc = spdk_dix_generate(task->src_iovs, task->src_iovcnt, &task->md_iov,
65680dfab0aSKrzysztof Karas 					       task->num_blocks, &task->dif_ctx);
65780dfab0aSKrzysztof Karas 			if (rc != 0) {
65880dfab0aSKrzysztof Karas 				fprintf(stderr, "Generation of DIX failed, error (%d)\n", rc);
65980dfab0aSKrzysztof Karas 				return rc;
66080dfab0aSKrzysztof Karas 			}
66180dfab0aSKrzysztof Karas 		}
66280dfab0aSKrzysztof Karas 
66380dfab0aSKrzysztof Karas 	}
66444bf79a8SKrzysztof Sprzaczkowski 
6658da995c4Spaul luse 	return 0;
6668da995c4Spaul luse }
6678da995c4Spaul luse 
668ac9a1a83Spaul luse inline static struct ap_task *
669ac9a1a83Spaul luse _get_task(struct worker_thread *worker)
670ac9a1a83Spaul luse {
671ac9a1a83Spaul luse 	struct ap_task *task;
672ac9a1a83Spaul luse 
673ac9a1a83Spaul luse 	if (!TAILQ_EMPTY(&worker->tasks_pool)) {
674ac9a1a83Spaul luse 		task = TAILQ_FIRST(&worker->tasks_pool);
675ac9a1a83Spaul luse 		TAILQ_REMOVE(&worker->tasks_pool, task, link);
676ac9a1a83Spaul luse 	} else {
677ac9a1a83Spaul luse 		fprintf(stderr, "Unable to get ap_task\n");
678ac9a1a83Spaul luse 		return NULL;
679ac9a1a83Spaul luse 	}
680ac9a1a83Spaul luse 
681ac9a1a83Spaul luse 	return task;
682ac9a1a83Spaul luse }
683ac9a1a83Spaul luse 
684f17e6705Spaul luse /* Submit one operation using the same ap task that just completed. */
6859f51cf32Spaul luse static void
686ac9a1a83Spaul luse _submit_single(struct worker_thread *worker, struct ap_task *task)
6879f51cf32Spaul luse {
688b9218b7aSpaul luse 	int random_num;
68940ec8e97Spaul luse 	int rc = 0;
6909f51cf32Spaul luse 
6919f51cf32Spaul luse 	assert(worker);
6929f51cf32Spaul luse 
69313067997Spaul luse 	switch (worker->workload) {
6945105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY:
695e8463f87Spaul luse 		rc = spdk_accel_submit_copy(worker->ch, task->dst, task->src,
69679e2a56fSKonrad Sztyber 					    g_xfer_size_bytes, accel_done, task);
697e69375bfSpaul luse 		break;
6985105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_FILL:
6992a0c66d0Spaul luse 		/* For fill use the first byte of the task->dst buffer */
700ee7e31f9Spaul luse 		rc = spdk_accel_submit_fill(worker->ch, task->dst, *(uint8_t *)task->src,
70179e2a56fSKonrad Sztyber 					    g_xfer_size_bytes, accel_done, task);
702e69375bfSpaul luse 		break;
7035105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_CRC32C:
70481beca34SMoshe Shahar 		rc = spdk_accel_submit_crc32cv(worker->ch, task->crc_dst,
70528886ac3Spaul luse 					       task->src_iovs, task->src_iovcnt, g_crc32c_seed,
70690c56d96SZiye Yang 					       accel_done, task);
707e69375bfSpaul luse 		break;
7085105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY_CRC32C:
70928886ac3Spaul luse 		rc = spdk_accel_submit_copy_crc32cv(worker->ch, task->dst, task->src_iovs, task->src_iovcnt,
71079e2a56fSKonrad Sztyber 						    task->crc_dst, g_crc32c_seed, accel_done, task);
711221eb3f4Spaul luse 		break;
7125105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COMPARE:
713b9218b7aSpaul luse 		random_num = rand() % 100;
714b9218b7aSpaul luse 		if (random_num < g_fail_percent_goal) {
715b9218b7aSpaul luse 			task->expected_status = -EILSEQ;
716b9218b7aSpaul luse 			*(uint8_t *)task->dst = ~DATA_PATTERN;
717b9218b7aSpaul luse 		} else {
718b9218b7aSpaul luse 			task->expected_status = 0;
719b9218b7aSpaul luse 			*(uint8_t *)task->dst = DATA_PATTERN;
720b9218b7aSpaul luse 		}
721ee7e31f9Spaul luse 		rc = spdk_accel_submit_compare(worker->ch, task->dst, task->src,
722e8463f87Spaul luse 					       g_xfer_size_bytes, accel_done, task);
723b9218b7aSpaul luse 		break;
7245105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_DUALCAST:
725ee7e31f9Spaul luse 		rc = spdk_accel_submit_dualcast(worker->ch, task->dst, task->dst2,
72679e2a56fSKonrad Sztyber 						task->src, g_xfer_size_bytes, accel_done, task);
7270ef079c6Spaul luse 		break;
7285105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COMPRESS:
72927e85f52SBen Walker 		task->src_iovs = task->cur_seg->uncompressed_iovs;
73027e85f52SBen Walker 		task->src_iovcnt = task->cur_seg->uncompressed_iovcnt;
7316afbf3dbSpaul luse 		rc = spdk_accel_submit_compress(worker->ch, task->dst, task->cur_seg->compressed_len_padded,
7326afbf3dbSpaul luse 						task->src_iovs,
73379e2a56fSKonrad Sztyber 						task->src_iovcnt, &task->compressed_sz, accel_done, task);
73427e85f52SBen Walker 		break;
7355105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_DECOMPRESS:
73627e85f52SBen Walker 		task->src_iovs = task->cur_seg->compressed_iovs;
73727e85f52SBen Walker 		task->src_iovcnt = task->cur_seg->compressed_iovcnt;
73827e85f52SBen Walker 		rc = spdk_accel_submit_decompress(worker->ch, task->dst_iovs, task->dst_iovcnt, task->src_iovs,
73979e2a56fSKonrad Sztyber 						  task->src_iovcnt, NULL, accel_done, task);
74027e85f52SBen Walker 		break;
7415105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_XOR:
742a5d5ab27SArtur Paszkiewicz 		rc = spdk_accel_submit_xor(worker->ch, task->dst, task->sources, g_xor_src_count,
743a5d5ab27SArtur Paszkiewicz 					   g_xfer_size_bytes, accel_done, task);
744a5d5ab27SArtur Paszkiewicz 		break;
74544bf79a8SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY:
74644bf79a8SKrzysztof Sprzaczkowski 		rc = spdk_accel_submit_dif_verify(worker->ch, task->src_iovs, task->src_iovcnt, task->num_blocks,
74744bf79a8SKrzysztof Sprzaczkowski 						  &task->dif_ctx, &task->dif_err, accel_done, task);
74844bf79a8SKrzysztof Sprzaczkowski 		break;
749ee2adf2eSKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_GENERATE:
750ee2adf2eSKrzysztof Sprzaczkowski 		rc = spdk_accel_submit_dif_generate(worker->ch, task->src_iovs, task->src_iovcnt, task->num_blocks,
751ee2adf2eSKrzysztof Sprzaczkowski 						    &task->dif_ctx, accel_done, task);
752ee2adf2eSKrzysztof Sprzaczkowski 		break;
753fbe2860eSKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
754fbe2860eSKrzysztof Sprzaczkowski 		rc = spdk_accel_submit_dif_generate_copy(worker->ch, task->dst_iovs, task->dst_iovcnt,
755fbe2860eSKrzysztof Sprzaczkowski 				task->src_iovs, task->src_iovcnt,
756fbe2860eSKrzysztof Sprzaczkowski 				task->num_blocks, &task->dif_ctx, accel_done, task);
757fbe2860eSKrzysztof Sprzaczkowski 		break;
75897457e44SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY_COPY:
75997457e44SKrzysztof Sprzaczkowski 		rc = spdk_accel_submit_dif_verify_copy(worker->ch, task->dst_iovs, task->dst_iovcnt,
76097457e44SKrzysztof Sprzaczkowski 						       task->src_iovs, task->src_iovcnt, task->num_blocks,
76197457e44SKrzysztof Sprzaczkowski 						       &task->dif_ctx, &task->dif_err, accel_done, task);
76297457e44SKrzysztof Sprzaczkowski 		break;
76380dfab0aSKrzysztof Karas 	case SPDK_ACCEL_OPC_DIX_GENERATE:
76480dfab0aSKrzysztof Karas 		rc = spdk_accel_submit_dix_generate(worker->ch, task->src_iovs, task->src_iovcnt,
76580dfab0aSKrzysztof Karas 						    &task->md_iov, task->num_blocks,
76680dfab0aSKrzysztof Karas 						    &task->dif_ctx, accel_done, task);
76780dfab0aSKrzysztof Karas 		break;
76880dfab0aSKrzysztof Karas 	case SPDK_ACCEL_OPC_DIX_VERIFY:
76980dfab0aSKrzysztof Karas 		rc = spdk_accel_submit_dix_verify(worker->ch, task->src_iovs, task->src_iovcnt,
77080dfab0aSKrzysztof Karas 						  &task->md_iov, task->num_blocks,
77180dfab0aSKrzysztof Karas 						  &task->dif_ctx, &task->dif_err, accel_done, task);
77280dfab0aSKrzysztof Karas 		break;
773e69375bfSpaul luse 	default:
7742a0c66d0Spaul luse 		assert(false);
775e69375bfSpaul luse 		break;
776e69375bfSpaul luse 
7772a0c66d0Spaul luse 	}
77840ec8e97Spaul luse 
7796799d46aSpaul luse 	worker->current_queue_depth++;
78040ec8e97Spaul luse 	if (rc) {
781e8463f87Spaul luse 		accel_done(task, rc);
78240ec8e97Spaul luse 	}
7839f51cf32Spaul luse }
7849f51cf32Spaul luse 
7859f51cf32Spaul luse static void
786e150f6b8SZiye Yang _free_task_buffers(struct ap_task *task)
787ac9a1a83Spaul luse {
78888754353SZiye Yang 	uint32_t i;
78988754353SZiye Yang 
7905105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS ||
7915105dc5dSKonrad Sztyber 	    g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
79227e85f52SBen Walker 		free(task->dst_iovs);
7935105dc5dSKonrad Sztyber 	} else if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
79444bf79a8SKrzysztof Sprzaczkowski 		   g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
795fbe2860eSKrzysztof Sprzaczkowski 		   g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
796ee2adf2eSKrzysztof Sprzaczkowski 		   g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
79797457e44SKrzysztof Sprzaczkowski 		   g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY ||
79880dfab0aSKrzysztof Karas 		   g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY_COPY ||
79980dfab0aSKrzysztof Karas 		   g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY ||
80080dfab0aSKrzysztof Karas 		   g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE) {
80181beca34SMoshe Shahar 		if (task->crc_dst) {
80281beca34SMoshe Shahar 			spdk_dma_free(task->crc_dst);
80381beca34SMoshe Shahar 		}
80428886ac3Spaul luse 		if (task->src_iovs) {
80528886ac3Spaul luse 			for (i = 0; i < task->src_iovcnt; i++) {
80628886ac3Spaul luse 				if (task->src_iovs[i].iov_base) {
80728886ac3Spaul luse 					spdk_dma_free(task->src_iovs[i].iov_base);
80888754353SZiye Yang 				}
80988754353SZiye Yang 			}
81028886ac3Spaul luse 			free(task->src_iovs);
81188754353SZiye Yang 		}
81297457e44SKrzysztof Sprzaczkowski 		if (task->dst_iovs) {
81397457e44SKrzysztof Sprzaczkowski 			for (i = 0; i < task->dst_iovcnt; i++) {
81497457e44SKrzysztof Sprzaczkowski 				if (task->dst_iovs[i].iov_base) {
81597457e44SKrzysztof Sprzaczkowski 					spdk_dma_free(task->dst_iovs[i].iov_base);
81697457e44SKrzysztof Sprzaczkowski 				}
81797457e44SKrzysztof Sprzaczkowski 			}
81897457e44SKrzysztof Sprzaczkowski 			free(task->dst_iovs);
81997457e44SKrzysztof Sprzaczkowski 		}
82080dfab0aSKrzysztof Karas 		if (task->md_iov.iov_base) {
82180dfab0aSKrzysztof Karas 			spdk_dma_free(task->md_iov.iov_base);
82280dfab0aSKrzysztof Karas 		}
8235105dc5dSKonrad Sztyber 	} else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
824a5d5ab27SArtur Paszkiewicz 		if (task->sources) {
825a5d5ab27SArtur Paszkiewicz 			for (i = 0; i < g_xor_src_count; i++) {
826a5d5ab27SArtur Paszkiewicz 				spdk_dma_free(task->sources[i]);
827a5d5ab27SArtur Paszkiewicz 			}
828a5d5ab27SArtur Paszkiewicz 			free(task->sources);
829a5d5ab27SArtur Paszkiewicz 		}
83088754353SZiye Yang 	} else {
831ac9a1a83Spaul luse 		spdk_dma_free(task->src);
83288754353SZiye Yang 	}
83388754353SZiye Yang 
834ac9a1a83Spaul luse 	spdk_dma_free(task->dst);
8355105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST || g_workload_selection == SPDK_ACCEL_OPC_XOR) {
836ac9a1a83Spaul luse 		spdk_dma_free(task->dst2);
837ac9a1a83Spaul luse 	}
838ac9a1a83Spaul luse }
839ac9a1a83Spaul luse 
840221eb3f4Spaul luse static int
84128886ac3Spaul luse _vector_memcmp(void *_dst, struct iovec *src_src_iovs, uint32_t iovcnt)
842221eb3f4Spaul luse {
843221eb3f4Spaul luse 	uint32_t i;
844221eb3f4Spaul luse 	uint32_t ttl_len = 0;
845221eb3f4Spaul luse 	uint8_t *dst = (uint8_t *)_dst;
846221eb3f4Spaul luse 
847221eb3f4Spaul luse 	for (i = 0; i < iovcnt; i++) {
84828886ac3Spaul luse 		if (memcmp(dst, src_src_iovs[i].iov_base, src_src_iovs[i].iov_len)) {
849221eb3f4Spaul luse 			return -1;
850221eb3f4Spaul luse 		}
85128886ac3Spaul luse 		dst += src_src_iovs[i].iov_len;
85228886ac3Spaul luse 		ttl_len += src_src_iovs[i].iov_len;
853221eb3f4Spaul luse 	}
854221eb3f4Spaul luse 
855221eb3f4Spaul luse 	if (ttl_len != iovcnt * g_xfer_size_bytes) {
856221eb3f4Spaul luse 		return -1;
857221eb3f4Spaul luse 	}
858221eb3f4Spaul luse 
859221eb3f4Spaul luse 	return 0;
860221eb3f4Spaul luse }
861221eb3f4Spaul luse 
86213067997Spaul luse static int _worker_stop(void *arg);
86313067997Spaul luse 
864fab40895Spaul luse static void
865df42f358Spaul luse accel_done(void *arg1, int status)
8669f51cf32Spaul luse {
8679f51cf32Spaul luse 	struct ap_task *task = arg1;
8689f51cf32Spaul luse 	struct worker_thread *worker = task->worker;
869e69375bfSpaul luse 	uint32_t sw_crc32c;
870fbe2860eSKrzysztof Sprzaczkowski 	struct spdk_dif_error err_blk;
8719f51cf32Spaul luse 
8729f51cf32Spaul luse 	assert(worker);
8739f51cf32Spaul luse 	assert(worker->current_queue_depth > 0);
8749f51cf32Spaul luse 
875df42f358Spaul luse 	if (g_verify && status == 0) {
87613067997Spaul luse 		switch (worker->workload) {
8775105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_COPY_CRC32C:
87828886ac3Spaul luse 			sw_crc32c = spdk_crc32c_iov_update(task->src_iovs, task->src_iovcnt, ~g_crc32c_seed);
87981beca34SMoshe Shahar 			if (*task->crc_dst != sw_crc32c) {
880221eb3f4Spaul luse 				SPDK_NOTICELOG("CRC-32C miscompare\n");
881221eb3f4Spaul luse 				worker->xfer_failed++;
882221eb3f4Spaul luse 			}
88328886ac3Spaul luse 			if (_vector_memcmp(task->dst, task->src_iovs, task->src_iovcnt)) {
884221eb3f4Spaul luse 				SPDK_NOTICELOG("Data miscompare\n");
885221eb3f4Spaul luse 				worker->xfer_failed++;
886221eb3f4Spaul luse 			}
887221eb3f4Spaul luse 			break;
8885105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_CRC32C:
88928886ac3Spaul luse 			sw_crc32c = spdk_crc32c_iov_update(task->src_iovs, task->src_iovcnt, ~g_crc32c_seed);
89081beca34SMoshe Shahar 			if (*task->crc_dst != sw_crc32c) {
891e69375bfSpaul luse 				SPDK_NOTICELOG("CRC-32C miscompare\n");
892e69375bfSpaul luse 				worker->xfer_failed++;
893e69375bfSpaul luse 			}
894b9218b7aSpaul luse 			break;
8955105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_COPY:
896b9218b7aSpaul luse 			if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
8979f51cf32Spaul luse 				SPDK_NOTICELOG("Data miscompare\n");
8989f51cf32Spaul luse 				worker->xfer_failed++;
899b9218b7aSpaul luse 			}
900b9218b7aSpaul luse 			break;
9015105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_DUALCAST:
9020ef079c6Spaul luse 			if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
9030ef079c6Spaul luse 				SPDK_NOTICELOG("Data miscompare, first destination\n");
9040ef079c6Spaul luse 				worker->xfer_failed++;
9050ef079c6Spaul luse 			}
9060ef079c6Spaul luse 			if (memcmp(task->src, task->dst2, g_xfer_size_bytes)) {
9070ef079c6Spaul luse 				SPDK_NOTICELOG("Data miscompare, second destination\n");
9080ef079c6Spaul luse 				worker->xfer_failed++;
9090ef079c6Spaul luse 			}
9100ef079c6Spaul luse 			break;
9115105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_FILL:
912d207237fSpaul luse 			if (memcmp(task->dst, task->src, g_xfer_size_bytes)) {
913d207237fSpaul luse 				SPDK_NOTICELOG("Data miscompare\n");
914d207237fSpaul luse 				worker->xfer_failed++;
915d207237fSpaul luse 			}
916d207237fSpaul luse 			break;
9175105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_COMPARE:
9188cee297cSpaul luse 			break;
9195105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_COMPRESS:
92027e85f52SBen Walker 			break;
9215105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_DECOMPRESS:
92227e85f52SBen Walker 			if (memcmp(task->dst, task->cur_seg->uncompressed_data, task->cur_seg->uncompressed_len)) {
92327e85f52SBen Walker 				SPDK_NOTICELOG("Data miscompare on decompression\n");
92427e85f52SBen Walker 				worker->xfer_failed++;
92527e85f52SBen Walker 			}
92627e85f52SBen Walker 			break;
9275105dc5dSKonrad Sztyber 		case SPDK_ACCEL_OPC_XOR:
928a5d5ab27SArtur Paszkiewicz 			if (spdk_xor_gen(task->dst2, task->sources, g_xor_src_count,
929a5d5ab27SArtur Paszkiewicz 					 g_xfer_size_bytes) != 0) {
930a5d5ab27SArtur Paszkiewicz 				SPDK_ERRLOG("Failed to generate xor for verification\n");
931a5d5ab27SArtur Paszkiewicz 			} else if (memcmp(task->dst, task->dst2, g_xfer_size_bytes)) {
932a5d5ab27SArtur Paszkiewicz 				SPDK_NOTICELOG("Data miscompare\n");
933a5d5ab27SArtur Paszkiewicz 				worker->xfer_failed++;
934a5d5ab27SArtur Paszkiewicz 			}
935a5d5ab27SArtur Paszkiewicz 			break;
93644bf79a8SKrzysztof Sprzaczkowski 		case SPDK_ACCEL_OPC_DIF_VERIFY:
93744bf79a8SKrzysztof Sprzaczkowski 			break;
938ee2adf2eSKrzysztof Sprzaczkowski 		case SPDK_ACCEL_OPC_DIF_GENERATE:
939ee2adf2eSKrzysztof Sprzaczkowski 			if (spdk_dif_verify(task->src_iovs, task->src_iovcnt, task->num_blocks,
940ee2adf2eSKrzysztof Sprzaczkowski 					    &task->dif_ctx, &err_blk) != 0) {
941ee2adf2eSKrzysztof Sprzaczkowski 				SPDK_NOTICELOG("Data miscompare, "
942ee2adf2eSKrzysztof Sprzaczkowski 					       "err_type %u, expected %lu, actual %lu, err_offset %u\n",
943ee2adf2eSKrzysztof Sprzaczkowski 					       err_blk.err_type, err_blk.expected,
944ee2adf2eSKrzysztof Sprzaczkowski 					       err_blk.actual, err_blk.err_offset);
945ee2adf2eSKrzysztof Sprzaczkowski 				worker->xfer_failed++;
946ee2adf2eSKrzysztof Sprzaczkowski 			}
947ee2adf2eSKrzysztof Sprzaczkowski 			break;
948fbe2860eSKrzysztof Sprzaczkowski 		case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
949fbe2860eSKrzysztof Sprzaczkowski 			if (spdk_dif_verify(task->dst_iovs, task->dst_iovcnt, task->num_blocks,
950fbe2860eSKrzysztof Sprzaczkowski 					    &task->dif_ctx, &err_blk) != 0) {
951fbe2860eSKrzysztof Sprzaczkowski 				SPDK_NOTICELOG("Data miscompare, "
952fbe2860eSKrzysztof Sprzaczkowski 					       "err_type %u, expected %lu, actual %lu, err_offset %u\n",
953fbe2860eSKrzysztof Sprzaczkowski 					       err_blk.err_type, err_blk.expected,
954fbe2860eSKrzysztof Sprzaczkowski 					       err_blk.actual, err_blk.err_offset);
955fbe2860eSKrzysztof Sprzaczkowski 				worker->xfer_failed++;
956fbe2860eSKrzysztof Sprzaczkowski 			}
957fbe2860eSKrzysztof Sprzaczkowski 			break;
95897457e44SKrzysztof Sprzaczkowski 		case SPDK_ACCEL_OPC_DIF_VERIFY_COPY:
95997457e44SKrzysztof Sprzaczkowski 			break;
96080dfab0aSKrzysztof Karas 		case SPDK_ACCEL_OPC_DIX_GENERATE:
96180dfab0aSKrzysztof Karas 			if (spdk_dix_verify(task->src_iovs, task->src_iovcnt, &task->md_iov,
96280dfab0aSKrzysztof Karas 					    task->num_blocks, &task->dif_ctx, &err_blk) != 0) {
96380dfab0aSKrzysztof Karas 				SPDK_NOTICELOG("Data miscompare, "
96480dfab0aSKrzysztof Karas 					       "err_type %u, expected %lu, actual %lu, err_offset %u\n",
96580dfab0aSKrzysztof Karas 					       err_blk.err_type, err_blk.expected,
96680dfab0aSKrzysztof Karas 					       err_blk.actual, err_blk.err_offset);
96780dfab0aSKrzysztof Karas 				worker->xfer_failed++;
96880dfab0aSKrzysztof Karas 			}
96980dfab0aSKrzysztof Karas 			break;
97080dfab0aSKrzysztof Karas 		case SPDK_ACCEL_OPC_DIX_VERIFY:
97180dfab0aSKrzysztof Karas 			break;
972b9218b7aSpaul luse 		default:
973b9218b7aSpaul luse 			assert(false);
974b9218b7aSpaul luse 			break;
9759f51cf32Spaul luse 		}
9769f51cf32Spaul luse 	}
977b9218b7aSpaul luse 
9785105dc5dSKonrad Sztyber 	if (worker->workload == SPDK_ACCEL_OPC_COMPRESS ||
9795105dc5dSKonrad Sztyber 	    g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
98027e85f52SBen Walker 		/* Advance the task to the next segment */
98127e85f52SBen Walker 		task->cur_seg = STAILQ_NEXT(task->cur_seg, link);
98227e85f52SBen Walker 		if (task->cur_seg == NULL) {
98327e85f52SBen Walker 			task->cur_seg = STAILQ_FIRST(&g_compress_segs);
98427e85f52SBen Walker 		}
98527e85f52SBen Walker 	}
98627e85f52SBen Walker 
987b9218b7aSpaul luse 	if (task->expected_status == -EILSEQ) {
988df42f358Spaul luse 		assert(status != 0);
989b9218b7aSpaul luse 		worker->injected_miscompares++;
99013067997Spaul luse 		status = 0;
991df42f358Spaul luse 	} else if (status) {
992712e8cb7SBen Walker 		/* Expected to pass but the accel module reported an error (ex: COMPARE operation). */
993b9218b7aSpaul luse 		worker->xfer_failed++;
994b9218b7aSpaul luse 	}
995b9218b7aSpaul luse 
9969f51cf32Spaul luse 	worker->current_queue_depth--;
9979f51cf32Spaul luse 
99813067997Spaul luse 	if (!worker->is_draining && status == 0) {
999451462f6SJim Harris 		TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
1000451462f6SJim Harris 		task = _get_task(worker);
10019f51cf32Spaul luse 		_submit_single(worker, task);
1002f17e6705Spaul luse 	} else {
1003b34883e0SZiye Yang 		TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
1004f17e6705Spaul luse 	}
10059f51cf32Spaul luse }
10069f51cf32Spaul luse 
10079f51cf32Spaul luse static int
10089f51cf32Spaul luse dump_result(void)
10099f51cf32Spaul luse {
10109f51cf32Spaul luse 	uint64_t total_completed = 0;
10119f51cf32Spaul luse 	uint64_t total_failed = 0;
1012b9218b7aSpaul luse 	uint64_t total_miscompared = 0;
1013e7cce062SGang Cao 	uint64_t total_xfer_per_sec, total_bw_in_MiBps = 0;
10149f51cf32Spaul luse 	struct worker_thread *worker = g_workers;
10159424e9ebSKonrad Sztyber 	char tmp[64];
10169f51cf32Spaul luse 
10179424e9ebSKonrad Sztyber 	printf("\n%-12s %20s %16s %16s %16s\n",
10189424e9ebSKonrad Sztyber 	       "Core,Thread", "Transfers", "Bandwidth", "Failed", "Miscompares");
10199424e9ebSKonrad Sztyber 	printf("------------------------------------------------------------------------------------\n");
10209f51cf32Spaul luse 	while (worker != NULL) {
10219f51cf32Spaul luse 
1022e3babb2bSKonrad Sztyber 		uint64_t xfer_per_sec = worker->stats.executed / g_time_in_sec;
1023e3babb2bSKonrad Sztyber 		uint64_t bw_in_MiBps = worker->stats.num_bytes /
10249f51cf32Spaul luse 				       (g_time_in_sec * 1024 * 1024);
10259f51cf32Spaul luse 
1026e3babb2bSKonrad Sztyber 		total_completed += worker->stats.executed;
10279f51cf32Spaul luse 		total_failed += worker->xfer_failed;
1028b9218b7aSpaul luse 		total_miscompared += worker->injected_miscompares;
1029e7cce062SGang Cao 		total_bw_in_MiBps += bw_in_MiBps;
10309f51cf32Spaul luse 
10319424e9ebSKonrad Sztyber 		snprintf(tmp, sizeof(tmp), "%u,%u", worker->display.core, worker->display.thread);
10329f51cf32Spaul luse 		if (xfer_per_sec) {
10339424e9ebSKonrad Sztyber 			printf("%-12s %18" PRIu64 "/s %10" PRIu64 " MiB/s %16"PRIu64 " %16" PRIu64 "\n",
10349424e9ebSKonrad Sztyber 			       tmp, xfer_per_sec, bw_in_MiBps, worker->xfer_failed,
10359424e9ebSKonrad Sztyber 			       worker->injected_miscompares);
10369f51cf32Spaul luse 		}
10379f51cf32Spaul luse 
10389f51cf32Spaul luse 		worker = worker->next;
10399f51cf32Spaul luse 	}
10409f51cf32Spaul luse 
10419f51cf32Spaul luse 	total_xfer_per_sec = total_completed / g_time_in_sec;
10429f51cf32Spaul luse 
10439424e9ebSKonrad Sztyber 	printf("====================================================================================\n");
10449424e9ebSKonrad Sztyber 	printf("%-12s %18" PRIu64 "/s %10" PRIu64 " MiB/s %16"PRIu64 " %16" PRIu64 "\n",
10459424e9ebSKonrad Sztyber 	       "Total", total_xfer_per_sec, total_bw_in_MiBps, total_failed, total_miscompared);
10469f51cf32Spaul luse 
10479f51cf32Spaul luse 	return total_failed ? 1 : 0;
10489f51cf32Spaul luse }
10499f51cf32Spaul luse 
1050e150f6b8SZiye Yang static inline void
1051e150f6b8SZiye Yang _free_task_buffers_in_pool(struct worker_thread *worker)
1052e150f6b8SZiye Yang {
1053e150f6b8SZiye Yang 	struct ap_task *task;
1054e150f6b8SZiye Yang 
1055e150f6b8SZiye Yang 	assert(worker);
1056e150f6b8SZiye Yang 	while ((task = TAILQ_FIRST(&worker->tasks_pool))) {
1057e150f6b8SZiye Yang 		TAILQ_REMOVE(&worker->tasks_pool, task, link);
1058e150f6b8SZiye Yang 		_free_task_buffers(task);
1059e150f6b8SZiye Yang 	}
1060e150f6b8SZiye Yang }
1061e150f6b8SZiye Yang 
10629f51cf32Spaul luse static int
10639f51cf32Spaul luse _check_draining(void *arg)
10649f51cf32Spaul luse {
10659f51cf32Spaul luse 	struct worker_thread *worker = arg;
10669f51cf32Spaul luse 
10679f51cf32Spaul luse 	assert(worker);
10689f51cf32Spaul luse 
10699f51cf32Spaul luse 	if (worker->current_queue_depth == 0) {
1070e150f6b8SZiye Yang 		_free_task_buffers_in_pool(worker);
10719f51cf32Spaul luse 		spdk_poller_unregister(&worker->is_draining_poller);
10729f51cf32Spaul luse 		unregister_worker(worker);
10739f51cf32Spaul luse 	}
10749f51cf32Spaul luse 
1075fa9e703fSpaul Luse 	return SPDK_POLLER_BUSY;
10769f51cf32Spaul luse }
10779f51cf32Spaul luse 
10789f51cf32Spaul luse static int
10799f51cf32Spaul luse _worker_stop(void *arg)
10809f51cf32Spaul luse {
10819f51cf32Spaul luse 	struct worker_thread *worker = arg;
10829f51cf32Spaul luse 
10839f51cf32Spaul luse 	assert(worker);
10849f51cf32Spaul luse 
10859f51cf32Spaul luse 	spdk_poller_unregister(&worker->stop_poller);
10869f51cf32Spaul luse 
10879f51cf32Spaul luse 	/* now let the worker drain and check it's outstanding IO with a poller */
10889f51cf32Spaul luse 	worker->is_draining = true;
1089ab0bc5c2SShuhei Matsumoto 	worker->is_draining_poller = SPDK_POLLER_REGISTER(_check_draining, worker, 0);
10909f51cf32Spaul luse 
1091fa9e703fSpaul Luse 	return SPDK_POLLER_BUSY;
10929f51cf32Spaul luse }
10939f51cf32Spaul luse 
109420b5c460STomasz Zawadzki static void shutdown_cb(void);
109520b5c460STomasz Zawadzki 
10969f51cf32Spaul luse static void
1097a34fc12bSpaul luse _init_thread(void *arg1)
1098a34fc12bSpaul luse {
1099a34fc12bSpaul luse 	struct worker_thread *worker;
1100a34fc12bSpaul luse 	struct ap_task *task;
1101998b5d66Spaul luse 	int i, num_tasks = g_allocate_depth;
1102445fe74eSpaul luse 	struct display_info *display = arg1;
1103a34fc12bSpaul luse 
1104a34fc12bSpaul luse 	worker = calloc(1, sizeof(*worker));
1105a34fc12bSpaul luse 	if (worker == NULL) {
1106a34fc12bSpaul luse 		fprintf(stderr, "Unable to allocate worker\n");
1107445fe74eSpaul luse 		free(display);
110820b5c460STomasz Zawadzki 		spdk_thread_exit(spdk_get_thread());
110920b5c460STomasz Zawadzki 		goto no_worker;
1110a34fc12bSpaul luse 	}
1111a34fc12bSpaul luse 
111213067997Spaul luse 	worker->workload = g_workload_selection;
1113445fe74eSpaul luse 	worker->display.core = display->core;
1114445fe74eSpaul luse 	worker->display.thread = display->thread;
1115445fe74eSpaul luse 	free(display);
11169f51cf32Spaul luse 	worker->core = spdk_env_get_current_core();
11179f51cf32Spaul luse 	worker->thread = spdk_get_thread();
1118eea826a2Spaul luse 	pthread_mutex_lock(&g_workers_lock);
1119eea826a2Spaul luse 	g_num_workers++;
11209f51cf32Spaul luse 	worker->next = g_workers;
1121eea826a2Spaul luse 	g_workers = worker;
1122eea826a2Spaul luse 	pthread_mutex_unlock(&g_workers_lock);
112334c48f1bSBen Walker 	worker->ch = spdk_accel_get_io_channel();
11242dd64cf9Spaul luse 	if (worker->ch == NULL) {
11252dd64cf9Spaul luse 		fprintf(stderr, "Unable to get an accel channel\n");
11262dd64cf9Spaul luse 		goto error;
11272dd64cf9Spaul luse 	}
1128b9218b7aSpaul luse 
1129f17e6705Spaul luse 	TAILQ_INIT(&worker->tasks_pool);
1130f17e6705Spaul luse 
1131ac9a1a83Spaul luse 	worker->task_base = calloc(num_tasks, sizeof(struct ap_task));
1132ac9a1a83Spaul luse 	if (worker->task_base == NULL) {
1133ac9a1a83Spaul luse 		fprintf(stderr, "Could not allocate task base.\n");
1134ac9a1a83Spaul luse 		goto error;
11350cecfcb1Spaul luse 	}
1136ac9a1a83Spaul luse 
1137ac9a1a83Spaul luse 	task = worker->task_base;
1138ac9a1a83Spaul luse 	for (i = 0; i < num_tasks; i++) {
1139ac9a1a83Spaul luse 		TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
11404cd7ca9bSJim Harris 		task->worker = worker;
1141ac9a1a83Spaul luse 		if (_get_task_data_bufs(task)) {
1142ac9a1a83Spaul luse 			fprintf(stderr, "Unable to get data bufs\n");
1143ac9a1a83Spaul luse 			goto error;
1144ac9a1a83Spaul luse 		}
1145ac9a1a83Spaul luse 		task++;
11469f51cf32Spaul luse 	}
11479f51cf32Spaul luse 
11489f51cf32Spaul luse 	/* Register a poller that will stop the worker at time elapsed */
1149ab0bc5c2SShuhei Matsumoto 	worker->stop_poller = SPDK_POLLER_REGISTER(_worker_stop, worker,
11509f51cf32Spaul luse 			      g_time_in_sec * 1000000ULL);
11519f51cf32Spaul luse 
1152998b5d66Spaul luse 	/* Load up queue depth worth of operations. */
1153998b5d66Spaul luse 	for (i = 0; i < g_queue_depth; i++) {
1154ac9a1a83Spaul luse 		task = _get_task(worker);
1155ac9a1a83Spaul luse 		if (task == NULL) {
1156a34fc12bSpaul luse 			goto error;
1157b9218b7aSpaul luse 		}
1158b9218b7aSpaul luse 
11599f51cf32Spaul luse 		_submit_single(worker, task);
11609f51cf32Spaul luse 	}
1161a34fc12bSpaul luse 	return;
1162a34fc12bSpaul luse error:
1163e150f6b8SZiye Yang 
1164e150f6b8SZiye Yang 	_free_task_buffers_in_pool(worker);
1165ac9a1a83Spaul luse 	free(worker->task_base);
1166*975c1df9SAlexey Marchuk 	worker->task_base = NULL;
116720b5c460STomasz Zawadzki no_worker:
116820b5c460STomasz Zawadzki 	shutdown_cb();
116920b5c460STomasz Zawadzki 	g_rc = -1;
11709f51cf32Spaul luse }
11719f51cf32Spaul luse 
11729f51cf32Spaul luse static void
11739f51cf32Spaul luse accel_perf_start(void *arg1)
11749f51cf32Spaul luse {
1175eea826a2Spaul luse 	struct spdk_cpuset tmp_cpumask = {};
1176eea826a2Spaul luse 	char thread_name[32];
1177eea826a2Spaul luse 	uint32_t i;
1178445fe74eSpaul luse 	int j;
1179eea826a2Spaul luse 	struct spdk_thread *thread;
1180445fe74eSpaul luse 	struct display_info *display;
1181514be889Spaul luse 
11829f51cf32Spaul luse 	g_tsc_rate = spdk_get_ticks_hz();
11839f51cf32Spaul luse 	g_tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate;
11849f51cf32Spaul luse 
11859260fa0cSpaul luse 	dump_user_config();
11869260fa0cSpaul luse 
11879f51cf32Spaul luse 	printf("Running for %d seconds...\n", g_time_in_sec);
11889f51cf32Spaul luse 	fflush(stdout);
11899f51cf32Spaul luse 
1190eea826a2Spaul luse 	/* Create worker threads for each core that was specified. */
1191eea826a2Spaul luse 	SPDK_ENV_FOREACH_CORE(i) {
1192445fe74eSpaul luse 		for (j = 0; j < g_threads_per_core; j++) {
1193445fe74eSpaul luse 			snprintf(thread_name, sizeof(thread_name), "ap_worker_%u_%u", i, j);
1194eea826a2Spaul luse 			spdk_cpuset_zero(&tmp_cpumask);
1195eea826a2Spaul luse 			spdk_cpuset_set_cpu(&tmp_cpumask, i, true);
1196eea826a2Spaul luse 			thread = spdk_thread_create(thread_name, &tmp_cpumask);
1197445fe74eSpaul luse 			display = calloc(1, sizeof(*display));
1198445fe74eSpaul luse 			if (display == NULL) {
1199445fe74eSpaul luse 				fprintf(stderr, "Unable to allocate memory\n");
1200445fe74eSpaul luse 				spdk_app_stop(-1);
1201445fe74eSpaul luse 				return;
1202445fe74eSpaul luse 			}
1203445fe74eSpaul luse 			display->core = i;
1204445fe74eSpaul luse 			display->thread = j;
1205445fe74eSpaul luse 			spdk_thread_send_msg(thread, _init_thread, display);
1206445fe74eSpaul luse 		}
1207eea826a2Spaul luse 	}
12089f51cf32Spaul luse }
12099f51cf32Spaul luse 
121027e85f52SBen Walker static void
121127e85f52SBen Walker accel_perf_free_compress_segs(void)
121227e85f52SBen Walker {
121327e85f52SBen Walker 	struct ap_compress_seg *seg, *tmp;
121427e85f52SBen Walker 
121527e85f52SBen Walker 	STAILQ_FOREACH_SAFE(seg, &g_compress_segs, link, tmp) {
121627e85f52SBen Walker 		free(seg->uncompressed_iovs);
121727e85f52SBen Walker 		free(seg->compressed_iovs);
121827e85f52SBen Walker 		spdk_dma_free(seg->compressed_data);
121927e85f52SBen Walker 		spdk_dma_free(seg->uncompressed_data);
122027e85f52SBen Walker 		STAILQ_REMOVE_HEAD(&g_compress_segs, link);
122127e85f52SBen Walker 		free(seg);
122227e85f52SBen Walker 	}
122327e85f52SBen Walker }
122427e85f52SBen Walker 
122527e85f52SBen Walker struct accel_perf_prep_ctx {
122627e85f52SBen Walker 	FILE			*file;
122727e85f52SBen Walker 	long			remaining;
122827e85f52SBen Walker 	struct spdk_io_channel	*ch;
122927e85f52SBen Walker 	struct ap_compress_seg	*cur_seg;
123027e85f52SBen Walker };
123127e85f52SBen Walker 
123227e85f52SBen Walker static void accel_perf_prep_process_seg(struct accel_perf_prep_ctx *ctx);
123327e85f52SBen Walker 
123427e85f52SBen Walker static void
123527e85f52SBen Walker accel_perf_prep_process_seg_cpl(void *ref, int status)
123627e85f52SBen Walker {
123727e85f52SBen Walker 	struct accel_perf_prep_ctx *ctx = ref;
123827e85f52SBen Walker 	struct ap_compress_seg *seg;
123927e85f52SBen Walker 
124027e85f52SBen Walker 	if (status != 0) {
124127e85f52SBen Walker 		fprintf(stderr, "error (%d) on initial compress completion\n", status);
124227e85f52SBen Walker 		spdk_dma_free(ctx->cur_seg->compressed_data);
124327e85f52SBen Walker 		spdk_dma_free(ctx->cur_seg->uncompressed_data);
124427e85f52SBen Walker 		free(ctx->cur_seg);
124527e85f52SBen Walker 		spdk_put_io_channel(ctx->ch);
124627e85f52SBen Walker 		fclose(ctx->file);
124727e85f52SBen Walker 		free(ctx);
124827e85f52SBen Walker 		spdk_app_stop(-status);
124927e85f52SBen Walker 		return;
125027e85f52SBen Walker 	}
125127e85f52SBen Walker 
125227e85f52SBen Walker 	seg = ctx->cur_seg;
125327e85f52SBen Walker 
12545105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
125527e85f52SBen Walker 		seg->compressed_iovs = calloc(g_chained_count, sizeof(struct iovec));
125627e85f52SBen Walker 		if (seg->compressed_iovs == NULL) {
125727e85f52SBen Walker 			fprintf(stderr, "unable to allocate iovec\n");
125827e85f52SBen Walker 			spdk_dma_free(seg->compressed_data);
125927e85f52SBen Walker 			spdk_dma_free(seg->uncompressed_data);
126027e85f52SBen Walker 			free(seg);
126127e85f52SBen Walker 			spdk_put_io_channel(ctx->ch);
126227e85f52SBen Walker 			fclose(ctx->file);
126327e85f52SBen Walker 			free(ctx);
126427e85f52SBen Walker 			spdk_app_stop(-ENOMEM);
126527e85f52SBen Walker 			return;
126627e85f52SBen Walker 		}
126727e85f52SBen Walker 		seg->compressed_iovcnt = g_chained_count;
126827e85f52SBen Walker 
126927e85f52SBen Walker 		accel_perf_construct_iovs(seg->compressed_data, seg->compressed_len, seg->compressed_iovs,
127027e85f52SBen Walker 					  seg->compressed_iovcnt);
127127e85f52SBen Walker 	}
127227e85f52SBen Walker 
127327e85f52SBen Walker 	STAILQ_INSERT_TAIL(&g_compress_segs, seg, link);
127427e85f52SBen Walker 	ctx->remaining -= seg->uncompressed_len;
127527e85f52SBen Walker 
127627e85f52SBen Walker 	accel_perf_prep_process_seg(ctx);
127727e85f52SBen Walker }
127827e85f52SBen Walker 
127927e85f52SBen Walker static void
128027e85f52SBen Walker accel_perf_prep_process_seg(struct accel_perf_prep_ctx *ctx)
128127e85f52SBen Walker {
128227e85f52SBen Walker 	struct ap_compress_seg *seg;
12836afbf3dbSpaul luse 	int sz, sz_read, sz_padded;
128427e85f52SBen Walker 	void *ubuf, *cbuf;
128527e85f52SBen Walker 	struct iovec iov[1];
128627e85f52SBen Walker 	int rc;
128727e85f52SBen Walker 
128827e85f52SBen Walker 	if (ctx->remaining == 0) {
128927e85f52SBen Walker 		spdk_put_io_channel(ctx->ch);
129027e85f52SBen Walker 		fclose(ctx->file);
129127e85f52SBen Walker 		free(ctx);
129227e85f52SBen Walker 		accel_perf_start(NULL);
129327e85f52SBen Walker 		return;
129427e85f52SBen Walker 	}
129527e85f52SBen Walker 
129627e85f52SBen Walker 	sz = spdk_min(ctx->remaining, g_xfer_size_bytes);
12976afbf3dbSpaul luse 	/* Add 10% pad to the compress buffer for incompressible data. Note that a real app
12986afbf3dbSpaul luse 	 * would likely either deal with the failure of not having a large enough buffer
12996afbf3dbSpaul luse 	 * by submitting another operation with a larger one.  Or, like the vbdev module
13006afbf3dbSpaul luse 	 * does, just accept the error and use the data uncompressed marking it as such in
13016afbf3dbSpaul luse 	 * its own metadata so that in the future it doesn't try to decompress uncompressed
13026afbf3dbSpaul luse 	 * data, etc.
13036afbf3dbSpaul luse 	 */
13046afbf3dbSpaul luse 	sz_padded = sz * COMP_BUF_PAD_PERCENTAGE;
130527e85f52SBen Walker 
130627e85f52SBen Walker 	ubuf = spdk_dma_zmalloc(sz, ALIGN_4K, NULL);
130727e85f52SBen Walker 	if (!ubuf) {
130827e85f52SBen Walker 		fprintf(stderr, "unable to allocate uncompress buffer\n");
130927e85f52SBen Walker 		rc = -ENOMEM;
131027e85f52SBen Walker 		goto error;
131127e85f52SBen Walker 	}
131227e85f52SBen Walker 
13136afbf3dbSpaul luse 	cbuf = spdk_dma_malloc(sz_padded, ALIGN_4K, NULL);
131427e85f52SBen Walker 	if (!cbuf) {
131527e85f52SBen Walker 		fprintf(stderr, "unable to allocate compress buffer\n");
131627e85f52SBen Walker 		rc = -ENOMEM;
131727e85f52SBen Walker 		spdk_dma_free(ubuf);
131827e85f52SBen Walker 		goto error;
131927e85f52SBen Walker 	}
132027e85f52SBen Walker 
132127e85f52SBen Walker 	seg = calloc(1, sizeof(*seg));
132227e85f52SBen Walker 	if (!seg) {
132327e85f52SBen Walker 		fprintf(stderr, "unable to allocate comp/decomp segment\n");
132427e85f52SBen Walker 		spdk_dma_free(ubuf);
132527e85f52SBen Walker 		spdk_dma_free(cbuf);
132627e85f52SBen Walker 		rc = -ENOMEM;
132727e85f52SBen Walker 		goto error;
132827e85f52SBen Walker 	}
132927e85f52SBen Walker 
133027e85f52SBen Walker 	sz_read = fread(ubuf, sizeof(uint8_t), sz, ctx->file);
133127e85f52SBen Walker 	if (sz_read != sz) {
133227e85f52SBen Walker 		fprintf(stderr, "unable to read input file\n");
133327e85f52SBen Walker 		free(seg);
133427e85f52SBen Walker 		spdk_dma_free(ubuf);
133527e85f52SBen Walker 		spdk_dma_free(cbuf);
133627e85f52SBen Walker 		rc = -errno;
133727e85f52SBen Walker 		goto error;
133827e85f52SBen Walker 	}
133927e85f52SBen Walker 
13405105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
134127e85f52SBen Walker 		seg->uncompressed_iovs = calloc(g_chained_count, sizeof(struct iovec));
134227e85f52SBen Walker 		if (seg->uncompressed_iovs == NULL) {
134327e85f52SBen Walker 			fprintf(stderr, "unable to allocate iovec\n");
134427e85f52SBen Walker 			free(seg);
134527e85f52SBen Walker 			spdk_dma_free(ubuf);
134627e85f52SBen Walker 			spdk_dma_free(cbuf);
134727e85f52SBen Walker 			rc = -ENOMEM;
134827e85f52SBen Walker 			goto error;
134927e85f52SBen Walker 		}
135027e85f52SBen Walker 		seg->uncompressed_iovcnt = g_chained_count;
135127e85f52SBen Walker 		accel_perf_construct_iovs(ubuf, sz, seg->uncompressed_iovs, seg->uncompressed_iovcnt);
135227e85f52SBen Walker 	}
135327e85f52SBen Walker 
135427e85f52SBen Walker 	seg->uncompressed_data = ubuf;
135527e85f52SBen Walker 	seg->uncompressed_len = sz;
135627e85f52SBen Walker 	seg->compressed_data = cbuf;
135727e85f52SBen Walker 	seg->compressed_len = sz;
13586afbf3dbSpaul luse 	seg->compressed_len_padded = sz_padded;
135927e85f52SBen Walker 
136027e85f52SBen Walker 	ctx->cur_seg = seg;
136127e85f52SBen Walker 	iov[0].iov_base = seg->uncompressed_data;
136227e85f52SBen Walker 	iov[0].iov_len = seg->uncompressed_len;
136327e85f52SBen Walker 	/* Note that anytime a call is made to spdk_accel_submit_compress() there's a chance
136427e85f52SBen Walker 	 * it will fail with -ENOMEM in the event that the destination buffer is not large enough
13656afbf3dbSpaul luse 	 * to hold the compressed data.  This example app simply adds 10% buffer for compressed data
13666afbf3dbSpaul luse 	 * but real applications may want to consider a more sophisticated method.
136727e85f52SBen Walker 	 */
13686afbf3dbSpaul luse 	rc = spdk_accel_submit_compress(ctx->ch, seg->compressed_data, seg->compressed_len_padded, iov, 1,
136979e2a56fSKonrad Sztyber 					&seg->compressed_len, accel_perf_prep_process_seg_cpl, ctx);
137027e85f52SBen Walker 	if (rc < 0) {
137127e85f52SBen Walker 		fprintf(stderr, "error (%d) on initial compress submission\n", rc);
137227e85f52SBen Walker 		goto error;
137327e85f52SBen Walker 	}
137427e85f52SBen Walker 
137527e85f52SBen Walker 	return;
137627e85f52SBen Walker 
137727e85f52SBen Walker error:
137827e85f52SBen Walker 	spdk_put_io_channel(ctx->ch);
137927e85f52SBen Walker 	fclose(ctx->file);
138027e85f52SBen Walker 	free(ctx);
138127e85f52SBen Walker 	spdk_app_stop(rc);
138227e85f52SBen Walker }
138327e85f52SBen Walker 
138427e85f52SBen Walker static void
138527e85f52SBen Walker accel_perf_prep(void *arg1)
138627e85f52SBen Walker {
138727e85f52SBen Walker 	struct accel_perf_prep_ctx *ctx;
13880a6b7098STomasz Zawadzki 	const char *module_name = NULL;
138927e85f52SBen Walker 	int rc = 0;
139027e85f52SBen Walker 
13910a6b7098STomasz Zawadzki 	if (g_module_name) {
13920a6b7098STomasz Zawadzki 		rc = spdk_accel_get_opc_module_name(g_workload_selection, &module_name);
13930a6b7098STomasz Zawadzki 		if (rc != 0 || strcmp(g_module_name, module_name) != 0) {
13940a6b7098STomasz Zawadzki 			fprintf(stderr, "Module '%s' was assigned via JSON config or RPC, instead of '%s'\n",
13950a6b7098STomasz Zawadzki 				module_name, g_module_name);
13960a6b7098STomasz Zawadzki 			fprintf(stderr, "-M option is not compatible with accel_assign_opc RPC\n");
13970a6b7098STomasz Zawadzki 			rc = -EINVAL;
13980a6b7098STomasz Zawadzki 			goto error_end;
13990a6b7098STomasz Zawadzki 		}
14000a6b7098STomasz Zawadzki 	}
14010a6b7098STomasz Zawadzki 
14025105dc5dSKonrad Sztyber 	if (g_workload_selection != SPDK_ACCEL_OPC_COMPRESS &&
14035105dc5dSKonrad Sztyber 	    g_workload_selection != SPDK_ACCEL_OPC_DECOMPRESS) {
140427e85f52SBen Walker 		accel_perf_start(arg1);
140527e85f52SBen Walker 		return;
140627e85f52SBen Walker 	}
140727e85f52SBen Walker 
140827e85f52SBen Walker 	if (g_cd_file_in_name == NULL) {
140927e85f52SBen Walker 		fprintf(stdout, "A filename is required.\n");
141027e85f52SBen Walker 		rc = -EINVAL;
141127e85f52SBen Walker 		goto error_end;
141227e85f52SBen Walker 	}
141327e85f52SBen Walker 
14145105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS && g_verify) {
141527e85f52SBen Walker 		fprintf(stdout, "\nCompression does not support the verify option, aborting.\n");
141627e85f52SBen Walker 		rc = -ENOTSUP;
141727e85f52SBen Walker 		goto error_end;
141827e85f52SBen Walker 	}
141927e85f52SBen Walker 
142027e85f52SBen Walker 	printf("Preparing input file...\n");
142127e85f52SBen Walker 
142227e85f52SBen Walker 	ctx = calloc(1, sizeof(*ctx));
142327e85f52SBen Walker 	if (ctx == NULL) {
142427e85f52SBen Walker 		rc = -ENOMEM;
142527e85f52SBen Walker 		goto error_end;
142627e85f52SBen Walker 	}
142727e85f52SBen Walker 
142827e85f52SBen Walker 	ctx->file = fopen(g_cd_file_in_name, "r");
142927e85f52SBen Walker 	if (ctx->file == NULL) {
143027e85f52SBen Walker 		fprintf(stderr, "Could not open file %s.\n", g_cd_file_in_name);
143127e85f52SBen Walker 		rc = -errno;
143227e85f52SBen Walker 		goto error_ctx;
143327e85f52SBen Walker 	}
143427e85f52SBen Walker 
143527e85f52SBen Walker 	fseek(ctx->file, 0L, SEEK_END);
143627e85f52SBen Walker 	ctx->remaining = ftell(ctx->file);
143727e85f52SBen Walker 	fseek(ctx->file, 0L, SEEK_SET);
143827e85f52SBen Walker 
143927e85f52SBen Walker 	ctx->ch = spdk_accel_get_io_channel();
144027e85f52SBen Walker 	if (ctx->ch == NULL) {
144127e85f52SBen Walker 		rc = -EAGAIN;
144227e85f52SBen Walker 		goto error_file;
144327e85f52SBen Walker 	}
144427e85f52SBen Walker 
144527e85f52SBen Walker 	if (g_xfer_size_bytes == 0) {
144627e85f52SBen Walker 		/* size of 0 means "file at a time" */
144727e85f52SBen Walker 		g_xfer_size_bytes = ctx->remaining;
144827e85f52SBen Walker 	}
144927e85f52SBen Walker 
145027e85f52SBen Walker 	accel_perf_prep_process_seg(ctx);
145127e85f52SBen Walker 	return;
145227e85f52SBen Walker 
145327e85f52SBen Walker error_file:
145427e85f52SBen Walker 	fclose(ctx->file);
145527e85f52SBen Walker error_ctx:
145627e85f52SBen Walker 	free(ctx);
145727e85f52SBen Walker error_end:
145827e85f52SBen Walker 	spdk_app_stop(rc);
145927e85f52SBen Walker }
146027e85f52SBen Walker 
14614c7b5046SKonrad Sztyber static void
14624c7b5046SKonrad Sztyber worker_shutdown(void *ctx)
14634c7b5046SKonrad Sztyber {
14644c7b5046SKonrad Sztyber 	_worker_stop(ctx);
14654c7b5046SKonrad Sztyber }
14664c7b5046SKonrad Sztyber 
14674c7b5046SKonrad Sztyber static void
14684c7b5046SKonrad Sztyber shutdown_cb(void)
14694c7b5046SKonrad Sztyber {
14704c7b5046SKonrad Sztyber 	struct worker_thread *worker;
14714c7b5046SKonrad Sztyber 
14724c7b5046SKonrad Sztyber 	pthread_mutex_lock(&g_workers_lock);
1473da5ec81fSKonrad Sztyber 	if (!g_workers) {
1474da5ec81fSKonrad Sztyber 		spdk_app_stop(1);
1475da5ec81fSKonrad Sztyber 		goto unlock;
1476da5ec81fSKonrad Sztyber 	}
1477da5ec81fSKonrad Sztyber 
14784c7b5046SKonrad Sztyber 	worker = g_workers;
14794c7b5046SKonrad Sztyber 	while (worker) {
14804c7b5046SKonrad Sztyber 		spdk_thread_send_msg(worker->thread, worker_shutdown, worker);
14814c7b5046SKonrad Sztyber 		worker = worker->next;
14824c7b5046SKonrad Sztyber 	}
1483da5ec81fSKonrad Sztyber unlock:
14844c7b5046SKonrad Sztyber 	pthread_mutex_unlock(&g_workers_lock);
14854c7b5046SKonrad Sztyber }
14864c7b5046SKonrad Sztyber 
14879f51cf32Spaul luse int
14889f51cf32Spaul luse main(int argc, char **argv)
14899f51cf32Spaul luse {
14909f51cf32Spaul luse 	struct worker_thread *worker, *tmp;
1491f5b5a9c4SKonrad Sztyber 	int rc;
14929f51cf32Spaul luse 
14939f51cf32Spaul luse 	pthread_mutex_init(&g_workers_lock, NULL);
14949260fa0cSpaul luse 	spdk_app_opts_init(&g_opts, sizeof(g_opts));
14959260fa0cSpaul luse 	g_opts.name = "accel_perf";
14969260fa0cSpaul luse 	g_opts.reactor_mask = "0x1";
14974c7b5046SKonrad Sztyber 	g_opts.shutdown_cb = shutdown_cb;
14985db859daSKrzysztof Karas 	g_opts.rpc_addr = NULL;
1499f5b5a9c4SKonrad Sztyber 
15000a6b7098STomasz Zawadzki 	rc = spdk_app_parse_args(argc, argv, &g_opts, "a:C:o:q:t:yw:M:P:f:T:l:S:x:", NULL,
1501f5b5a9c4SKonrad Sztyber 				 parse_args, usage);
1502f5b5a9c4SKonrad Sztyber 	if (rc != SPDK_APP_PARSE_ARGS_SUCCESS) {
1503f5b5a9c4SKonrad Sztyber 		return rc == SPDK_APP_PARSE_ARGS_HELP ? 0 : 1;
15049f51cf32Spaul luse 	}
15059f51cf32Spaul luse 
150684dbdf08STomasz Zawadzki 	if (g_workload_selection == SPDK_ACCEL_OPC_LAST) {
150784dbdf08STomasz Zawadzki 		fprintf(stderr, "Must provide a workload type\n");
15082a0c66d0Spaul luse 		usage();
1509724f3006STomasz Zawadzki 		return -1;
15102a0c66d0Spaul luse 	}
15112a0c66d0Spaul luse 
1512e1bf63afSJim Harris 	if (g_allocate_depth > 0 && g_queue_depth > g_allocate_depth) {
1513e1bf63afSJim Harris 		fprintf(stdout, "allocate depth must be at least as big as queue depth\n");
1514e1bf63afSJim Harris 		usage();
1515724f3006STomasz Zawadzki 		return -1;
1516e1bf63afSJim Harris 	}
1517e1bf63afSJim Harris 
1518e1bf63afSJim Harris 	if (g_allocate_depth == 0) {
1519e1bf63afSJim Harris 		g_allocate_depth = g_queue_depth;
1520e1bf63afSJim Harris 	}
1521e1bf63afSJim Harris 
15225105dc5dSKonrad Sztyber 	if ((g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
152344bf79a8SKrzysztof Sprzaczkowski 	     g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
1524ee2adf2eSKrzysztof Sprzaczkowski 	     g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
152580dfab0aSKrzysztof Karas 	     g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
152680dfab0aSKrzysztof Karas 	     g_workload_selection == SPDK_ACCEL_OPC_DIX_VERIFY ||
152780dfab0aSKrzysztof Karas 	     g_workload_selection == SPDK_ACCEL_OPC_DIX_GENERATE) &&
1528850cd900Spaul luse 	    g_chained_count == 0) {
152988754353SZiye Yang 		usage();
1530724f3006STomasz Zawadzki 		return -1;
153188754353SZiye Yang 	}
153288754353SZiye Yang 
15335105dc5dSKonrad Sztyber 	if (g_workload_selection == SPDK_ACCEL_OPC_XOR && g_xor_src_count < 2) {
1534a5d5ab27SArtur Paszkiewicz 		usage();
1535724f3006STomasz Zawadzki 		return -1;
1536a5d5ab27SArtur Paszkiewicz 	}
1537a5d5ab27SArtur Paszkiewicz 
15380a6b7098STomasz Zawadzki 	if (g_module_name && spdk_accel_assign_opc(g_workload_selection, g_module_name)) {
15390a6b7098STomasz Zawadzki 		fprintf(stderr, "Was not able to assign '%s' module to the workload\n", g_module_name);
15400a6b7098STomasz Zawadzki 		usage();
15410a6b7098STomasz Zawadzki 		return -1;
15420a6b7098STomasz Zawadzki 	}
15430a6b7098STomasz Zawadzki 
154427e85f52SBen Walker 	g_rc = spdk_app_start(&g_opts, accel_perf_prep, NULL);
15459b189667Spaul luse 	if (g_rc) {
15469f51cf32Spaul luse 		SPDK_ERRLOG("ERROR starting application\n");
15479f51cf32Spaul luse 	}
15489f51cf32Spaul luse 
15499f51cf32Spaul luse 	pthread_mutex_destroy(&g_workers_lock);
15509f51cf32Spaul luse 
15519f51cf32Spaul luse 	worker = g_workers;
15529f51cf32Spaul luse 	while (worker) {
15539f51cf32Spaul luse 		tmp = worker->next;
15549f51cf32Spaul luse 		free(worker);
15559f51cf32Spaul luse 		worker = tmp;
15569f51cf32Spaul luse 	}
155727e85f52SBen Walker 	accel_perf_free_compress_segs();
15589f51cf32Spaul luse 	spdk_app_fini();
15599b189667Spaul luse 	return g_rc;
15609f51cf32Spaul luse }
1561