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