Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/thread.h"
8 : : #include "spdk/env.h"
9 : : #include "spdk/event.h"
10 : : #include "spdk/log.h"
11 : : #include "spdk/string.h"
12 : : #include "spdk/accel.h"
13 : : #include "spdk/crc32.h"
14 : : #include "spdk/util.h"
15 : : #include "spdk/xor.h"
16 : : #include "spdk/dif.h"
17 : :
18 : : #define DATA_PATTERN 0x5a
19 : : #define ALIGN_4K 0x1000
20 : : #define COMP_BUF_PAD_PERCENTAGE 1.1L
21 : :
22 : : static uint64_t g_tsc_rate;
23 : : static uint64_t g_tsc_end;
24 : : static int g_rc;
25 : : static int g_xfer_size_bytes = 4096;
26 : : static int g_block_size_bytes = 512;
27 : : static int g_md_size_bytes = 8;
28 : : static int g_queue_depth = 32;
29 : : /* g_allocate_depth indicates how many tasks we allocate per worker. It will
30 : : * be at least as much as the queue depth.
31 : : */
32 : : static int g_allocate_depth = 0;
33 : : static int g_threads_per_core = 1;
34 : : static int g_time_in_sec = 5;
35 : : static uint32_t g_crc32c_seed = 0;
36 : : static uint32_t g_chained_count = 1;
37 : : static int g_fail_percent_goal = 0;
38 : : static uint8_t g_fill_pattern = 255;
39 : : static uint32_t g_xor_src_count = 2;
40 : : static bool g_verify = false;
41 : : static const char *g_workload_type = NULL;
42 : : static enum spdk_accel_opcode g_workload_selection = SPDK_ACCEL_OPC_LAST;
43 : : static const char *g_module_name = NULL;
44 : : static struct worker_thread *g_workers = NULL;
45 : : static int g_num_workers = 0;
46 : : static char *g_cd_file_in_name = NULL;
47 : : static pthread_mutex_t g_workers_lock = PTHREAD_MUTEX_INITIALIZER;
48 : : static struct spdk_app_opts g_opts = {};
49 : :
50 : : struct ap_compress_seg {
51 : : void *uncompressed_data;
52 : : uint32_t uncompressed_len;
53 : : struct iovec *uncompressed_iovs;
54 : : uint32_t uncompressed_iovcnt;
55 : :
56 : : void *compressed_data;
57 : : uint32_t compressed_len;
58 : : uint32_t compressed_len_padded;
59 : : struct iovec *compressed_iovs;
60 : : uint32_t compressed_iovcnt;
61 : :
62 : : STAILQ_ENTRY(ap_compress_seg) link;
63 : : };
64 : :
65 : : static STAILQ_HEAD(, ap_compress_seg) g_compress_segs = STAILQ_HEAD_INITIALIZER(g_compress_segs);
66 : :
67 : : struct worker_thread;
68 : : static void accel_done(void *ref, int status);
69 : :
70 : : struct display_info {
71 : : int core;
72 : : int thread;
73 : : };
74 : :
75 : : struct ap_task {
76 : : void *src;
77 : : struct iovec *src_iovs;
78 : : uint32_t src_iovcnt;
79 : : void **sources;
80 : : struct iovec *dst_iovs;
81 : : uint32_t dst_iovcnt;
82 : : void *dst;
83 : : void *dst2;
84 : : uint32_t crc_dst;
85 : : uint32_t compressed_sz;
86 : : struct ap_compress_seg *cur_seg;
87 : : struct worker_thread *worker;
88 : : int expected_status; /* used for the compare operation */
89 : : uint32_t num_blocks; /* used for the DIF related operations */
90 : : struct spdk_dif_ctx dif_ctx;
91 : : struct spdk_dif_error dif_err;
92 : : TAILQ_ENTRY(ap_task) link;
93 : : };
94 : :
95 : : struct worker_thread {
96 : : struct spdk_io_channel *ch;
97 : : struct spdk_accel_opcode_stats stats;
98 : : uint64_t xfer_failed;
99 : : uint64_t injected_miscompares;
100 : : uint64_t current_queue_depth;
101 : : TAILQ_HEAD(, ap_task) tasks_pool;
102 : : struct worker_thread *next;
103 : : unsigned core;
104 : : struct spdk_thread *thread;
105 : : bool is_draining;
106 : : struct spdk_poller *is_draining_poller;
107 : : struct spdk_poller *stop_poller;
108 : : void *task_base;
109 : : struct display_info display;
110 : : enum spdk_accel_opcode workload;
111 : : };
112 : :
113 : : static void
114 : 840 : dump_user_config(void)
115 : : {
116 : 840 : const char *module_name = NULL;
117 : : int rc;
118 : :
119 : 840 : rc = spdk_accel_get_opc_module_name(g_workload_selection, &module_name);
120 [ - + ]: 840 : if (rc) {
121 [ # # ]: 0 : printf("error getting module name (%d)\n", rc);
122 : : }
123 : :
124 [ - + ]: 840 : printf("\nSPDK Configuration:\n");
125 [ - + ]: 840 : printf("Core mask: %s\n\n", g_opts.reactor_mask);
126 [ - + ]: 840 : printf("Accel Perf Configuration:\n");
127 [ - + ]: 840 : printf("Workload Type: %s\n", g_workload_type);
128 [ + + ]: 840 : if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
129 [ + + ]: 756 : g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C) {
130 [ - + ]: 168 : printf("CRC-32C seed: %u\n", g_crc32c_seed);
131 [ + + ]: 672 : } else if (g_workload_selection == SPDK_ACCEL_OPC_FILL) {
132 [ - + ]: 42 : printf("Fill pattern: 0x%x\n", g_fill_pattern);
133 [ + + - + ]: 630 : } else if ((g_workload_selection == SPDK_ACCEL_OPC_COMPARE) && g_fail_percent_goal > 0) {
134 [ # # ]: 0 : printf("Failure inject: %u percent\n", g_fail_percent_goal);
135 [ + + ]: 630 : } else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
136 [ - + ]: 84 : printf("Source buffers: %u\n", g_xor_src_count);
137 : : }
138 [ + + ]: 840 : if (g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
139 [ + + ]: 756 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
140 [ + + ]: 714 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
141 [ + + ]: 672 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
142 [ - + ]: 210 : printf("Vector size: %u bytes\n", g_xfer_size_bytes);
143 [ - + ]: 210 : printf("Transfer size: %u bytes\n", g_xfer_size_bytes * g_chained_count);
144 : : } else {
145 [ - + ]: 630 : printf("Transfer size: %u bytes\n", g_xfer_size_bytes);
146 : : }
147 [ + + ]: 840 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
148 [ + + ]: 798 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) {
149 [ - + ]: 84 : printf("Block size: %u bytes\n", g_block_size_bytes);
150 [ - + ]: 84 : printf("Metadata size: %u bytes\n", g_md_size_bytes);
151 : : }
152 [ - + ]: 840 : printf("Vector count %u\n", g_chained_count);
153 [ - + ]: 840 : printf("Module: %s\n", module_name);
154 [ + + ]: 840 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS ||
155 [ + + ]: 798 : g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
156 [ - + ]: 294 : printf("File Name: %s\n", g_cd_file_in_name);
157 : : }
158 [ - + ]: 840 : printf("Queue depth: %u\n", g_queue_depth);
159 [ - + ]: 840 : printf("Allocate depth: %u\n", g_allocate_depth);
160 [ - + ]: 840 : printf("# threads/core: %u\n", g_threads_per_core);
161 [ - + ]: 840 : printf("Run time: %u seconds\n", g_time_in_sec);
162 [ + + + + : 840 : printf("Verify: %s\n\n", g_verify ? "Yes" : "No");
- + ]
163 : 840 : }
164 : :
165 : : static void
166 : 63 : usage(void)
167 : : {
168 [ - + ]: 63 : printf("accel_perf options:\n");
169 [ - + ]: 63 : printf("\t[-h help message]\n");
170 [ - + ]: 63 : printf("\t[-q queue depth per core]\n");
171 [ - + ]: 63 : printf("\t[-C for supported workloads, use this value to configure the io vector size to test (default 1)\n");
172 [ - + ]: 63 : printf("\t[-T number of threads per core\n");
173 [ - + ]: 63 : printf("\t[-o transfer size in bytes (default: 4KiB. For compress/decompress, 0 means the input file size)]\n");
174 [ - + ]: 63 : printf("\t[-t time in seconds]\n");
175 [ - + ]: 63 : printf("\t[-w workload type must be one of these: copy, fill, crc32c, copy_crc32c, compare, compress, decompress, dualcast, xor,\n");
176 [ - + ]: 63 : printf("\t[ dif_verify, , dif_generate, dif_generate_copy\n");
177 [ - + ]: 63 : printf("\t[-M assign module to the operation, not compatible with accel_assign_opc RPC\n");
178 [ - + ]: 63 : printf("\t[-l for compress/decompress workloads, name of uncompressed input file\n");
179 [ - + ]: 63 : printf("\t[-S for crc32c workload, use this seed value (default 0)\n");
180 [ - + ]: 63 : printf("\t[-P for compare workload, percentage of operations that should miscompare (percent, default 0)\n");
181 [ - + ]: 63 : printf("\t[-f for fill workload, use this BYTE value (default 255)\n");
182 [ - + ]: 63 : printf("\t[-x for xor workload, use this number of source buffers (default, minimum: 2)]\n");
183 [ - + ]: 63 : printf("\t[-y verify result if this switch is on]\n");
184 [ - + ]: 63 : printf("\t[-a tasks to allocate per core (default: same value as -q)]\n");
185 [ - + ]: 63 : printf("\t\tCan be used to spread operations across a wider range of memory.\n");
186 : 63 : }
187 : :
188 : : static int
189 : 3402 : parse_args(int ch, char *arg)
190 : : {
191 : 3402 : int argval = 0;
192 : :
193 [ + + ]: 3402 : switch (ch) {
194 : 1449 : case 'a':
195 : : case 'C':
196 : : case 'f':
197 : : case 'T':
198 : : case 'o':
199 : : case 'P':
200 : : case 'q':
201 : : case 'S':
202 : : case 't':
203 : : case 'x':
204 : 1449 : argval = spdk_strtol(optarg, 10);
205 [ + + ]: 1449 : if (argval < 0) {
206 [ - + ]: 21 : fprintf(stderr, "-%c option must be non-negative.\n", ch);
207 : 21 : usage();
208 : 21 : return 1;
209 : : }
210 : 1428 : break;
211 : 1953 : default:
212 : 1953 : break;
213 : : };
214 : :
215 [ + + + + : 3381 : switch (ch) {
+ + - + +
+ + + + -
- ]
216 : 42 : case 'a':
217 : 42 : g_allocate_depth = argval;
218 : 42 : break;
219 : 84 : case 'C':
220 : 84 : g_chained_count = argval;
221 : 84 : break;
222 : 315 : case 'l':
223 : 315 : g_cd_file_in_name = optarg;
224 : 315 : break;
225 : 42 : case 'f':
226 : 42 : g_fill_pattern = (uint8_t)argval;
227 : 42 : break;
228 : 84 : case 'T':
229 : 84 : g_threads_per_core = argval;
230 : 84 : break;
231 : 126 : case 'o':
232 : 126 : g_xfer_size_bytes = argval;
233 : 126 : break;
234 : 0 : case 'P':
235 : 0 : g_fail_percent_goal = argval;
236 : 0 : break;
237 : 42 : case 'q':
238 : 42 : g_queue_depth = argval;
239 : 42 : break;
240 : 42 : case 'S':
241 : 42 : g_crc32c_seed = argval;
242 : 42 : break;
243 : 924 : case 't':
244 : 924 : g_time_in_sec = argval;
245 : 924 : break;
246 : 42 : case 'x':
247 : 42 : g_xor_src_count = argval;
248 : 42 : break;
249 : 714 : case 'y':
250 : 714 : g_verify = true;
251 : 714 : break;
252 : 924 : case 'w':
253 : 924 : g_workload_type = optarg;
254 [ + + + + ]: 924 : if (!strcmp(g_workload_type, "copy")) {
255 : 42 : g_workload_selection = SPDK_ACCEL_OPC_COPY;
256 [ + + + + ]: 882 : } else if (!strcmp(g_workload_type, "fill")) {
257 : 42 : g_workload_selection = SPDK_ACCEL_OPC_FILL;
258 [ + + + + ]: 840 : } else if (!strcmp(g_workload_type, "crc32c")) {
259 : 84 : g_workload_selection = SPDK_ACCEL_OPC_CRC32C;
260 [ + + + + ]: 756 : } else if (!strcmp(g_workload_type, "copy_crc32c")) {
261 : 84 : g_workload_selection = SPDK_ACCEL_OPC_COPY_CRC32C;
262 [ + + + + ]: 672 : } else if (!strcmp(g_workload_type, "compare")) {
263 : 42 : g_workload_selection = SPDK_ACCEL_OPC_COMPARE;
264 [ + + + + ]: 630 : } else if (!strcmp(g_workload_type, "dualcast")) {
265 : 42 : g_workload_selection = SPDK_ACCEL_OPC_DUALCAST;
266 [ + + + + ]: 588 : } else if (!strcmp(g_workload_type, "compress")) {
267 : 84 : g_workload_selection = SPDK_ACCEL_OPC_COMPRESS;
268 [ + + + + ]: 504 : } else if (!strcmp(g_workload_type, "decompress")) {
269 : 252 : g_workload_selection = SPDK_ACCEL_OPC_DECOMPRESS;
270 [ + + + + ]: 252 : } else if (!strcmp(g_workload_type, "xor")) {
271 : 105 : g_workload_selection = SPDK_ACCEL_OPC_XOR;
272 [ + + + + ]: 147 : } else if (!strcmp(g_workload_type, "dif_verify")) {
273 : 42 : g_workload_selection = SPDK_ACCEL_OPC_DIF_VERIFY;
274 [ + + + + ]: 105 : } else if (!strcmp(g_workload_type, "dif_generate")) {
275 : 42 : g_workload_selection = SPDK_ACCEL_OPC_DIF_GENERATE;
276 [ + + + + ]: 63 : } else if (!strcmp(g_workload_type, "dif_generate_copy")) {
277 : 42 : g_workload_selection = SPDK_ACCEL_OPC_DIF_GENERATE_COPY;
278 : : } else {
279 [ - + ]: 21 : fprintf(stderr, "Unsupported workload type: %s\n", optarg);
280 : 21 : usage();
281 : 21 : return 1;
282 : : }
283 : 903 : break;
284 : 0 : case 'M':
285 : 0 : g_module_name = optarg;
286 : 0 : break;
287 : :
288 : 0 : default:
289 : 0 : usage();
290 : 0 : return 1;
291 : : }
292 : :
293 : 3360 : return 0;
294 : : }
295 : :
296 : : static int dump_result(void);
297 : : static void
298 : 1176 : unregister_worker(void *arg1)
299 : : {
300 : 1176 : struct worker_thread *worker = arg1;
301 : :
302 [ + - ]: 1176 : if (worker->ch) {
303 : 1176 : spdk_accel_get_opcode_stats(worker->ch, worker->workload,
304 : : &worker->stats, sizeof(worker->stats));
305 : 1176 : spdk_put_io_channel(worker->ch);
306 : 1176 : worker->ch = NULL;
307 : : }
308 : 1176 : free(worker->task_base);
309 : 1176 : spdk_thread_exit(spdk_get_thread());
310 [ - + ]: 1176 : pthread_mutex_lock(&g_workers_lock);
311 [ - + ]: 1176 : assert(g_num_workers >= 1);
312 [ + + ]: 1176 : if (--g_num_workers == 0) {
313 [ - + ]: 840 : pthread_mutex_unlock(&g_workers_lock);
314 : : /* Only dump results on successful runs */
315 [ + - ]: 840 : if (g_rc == 0) {
316 : 840 : g_rc = dump_result();
317 : : }
318 : 840 : spdk_app_stop(g_rc);
319 : : } else {
320 [ - + ]: 336 : pthread_mutex_unlock(&g_workers_lock);
321 : : }
322 : 1176 : }
323 : :
324 : : static void
325 : 24990 : accel_perf_construct_iovs(void *buf, uint64_t sz, struct iovec *iovs, uint32_t iovcnt)
326 : : {
327 : : uint64_t ele_size;
328 : : uint8_t *data;
329 : : uint32_t i;
330 : :
331 : 24990 : ele_size = spdk_divide_round_up(sz, iovcnt);
332 : :
333 : 24990 : data = buf;
334 [ + + ]: 49980 : for (i = 0; i < iovcnt; i++) {
335 : 24990 : ele_size = spdk_min(ele_size, sz);
336 [ - + ]: 24990 : assert(ele_size > 0);
337 : :
338 : 24990 : iovs[i].iov_base = data;
339 : 24990 : iovs[i].iov_len = ele_size;
340 : :
341 : 24990 : data += ele_size;
342 : 24990 : sz -= ele_size;
343 : : }
344 [ - + ]: 24990 : assert(sz == 0);
345 : 24990 : }
346 : :
347 : : static int
348 : 38976 : _get_task_data_bufs(struct ap_task *task)
349 : : {
350 : 38976 : uint32_t align = 0;
351 : 38976 : uint32_t i = 0;
352 : 38976 : int src_buff_len = g_xfer_size_bytes;
353 : 38976 : int dst_buff_len = g_xfer_size_bytes;
354 : 17600 : struct spdk_dif_ctx_init_ext_opts dif_opts;
355 : : uint32_t num_blocks, transfer_size_with_md;
356 : : int rc;
357 : :
358 : : /* For dualcast, the DSA HW requires 4K alignment on destination addresses but
359 : : * we do this for all modules to keep it simple.
360 : : */
361 [ + + ]: 38976 : if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST) {
362 : 1344 : align = ALIGN_4K;
363 : : }
364 : :
365 [ + + ]: 38976 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS ||
366 [ + + ]: 37632 : g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
367 : 20160 : task->cur_seg = STAILQ_FIRST(&g_compress_segs);
368 : :
369 [ + + ]: 20160 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
370 : 1344 : dst_buff_len = task->cur_seg->compressed_len_padded;
371 : : }
372 : :
373 : 20160 : task->dst = spdk_dma_zmalloc(dst_buff_len, align, NULL);
374 [ - + ]: 20160 : if (task->dst == NULL) {
375 [ # # # # ]: 0 : fprintf(stderr, "Unable to alloc dst buffer\n");
376 : 0 : return -ENOMEM;
377 : : }
378 : :
379 : 20160 : task->dst_iovs = calloc(g_chained_count, sizeof(struct iovec));
380 [ - + ]: 20160 : if (!task->dst_iovs) {
381 [ # # # # ]: 0 : fprintf(stderr, "cannot allocate task->dst_iovs for task=%p\n", task);
382 : 0 : return -ENOMEM;
383 : : }
384 : 20160 : task->dst_iovcnt = g_chained_count;
385 : 20160 : accel_perf_construct_iovs(task->dst, dst_buff_len, task->dst_iovs, task->dst_iovcnt);
386 : :
387 : 20160 : return 0;
388 : : }
389 : :
390 [ + + ]: 18816 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
391 : 1344 : task->dst_iovcnt = g_chained_count;
392 : 1344 : task->dst_iovs = calloc(task->dst_iovcnt, sizeof(struct iovec));
393 [ - + ]: 1344 : if (!task->dst_iovs) {
394 [ # # # # ]: 0 : fprintf(stderr, "cannot allocate task->dst_iovs for task=%p\n", task);
395 : 0 : return -ENOMEM;
396 : : }
397 : :
398 [ - + ]: 1344 : num_blocks = g_xfer_size_bytes / g_block_size_bytes;
399 : : /* Add bytes for each block for metadata */
400 : 1344 : transfer_size_with_md = g_xfer_size_bytes + (num_blocks * g_md_size_bytes);
401 : 1344 : task->num_blocks = num_blocks;
402 : :
403 [ + + ]: 2688 : for (i = 0; i < task->dst_iovcnt; i++) {
404 : 1344 : task->dst_iovs[i].iov_base = spdk_dma_zmalloc(transfer_size_with_md, 0, NULL);
405 [ - + ]: 1344 : if (task->dst_iovs[i].iov_base == NULL) {
406 : 0 : return -ENOMEM;
407 : : }
408 : 1344 : task->dst_iovs[i].iov_len = transfer_size_with_md;
409 : : }
410 : :
411 : 1344 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
412 : 1344 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
413 : :
414 : 1344 : rc = spdk_dif_ctx_init(&task->dif_ctx,
415 : 1344 : g_block_size_bytes + g_md_size_bytes,
416 : : g_md_size_bytes, true, true,
417 : : SPDK_DIF_TYPE1,
418 : : SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK,
419 : : 0x123, 0xFFFF, 0x234, 0, 0, &dif_opts);
420 [ - + ]: 1344 : if (rc != 0) {
421 [ # # # # ]: 0 : fprintf(stderr, "Initialization of DIF context failed\n");
422 : 0 : return rc;
423 : : }
424 : : }
425 : :
426 [ + + ]: 18816 : if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
427 [ + + ]: 16128 : g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
428 [ + + ]: 13440 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
429 [ + + ]: 12096 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
430 [ + + ]: 10752 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
431 [ - + ]: 9408 : assert(g_chained_count > 0);
432 : 9408 : task->src_iovcnt = g_chained_count;
433 : 9408 : task->src_iovs = calloc(task->src_iovcnt, sizeof(struct iovec));
434 [ - + ]: 9408 : if (!task->src_iovs) {
435 [ # # # # ]: 0 : fprintf(stderr, "cannot allocated task->src_iovs fot task=%p\n", task);
436 : 0 : return -ENOMEM;
437 : : }
438 : :
439 [ + + ]: 9408 : if (g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C) {
440 : 2688 : dst_buff_len = g_xfer_size_bytes * g_chained_count;
441 : : }
442 : :
443 [ + + ]: 9408 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
444 [ + + ]: 8064 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) {
445 [ - + ]: 2688 : src_buff_len += (g_xfer_size_bytes / g_block_size_bytes) * g_md_size_bytes;
446 : : }
447 : :
448 [ + + ]: 21504 : for (i = 0; i < task->src_iovcnt; i++) {
449 : 12096 : task->src_iovs[i].iov_base = spdk_dma_zmalloc(src_buff_len, 0, NULL);
450 [ - + ]: 12096 : if (task->src_iovs[i].iov_base == NULL) {
451 : 0 : return -ENOMEM;
452 : : }
453 [ - + ]: 12096 : memset(task->src_iovs[i].iov_base, DATA_PATTERN, src_buff_len);
454 : 12096 : task->src_iovs[i].iov_len = src_buff_len;
455 : : }
456 [ + + ]: 9408 : } else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
457 [ - + ]: 2688 : assert(g_xor_src_count > 1);
458 : 2688 : task->sources = calloc(g_xor_src_count, sizeof(*task->sources));
459 [ - + ]: 2688 : if (!task->sources) {
460 : 0 : return -ENOMEM;
461 : : }
462 : :
463 [ + + ]: 9408 : for (i = 0; i < g_xor_src_count; i++) {
464 : 6720 : task->sources[i] = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
465 [ - + ]: 6720 : if (!task->sources[i]) {
466 : 0 : return -ENOMEM;
467 : : }
468 [ - + ]: 6720 : memset(task->sources[i], DATA_PATTERN, g_xfer_size_bytes);
469 : : }
470 : : } else {
471 : 6720 : task->src = spdk_dma_zmalloc(g_xfer_size_bytes, 0, NULL);
472 [ - + ]: 6720 : if (task->src == NULL) {
473 [ # # # # ]: 0 : fprintf(stderr, "Unable to alloc src buffer\n");
474 : 0 : return -ENOMEM;
475 : : }
476 : :
477 : : /* For fill, set the entire src buffer so we can check if verify is enabled. */
478 [ + + ]: 6720 : if (g_workload_selection == SPDK_ACCEL_OPC_FILL) {
479 [ - + ]: 2688 : memset(task->src, g_fill_pattern, g_xfer_size_bytes);
480 : : } else {
481 [ - + ]: 4032 : memset(task->src, DATA_PATTERN, g_xfer_size_bytes);
482 : : }
483 : : }
484 : :
485 [ + + ]: 18816 : if (g_workload_selection != SPDK_ACCEL_OPC_CRC32C &&
486 [ + + ]: 16128 : g_workload_selection != SPDK_ACCEL_OPC_DIF_VERIFY &&
487 [ + + ]: 14784 : g_workload_selection != SPDK_ACCEL_OPC_DIF_GENERATE &&
488 [ + + ]: 13440 : g_workload_selection != SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
489 : 12096 : task->dst = spdk_dma_zmalloc(dst_buff_len, align, NULL);
490 [ - + ]: 12096 : if (task->dst == NULL) {
491 [ # # # # ]: 0 : fprintf(stderr, "Unable to alloc dst buffer\n");
492 : 0 : return -ENOMEM;
493 : : }
494 : :
495 : : /* For compare we want the buffers to match, otherwise not. */
496 [ + + ]: 12096 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPARE) {
497 [ - + ]: 1344 : memset(task->dst, DATA_PATTERN, dst_buff_len);
498 : : } else {
499 [ - + ]: 10752 : memset(task->dst, ~DATA_PATTERN, dst_buff_len);
500 : : }
501 : : }
502 : :
503 : : /* For dualcast 2 buffers are needed for the operation. */
504 [ + + ]: 18816 : if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST ||
505 [ + + + + : 17472 : (g_workload_selection == SPDK_ACCEL_OPC_XOR && g_verify)) {
+ - ]
506 : 4032 : task->dst2 = spdk_dma_zmalloc(g_xfer_size_bytes, align, NULL);
507 [ - + ]: 4032 : if (task->dst2 == NULL) {
508 [ # # # # ]: 0 : fprintf(stderr, "Unable to alloc dst buffer\n");
509 : 0 : return -ENOMEM;
510 : : }
511 [ - + ]: 4032 : memset(task->dst2, ~DATA_PATTERN, g_xfer_size_bytes);
512 : : }
513 : :
514 [ + + ]: 18816 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
515 [ + + ]: 17472 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) {
516 : 2688 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
517 : 2688 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
518 : :
519 [ - + ]: 2688 : task->num_blocks = (g_xfer_size_bytes * g_chained_count) / g_block_size_bytes;
520 : :
521 : 2688 : rc = spdk_dif_ctx_init(&task->dif_ctx,
522 : 2688 : g_block_size_bytes + g_md_size_bytes,
523 : : g_md_size_bytes, true, true,
524 : : SPDK_DIF_TYPE1,
525 : : SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | SPDK_DIF_FLAGS_REFTAG_CHECK,
526 : : 16, 0xFFFF, 10, 0, 0, &dif_opts);
527 [ - + ]: 2688 : if (rc != 0) {
528 [ # # # # ]: 0 : fprintf(stderr, "Initialization of DIF context failed, error (%d)\n", rc);
529 : 0 : return rc;
530 : : }
531 : :
532 [ + + ]: 2688 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY) {
533 : 1344 : rc = spdk_dif_generate(task->src_iovs, task->src_iovcnt, task->num_blocks, &task->dif_ctx);
534 [ - + ]: 1344 : if (rc != 0) {
535 [ # # # # ]: 0 : fprintf(stderr, "Generation of DIF failed, error (%d)\n", rc);
536 : 0 : return rc;
537 : : }
538 : : }
539 : : }
540 : :
541 : 18816 : return 0;
542 : : }
543 : :
544 : : inline static struct ap_task *
545 : 234022942 : _get_task(struct worker_thread *worker)
546 : : {
547 : : struct ap_task *task;
548 : :
549 [ + - ]: 234022942 : if (!TAILQ_EMPTY(&worker->tasks_pool)) {
550 : 234022942 : task = TAILQ_FIRST(&worker->tasks_pool);
551 [ + + ]: 234022942 : TAILQ_REMOVE(&worker->tasks_pool, task, link);
552 : : } else {
553 [ # # # # ]: 0 : fprintf(stderr, "Unable to get ap_task\n");
554 : 0 : return NULL;
555 : : }
556 : :
557 : 234022942 : return task;
558 : : }
559 : :
560 : : /* Submit one operation using the same ap task that just completed. */
561 : : static void
562 : 234022942 : _submit_single(struct worker_thread *worker, struct ap_task *task)
563 : : {
564 : : int random_num;
565 : 234022942 : int rc = 0;
566 : 234022942 : int flags = 0;
567 : :
568 [ - + ]: 234022942 : assert(worker);
569 : :
570 [ + + + + : 234022942 : switch (worker->workload) {
+ + + + +
+ + + - ]
571 : 20465248 : case SPDK_ACCEL_OPC_COPY:
572 : 20465248 : rc = spdk_accel_submit_copy(worker->ch, task->dst, task->src,
573 : : g_xfer_size_bytes, flags, accel_done, task);
574 : 20465248 : break;
575 : 29881216 : case SPDK_ACCEL_OPC_FILL:
576 : : /* For fill use the first byte of the task->dst buffer */
577 : 29881216 : rc = spdk_accel_submit_fill(worker->ch, task->dst, *(uint8_t *)task->src,
578 : : g_xfer_size_bytes, flags, accel_done, task);
579 : 29881216 : break;
580 : 43394848 : case SPDK_ACCEL_OPC_CRC32C:
581 : 43394848 : rc = spdk_accel_submit_crc32cv(worker->ch, &task->crc_dst,
582 : : task->src_iovs, task->src_iovcnt, g_crc32c_seed,
583 : : accel_done, task);
584 : 43394848 : break;
585 : 23553952 : case SPDK_ACCEL_OPC_COPY_CRC32C:
586 : 23553952 : rc = spdk_accel_submit_copy_crc32cv(worker->ch, task->dst, task->src_iovs, task->src_iovcnt,
587 : : &task->crc_dst, g_crc32c_seed, flags, accel_done, task);
588 : 23553952 : break;
589 : 30449408 : case SPDK_ACCEL_OPC_COMPARE:
590 : 30449408 : random_num = rand() % 100;
591 [ - + ]: 30449408 : if (random_num < g_fail_percent_goal) {
592 : 0 : task->expected_status = -EILSEQ;
593 : 0 : *(uint8_t *)task->dst = ~DATA_PATTERN;
594 : : } else {
595 : 30449408 : task->expected_status = 0;
596 : 30449408 : *(uint8_t *)task->dst = DATA_PATTERN;
597 : : }
598 : 30449408 : rc = spdk_accel_submit_compare(worker->ch, task->dst, task->src,
599 : : g_xfer_size_bytes, accel_done, task);
600 : 30449408 : break;
601 : 20457408 : case SPDK_ACCEL_OPC_DUALCAST:
602 : 20457408 : rc = spdk_accel_submit_dualcast(worker->ch, task->dst, task->dst2,
603 : : task->src, g_xfer_size_bytes, flags, accel_done, task);
604 : 20457408 : break;
605 : 2483391 : case SPDK_ACCEL_OPC_COMPRESS:
606 : 2483391 : task->src_iovs = task->cur_seg->uncompressed_iovs;
607 : 2483391 : task->src_iovcnt = task->cur_seg->uncompressed_iovcnt;
608 : 4628126 : rc = spdk_accel_submit_compress(worker->ch, task->dst, task->cur_seg->compressed_len_padded,
609 : : task->src_iovs,
610 : 2483391 : task->src_iovcnt, &task->compressed_sz, flags, accel_done, task);
611 : 2483391 : break;
612 : 17963675 : case SPDK_ACCEL_OPC_DECOMPRESS:
613 : 17963675 : task->src_iovs = task->cur_seg->compressed_iovs;
614 : 17963675 : task->src_iovcnt = task->cur_seg->compressed_iovcnt;
615 : 17963675 : rc = spdk_accel_submit_decompress(worker->ch, task->dst_iovs, task->dst_iovcnt, task->src_iovs,
616 : 17963675 : task->src_iovcnt, NULL, flags, accel_done, task);
617 : 17963675 : break;
618 : 28144416 : case SPDK_ACCEL_OPC_XOR:
619 : 28144416 : rc = spdk_accel_submit_xor(worker->ch, task->dst, task->sources, g_xor_src_count,
620 : : g_xfer_size_bytes, accel_done, task);
621 : 28144416 : break;
622 : 5346048 : case SPDK_ACCEL_OPC_DIF_VERIFY:
623 : 9087040 : rc = spdk_accel_submit_dif_verify(worker->ch, task->src_iovs, task->src_iovcnt, task->num_blocks,
624 : 5346048 : &task->dif_ctx, &task->dif_err, accel_done, task);
625 : 5346048 : break;
626 : 6692256 : case SPDK_ACCEL_OPC_DIF_GENERATE:
627 : 6692256 : rc = spdk_accel_submit_dif_generate(worker->ch, task->src_iovs, task->src_iovcnt, task->num_blocks,
628 : 6692256 : &task->dif_ctx, accel_done, task);
629 : 6692256 : break;
630 : 5191072 : case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
631 : 8667648 : rc = spdk_accel_submit_dif_generate_copy(worker->ch, task->dst_iovs, task->dst_iovcnt,
632 : 5191072 : task->src_iovs, task->src_iovcnt,
633 : 5191072 : task->num_blocks, &task->dif_ctx, accel_done, task);
634 : 5191072 : break;
635 : 0 : default:
636 : 0 : assert(false);
637 : : break;
638 : :
639 : : }
640 : :
641 : 234022942 : worker->current_queue_depth++;
642 [ - + ]: 234022942 : if (rc) {
643 : 0 : accel_done(task, rc);
644 : : }
645 : 234022942 : }
646 : :
647 : : static void
648 : 38976 : _free_task_buffers(struct ap_task *task)
649 : : {
650 : : uint32_t i;
651 : :
652 [ + + ]: 38976 : if (g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS ||
653 [ + + ]: 20160 : g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
654 : 20160 : free(task->dst_iovs);
655 [ + + ]: 18816 : } else if (g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
656 [ + + ]: 16128 : g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
657 [ + + ]: 13440 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
658 [ + + ]: 12096 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE ||
659 [ + + ]: 10752 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
660 [ + - ]: 9408 : if (task->src_iovs) {
661 [ + + ]: 21504 : for (i = 0; i < task->src_iovcnt; i++) {
662 [ + - ]: 12096 : if (task->src_iovs[i].iov_base) {
663 : 12096 : spdk_dma_free(task->src_iovs[i].iov_base);
664 : : }
665 : : }
666 : 9408 : free(task->src_iovs);
667 : : }
668 [ + + ]: 9408 : } else if (g_workload_selection == SPDK_ACCEL_OPC_XOR) {
669 [ + - ]: 2688 : if (task->sources) {
670 [ + + ]: 9408 : for (i = 0; i < g_xor_src_count; i++) {
671 : 6720 : spdk_dma_free(task->sources[i]);
672 : : }
673 : 2688 : free(task->sources);
674 : : }
675 : : } else {
676 : 6720 : spdk_dma_free(task->src);
677 : : }
678 : :
679 : 38976 : spdk_dma_free(task->dst);
680 [ + + + + ]: 38976 : if (g_workload_selection == SPDK_ACCEL_OPC_DUALCAST || g_workload_selection == SPDK_ACCEL_OPC_XOR) {
681 : 4032 : spdk_dma_free(task->dst2);
682 : : }
683 : :
684 [ + + ]: 38976 : if (g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE_COPY) {
685 [ + - ]: 1344 : if (task->dst_iovs) {
686 [ + + ]: 2688 : for (i = 0; i < task->dst_iovcnt; i++) {
687 [ + - ]: 1344 : if (task->dst_iovs[i].iov_base) {
688 : 1344 : spdk_dma_free(task->dst_iovs[i].iov_base);
689 : : }
690 : : }
691 : 1344 : free(task->dst_iovs);
692 : : }
693 : : }
694 : 38976 : }
695 : :
696 : : static int
697 : 23553952 : _vector_memcmp(void *_dst, struct iovec *src_src_iovs, uint32_t iovcnt)
698 : : {
699 : : uint32_t i;
700 : 23553952 : uint32_t ttl_len = 0;
701 : 23553952 : uint8_t *dst = (uint8_t *)_dst;
702 : :
703 [ + + ]: 56623266 : for (i = 0; i < iovcnt; i++) {
704 [ - + - + : 33069312 : if (memcmp(dst, src_src_iovs[i].iov_base, src_src_iovs[i].iov_len)) {
- + ]
705 : 0 : return -1;
706 : : }
707 : 33069312 : dst += src_src_iovs[i].iov_len;
708 : 33069312 : ttl_len += src_src_iovs[i].iov_len;
709 : : }
710 : :
711 [ - + ]: 23553952 : if (ttl_len != iovcnt * g_xfer_size_bytes) {
712 : 0 : return -1;
713 : : }
714 : :
715 : 23553952 : return 0;
716 : : }
717 : :
718 : : static int _worker_stop(void *arg);
719 : :
720 : : static void
721 : 234022942 : accel_done(void *arg1, int status)
722 : : {
723 : 234022942 : struct ap_task *task = arg1;
724 : 234022942 : struct worker_thread *worker = task->worker;
725 : : uint32_t sw_crc32c;
726 : 100532196 : struct spdk_dif_error err_blk;
727 : :
728 [ - + ]: 234022942 : assert(worker);
729 [ - + ]: 234022942 : assert(worker->current_queue_depth > 0);
730 : :
731 [ + + + + : 234022942 : if (g_verify && status == 0) {
+ + ]
732 [ + + + + : 214310169 : switch (worker->workload) {
+ + - + +
- - - - ]
733 : 23553952 : case SPDK_ACCEL_OPC_COPY_CRC32C:
734 : 23553952 : sw_crc32c = spdk_crc32c_iov_update(task->src_iovs, task->src_iovcnt, ~g_crc32c_seed);
735 [ - + ]: 23553952 : if (task->crc_dst != sw_crc32c) {
736 : 0 : SPDK_NOTICELOG("CRC-32C miscompare\n");
737 : 0 : worker->xfer_failed++;
738 : : }
739 [ - + ]: 23553952 : if (_vector_memcmp(task->dst, task->src_iovs, task->src_iovcnt)) {
740 : 0 : SPDK_NOTICELOG("Data miscompare\n");
741 : 0 : worker->xfer_failed++;
742 : : }
743 : 23553952 : break;
744 : 43394848 : case SPDK_ACCEL_OPC_CRC32C:
745 : 43394848 : sw_crc32c = spdk_crc32c_iov_update(task->src_iovs, task->src_iovcnt, ~g_crc32c_seed);
746 [ - + ]: 43394848 : if (task->crc_dst != sw_crc32c) {
747 : 0 : SPDK_NOTICELOG("CRC-32C miscompare\n");
748 : 0 : worker->xfer_failed++;
749 : : }
750 : 43394848 : break;
751 : 20465248 : case SPDK_ACCEL_OPC_COPY:
752 [ - + - + : 20465248 : if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
- + ]
753 : 0 : SPDK_NOTICELOG("Data miscompare\n");
754 : 0 : worker->xfer_failed++;
755 : : }
756 : 20465248 : break;
757 : 20457408 : case SPDK_ACCEL_OPC_DUALCAST:
758 [ - + - + : 20457408 : if (memcmp(task->src, task->dst, g_xfer_size_bytes)) {
- + ]
759 : 0 : SPDK_NOTICELOG("Data miscompare, first destination\n");
760 : 0 : worker->xfer_failed++;
761 : : }
762 [ - + - + : 20457408 : if (memcmp(task->src, task->dst2, g_xfer_size_bytes)) {
- + ]
763 : 0 : SPDK_NOTICELOG("Data miscompare, second destination\n");
764 : 0 : worker->xfer_failed++;
765 : : }
766 : 20457408 : break;
767 : 29881216 : case SPDK_ACCEL_OPC_FILL:
768 [ - + - + : 29881216 : if (memcmp(task->dst, task->src, g_xfer_size_bytes)) {
- + ]
769 : 0 : SPDK_NOTICELOG("Data miscompare\n");
770 : 0 : worker->xfer_failed++;
771 : : }
772 : 29881216 : break;
773 : 30449408 : case SPDK_ACCEL_OPC_COMPARE:
774 : 30449408 : break;
775 : 0 : case SPDK_ACCEL_OPC_COMPRESS:
776 : 0 : break;
777 : 17963675 : case SPDK_ACCEL_OPC_DECOMPRESS:
778 [ - + - + : 17963675 : if (memcmp(task->dst, task->cur_seg->uncompressed_data, task->cur_seg->uncompressed_len)) {
- + ]
779 : 0 : SPDK_NOTICELOG("Data miscompare on decompression\n");
780 : 0 : worker->xfer_failed++;
781 : : }
782 : 17963675 : break;
783 : 28144416 : case SPDK_ACCEL_OPC_XOR:
784 [ - + ]: 28144416 : if (spdk_xor_gen(task->dst2, task->sources, g_xor_src_count,
785 : : g_xfer_size_bytes) != 0) {
786 : 0 : SPDK_ERRLOG("Failed to generate xor for verification\n");
787 [ - + - + : 28144416 : } else if (memcmp(task->dst, task->dst2, g_xfer_size_bytes)) {
- + ]
788 : 0 : SPDK_NOTICELOG("Data miscompare\n");
789 : 0 : worker->xfer_failed++;
790 : : }
791 : 28144416 : break;
792 : 0 : case SPDK_ACCEL_OPC_DIF_VERIFY:
793 : 0 : break;
794 : 0 : case SPDK_ACCEL_OPC_DIF_GENERATE:
795 [ # # ]: 0 : if (spdk_dif_verify(task->src_iovs, task->src_iovcnt, task->num_blocks,
796 : 0 : &task->dif_ctx, &err_blk) != 0) {
797 : 0 : SPDK_NOTICELOG("Data miscompare, "
798 : : "err_type %u, expected %lu, actual %lu, err_offset %u\n",
799 : : err_blk.err_type, err_blk.expected,
800 : : err_blk.actual, err_blk.err_offset);
801 : 0 : worker->xfer_failed++;
802 : : }
803 : 0 : break;
804 : 0 : case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
805 [ # # ]: 0 : if (spdk_dif_verify(task->dst_iovs, task->dst_iovcnt, task->num_blocks,
806 : 0 : &task->dif_ctx, &err_blk) != 0) {
807 : 0 : SPDK_NOTICELOG("Data miscompare, "
808 : : "err_type %u, expected %lu, actual %lu, err_offset %u\n",
809 : : err_blk.err_type, err_blk.expected,
810 : : err_blk.actual, err_blk.err_offset);
811 : 0 : worker->xfer_failed++;
812 : : }
813 : 0 : break;
814 : 0 : default:
815 : 0 : assert(false);
816 : : break;
817 : : }
818 : 1147168 : }
819 : :
820 [ + + ]: 234022942 : if (worker->workload == SPDK_ACCEL_OPC_COMPRESS ||
821 [ + + ]: 231539543 : g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
822 : : /* Advance the task to the next segment */
823 : 20447066 : task->cur_seg = STAILQ_NEXT(task->cur_seg, link);
824 [ + + ]: 20447066 : if (task->cur_seg == NULL) {
825 : 2173658 : task->cur_seg = STAILQ_FIRST(&g_compress_segs);
826 : : }
827 : : }
828 : :
829 [ - + ]: 234022942 : if (task->expected_status == -EILSEQ) {
830 [ # # ]: 0 : assert(status != 0);
831 : 0 : worker->injected_miscompares++;
832 : 0 : status = 0;
833 [ - + ]: 234022942 : } else if (status) {
834 : : /* Expected to pass but the accel module reported an error (ex: COMPARE operation). */
835 : 0 : worker->xfer_failed++;
836 : : }
837 : :
838 : 234022942 : worker->current_queue_depth--;
839 : :
840 [ + + + + : 234022942 : if (!worker->is_draining && status == 0) {
+ - ]
841 : 233983962 : TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
842 : 233983962 : task = _get_task(worker);
843 : 233983962 : _submit_single(worker, task);
844 : : } else {
845 : 38976 : TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
846 : : }
847 : 234022942 : }
848 : :
849 : : static int
850 : 840 : dump_result(void)
851 : : {
852 : 840 : uint64_t total_completed = 0;
853 : 840 : uint64_t total_failed = 0;
854 : 840 : uint64_t total_miscompared = 0;
855 : : uint64_t total_xfer_per_sec, total_bw_in_MiBps;
856 : 840 : struct worker_thread *worker = g_workers;
857 : 386 : char tmp[64];
858 : :
859 [ - + ]: 840 : printf("\n%-12s %20s %16s %16s %16s\n",
860 : : "Core,Thread", "Transfers", "Bandwidth", "Failed", "Miscompares");
861 [ - + ]: 840 : printf("------------------------------------------------------------------------------------\n");
862 [ + + ]: 2016 : while (worker != NULL) {
863 : :
864 [ - + ]: 1176 : uint64_t xfer_per_sec = worker->stats.executed / g_time_in_sec;
865 [ - + ]: 1176 : uint64_t bw_in_MiBps = worker->stats.num_bytes /
866 : 1176 : (g_time_in_sec * 1024 * 1024);
867 : :
868 : 1176 : total_completed += worker->stats.executed;
869 : 1176 : total_failed += worker->xfer_failed;
870 : 1176 : total_miscompared += worker->injected_miscompares;
871 : :
872 [ - + ]: 1176 : snprintf(tmp, sizeof(tmp), "%u,%u", worker->display.core, worker->display.thread);
873 [ + - ]: 1176 : if (xfer_per_sec) {
874 [ - + ]: 1176 : printf("%-12s %18" PRIu64 "/s %10" PRIu64 " MiB/s %16"PRIu64 " %16" PRIu64 "\n",
875 : : tmp, xfer_per_sec, bw_in_MiBps, worker->xfer_failed,
876 : : worker->injected_miscompares);
877 : : }
878 : :
879 : 1176 : worker = worker->next;
880 : : }
881 : :
882 [ - + ]: 840 : total_xfer_per_sec = total_completed / g_time_in_sec;
883 : 146 : total_bw_in_MiBps = (total_completed * g_xfer_size_bytes) /
884 [ - + ]: 840 : (g_time_in_sec * 1024 * 1024);
885 : :
886 [ - + ]: 840 : printf("====================================================================================\n");
887 [ - + ]: 840 : printf("%-12s %18" PRIu64 "/s %10" PRIu64 " MiB/s %16"PRIu64 " %16" PRIu64 "\n",
888 : : "Total", total_xfer_per_sec, total_bw_in_MiBps, total_failed, total_miscompared);
889 : :
890 : 840 : return total_failed ? 1 : 0;
891 : : }
892 : :
893 : : static inline void
894 : 1176 : _free_task_buffers_in_pool(struct worker_thread *worker)
895 : : {
896 : : struct ap_task *task;
897 : :
898 [ - + ]: 1176 : assert(worker);
899 [ + + ]: 40152 : while ((task = TAILQ_FIRST(&worker->tasks_pool))) {
900 [ + + ]: 38976 : TAILQ_REMOVE(&worker->tasks_pool, task, link);
901 : 38976 : _free_task_buffers(task);
902 : : }
903 : 1176 : }
904 : :
905 : : static int
906 : 4807 : _check_draining(void *arg)
907 : : {
908 : 4807 : struct worker_thread *worker = arg;
909 : :
910 [ - + ]: 4807 : assert(worker);
911 : :
912 [ + + ]: 4807 : if (worker->current_queue_depth == 0) {
913 : 1176 : _free_task_buffers_in_pool(worker);
914 : 1176 : spdk_poller_unregister(&worker->is_draining_poller);
915 : 1176 : unregister_worker(worker);
916 : : }
917 : :
918 : 4807 : return SPDK_POLLER_BUSY;
919 : : }
920 : :
921 : : static int
922 : 1176 : _worker_stop(void *arg)
923 : : {
924 : 1176 : struct worker_thread *worker = arg;
925 : :
926 [ - + ]: 1176 : assert(worker);
927 : :
928 : 1176 : spdk_poller_unregister(&worker->stop_poller);
929 : :
930 : : /* now let the worker drain and check it's outstanding IO with a poller */
931 : 1176 : worker->is_draining = true;
932 : 1176 : worker->is_draining_poller = SPDK_POLLER_REGISTER(_check_draining, worker, 0);
933 : :
934 : 1176 : return SPDK_POLLER_BUSY;
935 : : }
936 : :
937 : : static void shutdown_cb(void);
938 : :
939 : : static void
940 : 1176 : _init_thread(void *arg1)
941 : : {
942 : : struct worker_thread *worker;
943 : : struct ap_task *task;
944 : 1176 : int i, num_tasks = g_allocate_depth;
945 : 1176 : struct display_info *display = arg1;
946 : :
947 : 1176 : worker = calloc(1, sizeof(*worker));
948 [ - + ]: 1176 : if (worker == NULL) {
949 [ # # # # ]: 0 : fprintf(stderr, "Unable to allocate worker\n");
950 : 0 : free(display);
951 : 0 : spdk_thread_exit(spdk_get_thread());
952 : 0 : goto no_worker;
953 : : }
954 : :
955 : 1176 : worker->workload = g_workload_selection;
956 : 1176 : worker->display.core = display->core;
957 : 1176 : worker->display.thread = display->thread;
958 : 1176 : free(display);
959 : 1176 : worker->core = spdk_env_get_current_core();
960 : 1176 : worker->thread = spdk_get_thread();
961 [ - + ]: 1176 : pthread_mutex_lock(&g_workers_lock);
962 : 1176 : g_num_workers++;
963 : 1176 : worker->next = g_workers;
964 : 1176 : g_workers = worker;
965 [ - + ]: 1176 : pthread_mutex_unlock(&g_workers_lock);
966 : 1176 : worker->ch = spdk_accel_get_io_channel();
967 [ - + ]: 1176 : if (worker->ch == NULL) {
968 [ # # # # ]: 0 : fprintf(stderr, "Unable to get an accel channel\n");
969 : 0 : goto error;
970 : : }
971 : :
972 : 1176 : TAILQ_INIT(&worker->tasks_pool);
973 : :
974 : 1176 : worker->task_base = calloc(num_tasks, sizeof(struct ap_task));
975 [ - + ]: 1176 : if (worker->task_base == NULL) {
976 [ # # # # ]: 0 : fprintf(stderr, "Could not allocate task base.\n");
977 : 0 : goto error;
978 : : }
979 : :
980 : 1176 : task = worker->task_base;
981 [ + + ]: 40152 : for (i = 0; i < num_tasks; i++) {
982 : 38976 : TAILQ_INSERT_TAIL(&worker->tasks_pool, task, link);
983 : 38976 : task->worker = worker;
984 [ - + ]: 38976 : if (_get_task_data_bufs(task)) {
985 [ # # # # ]: 0 : fprintf(stderr, "Unable to get data bufs\n");
986 : 0 : goto error;
987 : : }
988 : 38976 : task++;
989 : : }
990 : :
991 : : /* Register a poller that will stop the worker at time elapsed */
992 : 1176 : worker->stop_poller = SPDK_POLLER_REGISTER(_worker_stop, worker,
993 : : g_time_in_sec * 1000000ULL);
994 : :
995 : : /* Load up queue depth worth of operations. */
996 [ + + ]: 40152 : for (i = 0; i < g_queue_depth; i++) {
997 : 38976 : task = _get_task(worker);
998 [ - + ]: 38976 : if (task == NULL) {
999 : 0 : goto error;
1000 : : }
1001 : :
1002 : 38976 : _submit_single(worker, task);
1003 : : }
1004 : 1176 : return;
1005 : 0 : error:
1006 : :
1007 : 0 : _free_task_buffers_in_pool(worker);
1008 : 0 : free(worker->task_base);
1009 : 0 : no_worker:
1010 : 0 : shutdown_cb();
1011 : 0 : g_rc = -1;
1012 : : }
1013 : :
1014 : : static void
1015 : 840 : accel_perf_start(void *arg1)
1016 : : {
1017 : 840 : struct spdk_cpuset tmp_cpumask = {};
1018 : 386 : char thread_name[32];
1019 : : uint32_t i;
1020 : : int j;
1021 : : struct spdk_thread *thread;
1022 : : struct display_info *display;
1023 : :
1024 : 840 : g_tsc_rate = spdk_get_ticks_hz();
1025 : 840 : g_tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate;
1026 : :
1027 : 840 : dump_user_config();
1028 : :
1029 [ - + ]: 840 : printf("Running for %d seconds...\n", g_time_in_sec);
1030 : 840 : fflush(stdout);
1031 : :
1032 : : /* Create worker threads for each core that was specified. */
1033 [ + + ]: 1932 : SPDK_ENV_FOREACH_CORE(i) {
1034 [ + + ]: 2268 : for (j = 0; j < g_threads_per_core; j++) {
1035 [ - + ]: 1176 : snprintf(thread_name, sizeof(thread_name), "ap_worker_%u_%u", i, j);
1036 : 1176 : spdk_cpuset_zero(&tmp_cpumask);
1037 : 1176 : spdk_cpuset_set_cpu(&tmp_cpumask, i, true);
1038 : 1176 : thread = spdk_thread_create(thread_name, &tmp_cpumask);
1039 : 1176 : display = calloc(1, sizeof(*display));
1040 [ - + ]: 1176 : if (display == NULL) {
1041 [ # # # # ]: 0 : fprintf(stderr, "Unable to allocate memory\n");
1042 : 0 : spdk_app_stop(-1);
1043 : 0 : return;
1044 : : }
1045 : 1176 : display->core = i;
1046 : 1176 : display->thread = j;
1047 : 1176 : spdk_thread_send_msg(thread, _init_thread, display);
1048 : : }
1049 : : }
1050 : : }
1051 : :
1052 : : static void
1053 : 882 : accel_perf_free_compress_segs(void)
1054 : : {
1055 : : struct ap_compress_seg *seg, *tmp;
1056 : :
1057 [ + + ]: 5712 : STAILQ_FOREACH_SAFE(seg, &g_compress_segs, link, tmp) {
1058 : 4830 : free(seg->uncompressed_iovs);
1059 : 4830 : free(seg->compressed_iovs);
1060 : 4830 : spdk_dma_free(seg->compressed_data);
1061 : 4830 : spdk_dma_free(seg->uncompressed_data);
1062 [ + + ]: 4830 : STAILQ_REMOVE_HEAD(&g_compress_segs, link);
1063 : 4830 : free(seg);
1064 : : }
1065 : 882 : }
1066 : :
1067 : : struct accel_perf_prep_ctx {
1068 : : FILE *file;
1069 : : long remaining;
1070 : : struct spdk_io_channel *ch;
1071 : : struct ap_compress_seg *cur_seg;
1072 : : };
1073 : :
1074 : : static void accel_perf_prep_process_seg(struct accel_perf_prep_ctx *ctx);
1075 : :
1076 : : static void
1077 : 4830 : accel_perf_prep_process_seg_cpl(void *ref, int status)
1078 : : {
1079 : 4830 : struct accel_perf_prep_ctx *ctx = ref;
1080 : : struct ap_compress_seg *seg;
1081 : :
1082 [ - + ]: 4830 : if (status != 0) {
1083 [ # # # # ]: 0 : fprintf(stderr, "error (%d) on initial compress completion\n", status);
1084 : 0 : spdk_dma_free(ctx->cur_seg->compressed_data);
1085 : 0 : spdk_dma_free(ctx->cur_seg->uncompressed_data);
1086 : 0 : free(ctx->cur_seg);
1087 : 0 : spdk_put_io_channel(ctx->ch);
1088 : 0 : fclose(ctx->file);
1089 : 0 : free(ctx);
1090 : 0 : spdk_app_stop(-status);
1091 : 0 : return;
1092 : : }
1093 : :
1094 : 4830 : seg = ctx->cur_seg;
1095 : :
1096 [ + + ]: 4830 : if (g_workload_selection == SPDK_ACCEL_OPC_DECOMPRESS) {
1097 : 3654 : seg->compressed_iovs = calloc(g_chained_count, sizeof(struct iovec));
1098 [ - + ]: 3654 : if (seg->compressed_iovs == NULL) {
1099 [ # # # # ]: 0 : fprintf(stderr, "unable to allocate iovec\n");
1100 : 0 : spdk_dma_free(seg->compressed_data);
1101 : 0 : spdk_dma_free(seg->uncompressed_data);
1102 : 0 : free(seg);
1103 : 0 : spdk_put_io_channel(ctx->ch);
1104 : 0 : fclose(ctx->file);
1105 : 0 : free(ctx);
1106 : 0 : spdk_app_stop(-ENOMEM);
1107 : 0 : return;
1108 : : }
1109 : 3654 : seg->compressed_iovcnt = g_chained_count;
1110 : :
1111 : 3654 : accel_perf_construct_iovs(seg->compressed_data, seg->compressed_len, seg->compressed_iovs,
1112 : : seg->compressed_iovcnt);
1113 : : }
1114 : :
1115 : 4830 : STAILQ_INSERT_TAIL(&g_compress_segs, seg, link);
1116 : 4830 : ctx->remaining -= seg->uncompressed_len;
1117 : :
1118 : 4830 : accel_perf_prep_process_seg(ctx);
1119 : : }
1120 : :
1121 : : static void
1122 : 5124 : accel_perf_prep_process_seg(struct accel_perf_prep_ctx *ctx)
1123 : : {
1124 : : struct ap_compress_seg *seg;
1125 : : int sz, sz_read, sz_padded;
1126 : : void *ubuf, *cbuf;
1127 : 2196 : struct iovec iov[1];
1128 : : int rc;
1129 : :
1130 [ + + ]: 5124 : if (ctx->remaining == 0) {
1131 : 294 : spdk_put_io_channel(ctx->ch);
1132 : 294 : fclose(ctx->file);
1133 : 294 : free(ctx);
1134 : 294 : accel_perf_start(NULL);
1135 : 3054 : return;
1136 : : }
1137 : :
1138 : 4830 : sz = spdk_min(ctx->remaining, g_xfer_size_bytes);
1139 : : /* Add 10% pad to the compress buffer for incompressible data. Note that a real app
1140 : : * would likely either deal with the failure of not having a large enough buffer
1141 : : * by submitting another operation with a larger one. Or, like the vbdev module
1142 : : * does, just accept the error and use the data uncompressed marking it as such in
1143 : : * its own metadata so that in the future it doesn't try to decompress uncompressed
1144 : : * data, etc.
1145 : : */
1146 : 4830 : sz_padded = sz * COMP_BUF_PAD_PERCENTAGE;
1147 : :
1148 : 4830 : ubuf = spdk_dma_zmalloc(sz, ALIGN_4K, NULL);
1149 [ - + ]: 4830 : if (!ubuf) {
1150 [ # # ]: 0 : fprintf(stderr, "unable to allocate uncompress buffer\n");
1151 : 0 : rc = -ENOMEM;
1152 : 0 : goto error;
1153 : : }
1154 : :
1155 : 4830 : cbuf = spdk_dma_malloc(sz_padded, ALIGN_4K, NULL);
1156 [ - + ]: 4830 : if (!cbuf) {
1157 [ # # ]: 0 : fprintf(stderr, "unable to allocate compress buffer\n");
1158 : 0 : rc = -ENOMEM;
1159 : 0 : spdk_dma_free(ubuf);
1160 : 0 : goto error;
1161 : : }
1162 : :
1163 : 4830 : seg = calloc(1, sizeof(*seg));
1164 [ - + ]: 4830 : if (!seg) {
1165 [ # # ]: 0 : fprintf(stderr, "unable to allocate comp/decomp segment\n");
1166 : 0 : spdk_dma_free(ubuf);
1167 : 0 : spdk_dma_free(cbuf);
1168 : 0 : rc = -ENOMEM;
1169 : 0 : goto error;
1170 : : }
1171 : :
1172 : 4830 : sz_read = fread(ubuf, sizeof(uint8_t), sz, ctx->file);
1173 [ - + ]: 4830 : if (sz_read != sz) {
1174 [ # # ]: 0 : fprintf(stderr, "unable to read input file\n");
1175 : 0 : free(seg);
1176 : 0 : spdk_dma_free(ubuf);
1177 : 0 : spdk_dma_free(cbuf);
1178 : 0 : rc = -errno;
1179 : 0 : goto error;
1180 : : }
1181 : :
1182 [ + + ]: 4830 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS) {
1183 : 1176 : seg->uncompressed_iovs = calloc(g_chained_count, sizeof(struct iovec));
1184 [ - + ]: 1176 : if (seg->uncompressed_iovs == NULL) {
1185 [ # # ]: 0 : fprintf(stderr, "unable to allocate iovec\n");
1186 : 0 : free(seg);
1187 : 0 : spdk_dma_free(ubuf);
1188 : 0 : spdk_dma_free(cbuf);
1189 : 0 : rc = -ENOMEM;
1190 : 0 : goto error;
1191 : : }
1192 : 1176 : seg->uncompressed_iovcnt = g_chained_count;
1193 : 1176 : accel_perf_construct_iovs(ubuf, sz, seg->uncompressed_iovs, seg->uncompressed_iovcnt);
1194 : : }
1195 : :
1196 : 4830 : seg->uncompressed_data = ubuf;
1197 : 4830 : seg->uncompressed_len = sz;
1198 : 4830 : seg->compressed_data = cbuf;
1199 : 4830 : seg->compressed_len = sz;
1200 : 4830 : seg->compressed_len_padded = sz_padded;
1201 : :
1202 : 4830 : ctx->cur_seg = seg;
1203 : 4830 : iov[0].iov_base = seg->uncompressed_data;
1204 : 4830 : iov[0].iov_len = seg->uncompressed_len;
1205 : : /* Note that anytime a call is made to spdk_accel_submit_compress() there's a chance
1206 : : * it will fail with -ENOMEM in the event that the destination buffer is not large enough
1207 : : * to hold the compressed data. This example app simply adds 10% buffer for compressed data
1208 : : * but real applications may want to consider a more sophisticated method.
1209 : : */
1210 : 4830 : rc = spdk_accel_submit_compress(ctx->ch, seg->compressed_data, seg->compressed_len_padded, iov, 1,
1211 : : &seg->compressed_len, 0, accel_perf_prep_process_seg_cpl, ctx);
1212 [ - + ]: 4830 : if (rc < 0) {
1213 [ # # ]: 0 : fprintf(stderr, "error (%d) on initial compress submission\n", rc);
1214 : 0 : goto error;
1215 : : }
1216 : :
1217 : 4830 : return;
1218 : :
1219 : 0 : error:
1220 : 0 : spdk_put_io_channel(ctx->ch);
1221 : 0 : fclose(ctx->file);
1222 : 0 : free(ctx);
1223 : 0 : spdk_app_stop(rc);
1224 : : }
1225 : :
1226 : : static void
1227 : 882 : accel_perf_prep(void *arg1)
1228 : : {
1229 : : struct accel_perf_prep_ctx *ctx;
1230 : 882 : const char *module_name = NULL;
1231 : 882 : int rc = 0;
1232 : :
1233 [ - + ]: 882 : if (g_module_name) {
1234 : 0 : rc = spdk_accel_get_opc_module_name(g_workload_selection, &module_name);
1235 [ # # # # : 0 : if (rc != 0 || strcmp(g_module_name, module_name) != 0) {
# # # # ]
1236 [ # # ]: 0 : fprintf(stderr, "Module '%s' was assigned via JSON config or RPC, instead of '%s'\n",
1237 : : module_name, g_module_name);
1238 [ # # ]: 0 : fprintf(stderr, "-M option is not compatible with accel_assign_opc RPC\n");
1239 : 0 : rc = -EINVAL;
1240 : 0 : goto error_end;
1241 : : }
1242 : : }
1243 : :
1244 [ + + ]: 882 : if (g_workload_selection != SPDK_ACCEL_OPC_COMPRESS &&
1245 [ + + ]: 798 : g_workload_selection != SPDK_ACCEL_OPC_DECOMPRESS) {
1246 : 546 : accel_perf_start(arg1);
1247 : 714 : return;
1248 : : }
1249 : :
1250 [ + + ]: 336 : if (g_cd_file_in_name == NULL) {
1251 [ - + ]: 21 : fprintf(stdout, "A filename is required.\n");
1252 : 21 : rc = -EINVAL;
1253 : 21 : goto error_end;
1254 : : }
1255 : :
1256 [ + + + + : 315 : if (g_workload_selection == SPDK_ACCEL_OPC_COMPRESS && g_verify) {
+ + ]
1257 [ - + ]: 21 : fprintf(stdout, "\nCompression does not support the verify option, aborting.\n");
1258 : 21 : rc = -ENOTSUP;
1259 : 21 : goto error_end;
1260 : : }
1261 : :
1262 : 294 : printf("Preparing input file...\n");
1263 : :
1264 : 294 : ctx = calloc(1, sizeof(*ctx));
1265 [ - + ]: 294 : if (ctx == NULL) {
1266 : 0 : rc = -ENOMEM;
1267 : 0 : goto error_end;
1268 : : }
1269 : :
1270 : 294 : ctx->file = fopen(g_cd_file_in_name, "r");
1271 [ - + ]: 294 : if (ctx->file == NULL) {
1272 [ # # ]: 0 : fprintf(stderr, "Could not open file %s.\n", g_cd_file_in_name);
1273 : 0 : rc = -errno;
1274 : 0 : goto error_ctx;
1275 : : }
1276 : :
1277 : 294 : fseek(ctx->file, 0L, SEEK_END);
1278 : 294 : ctx->remaining = ftell(ctx->file);
1279 : 294 : fseek(ctx->file, 0L, SEEK_SET);
1280 : :
1281 : 294 : ctx->ch = spdk_accel_get_io_channel();
1282 [ - + ]: 294 : if (ctx->ch == NULL) {
1283 : 0 : rc = -EAGAIN;
1284 : 0 : goto error_file;
1285 : : }
1286 : :
1287 [ + + ]: 294 : if (g_xfer_size_bytes == 0) {
1288 : : /* size of 0 means "file at a time" */
1289 : 126 : g_xfer_size_bytes = ctx->remaining;
1290 : : }
1291 : :
1292 : 294 : accel_perf_prep_process_seg(ctx);
1293 : 294 : return;
1294 : :
1295 : 0 : error_file:
1296 : 0 : fclose(ctx->file);
1297 : 0 : error_ctx:
1298 : 0 : free(ctx);
1299 : 42 : error_end:
1300 : 42 : spdk_app_stop(rc);
1301 : : }
1302 : :
1303 : : static void
1304 : 0 : worker_shutdown(void *ctx)
1305 : : {
1306 : 0 : _worker_stop(ctx);
1307 : 0 : }
1308 : :
1309 : : static void
1310 : 0 : shutdown_cb(void)
1311 : : {
1312 : : struct worker_thread *worker;
1313 : :
1314 [ # # ]: 0 : pthread_mutex_lock(&g_workers_lock);
1315 [ # # ]: 0 : if (!g_workers) {
1316 : 0 : spdk_app_stop(1);
1317 : 0 : goto unlock;
1318 : : }
1319 : :
1320 : 0 : worker = g_workers;
1321 [ # # ]: 0 : while (worker) {
1322 : 0 : spdk_thread_send_msg(worker->thread, worker_shutdown, worker);
1323 : 0 : worker = worker->next;
1324 : : }
1325 : 0 : unlock:
1326 [ # # ]: 0 : pthread_mutex_unlock(&g_workers_lock);
1327 : 0 : }
1328 : :
1329 : : int
1330 : 945 : main(int argc, char **argv)
1331 : : {
1332 : : struct worker_thread *worker, *tmp;
1333 : : int rc;
1334 : :
1335 [ - + ]: 945 : pthread_mutex_init(&g_workers_lock, NULL);
1336 : 945 : spdk_app_opts_init(&g_opts, sizeof(g_opts));
1337 : 945 : g_opts.name = "accel_perf";
1338 : 945 : g_opts.reactor_mask = "0x1";
1339 : 945 : g_opts.shutdown_cb = shutdown_cb;
1340 : :
1341 : 945 : rc = spdk_app_parse_args(argc, argv, &g_opts, "a:C:o:q:t:yw:M:P:f:T:l:S:x:", NULL,
1342 : : parse_args, usage);
1343 [ + + ]: 945 : if (rc != SPDK_APP_PARSE_ARGS_SUCCESS) {
1344 : 63 : return rc == SPDK_APP_PARSE_ARGS_HELP ? 0 : 1;
1345 : : }
1346 : :
1347 [ - + ]: 882 : if (g_workload_selection == SPDK_ACCEL_OPC_LAST) {
1348 [ # # # # ]: 0 : fprintf(stderr, "Must provide a workload type\n");
1349 : 0 : usage();
1350 : 0 : return -1;
1351 : : }
1352 : :
1353 [ + + - + ]: 882 : if (g_allocate_depth > 0 && g_queue_depth > g_allocate_depth) {
1354 [ # # # # ]: 0 : fprintf(stdout, "allocate depth must be at least as big as queue depth\n");
1355 : 0 : usage();
1356 : 0 : return -1;
1357 : : }
1358 : :
1359 [ + + ]: 882 : if (g_allocate_depth == 0) {
1360 : 840 : g_allocate_depth = g_queue_depth;
1361 : : }
1362 : :
1363 [ + + ]: 882 : if ((g_workload_selection == SPDK_ACCEL_OPC_CRC32C ||
1364 [ + + ]: 798 : g_workload_selection == SPDK_ACCEL_OPC_COPY_CRC32C ||
1365 [ + + ]: 714 : g_workload_selection == SPDK_ACCEL_OPC_DIF_VERIFY ||
1366 [ + + ]: 672 : g_workload_selection == SPDK_ACCEL_OPC_DIF_GENERATE) &&
1367 [ - + ]: 252 : g_chained_count == 0) {
1368 : 0 : usage();
1369 : 0 : return -1;
1370 : : }
1371 : :
1372 [ + + - + ]: 882 : if (g_workload_selection == SPDK_ACCEL_OPC_XOR && g_xor_src_count < 2) {
1373 : 0 : usage();
1374 : 0 : return -1;
1375 : : }
1376 : :
1377 [ - + - - ]: 882 : if (g_module_name && spdk_accel_assign_opc(g_workload_selection, g_module_name)) {
1378 [ # # # # ]: 0 : fprintf(stderr, "Was not able to assign '%s' module to the workload\n", g_module_name);
1379 : 0 : usage();
1380 : 0 : return -1;
1381 : : }
1382 : :
1383 : 882 : g_rc = spdk_app_start(&g_opts, accel_perf_prep, NULL);
1384 [ + + ]: 882 : if (g_rc) {
1385 : 42 : SPDK_ERRLOG("ERROR starting application\n");
1386 : : }
1387 : :
1388 [ - + ]: 882 : pthread_mutex_destroy(&g_workers_lock);
1389 : :
1390 : 882 : worker = g_workers;
1391 [ + + ]: 2058 : while (worker) {
1392 : 1176 : tmp = worker->next;
1393 : 1176 : free(worker);
1394 : 1176 : worker = tmp;
1395 : : }
1396 : 882 : accel_perf_free_compress_segs();
1397 : 882 : spdk_app_fini();
1398 : 882 : return g_rc;
1399 : : }
|