diff --git a/examples/accel/perf/accel_perf.c b/examples/accel/perf/accel_perf.c index 17a406af9..924a5b129 100644 --- a/examples/accel/perf/accel_perf.c +++ b/examples/accel/perf/accel_perf.c @@ -290,6 +290,12 @@ _accel_done(void *arg1) worker->xfer_failed++; } break; + case ACCEL_FILL: + if (memcmp(task->dst, task->src, g_xfer_size_bytes)) { + SPDK_NOTICELOG("Data miscompare\n"); + worker->xfer_failed++; + } + break; default: assert(false); break; @@ -438,6 +444,11 @@ _get_task_data_bufs(struct ap_task *task) memset(task->dst, ~DATA_PATTERN, g_xfer_size_bytes); } + /* For fill, set the entire src buffer so we can check if verify is enabled. */ + if (g_workload_selection == ACCEL_FILL) { + memset(task->src, g_fill_pattern, g_xfer_size_bytes); + } + if (g_workload_selection == ACCEL_DUALCAST) { task->dst2 = spdk_dma_zmalloc(g_xfer_size_bytes, align, NULL); if (task->dst2 == NULL) { @@ -471,6 +482,11 @@ _batch_prep_cmd(struct worker_thread *worker, struct ap_task *task, struct spdk_ worker->ch, batch, task->dst, task->src, g_xfer_size_bytes, accel_done); break; + case ACCEL_FILL: + rc = spdk_accel_batch_prep_fill(__accel_task_from_ap_task(task), + worker->ch, batch, task->dst, *(uint8_t *)task->src, + g_xfer_size_bytes, accel_done); + break; default: assert(false); break; @@ -524,7 +540,8 @@ _init_thread(void *arg1) /* TODO: remove the workload selection checks once all are added. */ if ((g_workload_selection == ACCEL_COPY || g_workload_selection == ACCEL_DUALCAST || - g_workload_selection == ACCEL_COMPARE) + g_workload_selection == ACCEL_COMPARE || + g_workload_selection == ACCEL_FILL) && ((g_capabilites & ACCEL_BATCH) == ACCEL_BATCH) && g_queue_depth > 1) { diff --git a/include/spdk/accel_engine.h b/include/spdk/accel_engine.h index 30653ea80..428c771ca 100644 --- a/include/spdk/accel_engine.h +++ b/include/spdk/accel_engine.h @@ -262,6 +262,26 @@ int spdk_accel_submit_compare(struct spdk_accel_task *accel_req, struct spdk_io_ void *src1, void *src2, uint64_t nbytes, spdk_accel_completion_cb cb); +/** + * Synchronous call to prepare a fill request into a previously initialized batch + * created with spdk_accel_batch_create(). The callback will be called when the fill + * completes after the batch has been submitted by an asynchronous call to + * spdk_accel_batch_submit(). + * + * \param accel_req Accel request task. + * \param ch I/O channel to submit request to the accel engine. + * \param batch Handle provided when the batch was started with spdk_accel_batch_create(). + * \param dst Destination to fill. + * \param fill Constant byte to fill to the destination. + * \param nbytes Length in bytes to fill. + * \param cb Called when this operation completes. + * + * \return 0 on success, negative errno on failure. + */ +int spdk_accel_batch_prep_fill(struct spdk_accel_task *accel_req, struct spdk_io_channel *ch, + struct spdk_accel_batch *batch, void *dst, uint8_t fill, + uint64_t nbytes, spdk_accel_completion_cb cb); + /** * Submit a fill request. * diff --git a/include/spdk_internal/accel_engine.h b/include/spdk_internal/accel_engine.h index 6dc0349fc..e8c2d880a 100644 --- a/include/spdk_internal/accel_engine.h +++ b/include/spdk_internal/accel_engine.h @@ -58,6 +58,8 @@ struct spdk_accel_engine { void *dst1, void *dst2, void *src, uint64_t nbytes, spdk_accel_completion_cb cb); int (*batch_prep_compare)(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch, void *src1, void *src2, uint64_t nbytes, spdk_accel_completion_cb cb); + int (*batch_prep_fill)(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch, + void *dst, uint8_t fill, uint64_t nbytes, spdk_accel_completion_cb cb); int (*batch_submit)(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch, spdk_accel_completion_cb cb); int (*compare)(void *cb_arg, struct spdk_io_channel *ch, void *src1, void *src2, diff --git a/lib/accel/accel_engine.c b/lib/accel/accel_engine.c index 1d538965b..7d36585d7 100644 --- a/lib/accel/accel_engine.c +++ b/lib/accel/accel_engine.c @@ -255,6 +255,21 @@ spdk_accel_batch_prep_compare(struct spdk_accel_task *accel_req, struct spdk_io_ batch, src1, src2, nbytes, _accel_engine_done); } +/* Accel framework public API for batch prep_fill function. All engines are + * required to implement this API. + */ +int +spdk_accel_batch_prep_fill(struct spdk_accel_task *accel_req, struct spdk_io_channel *ch, + struct spdk_accel_batch *batch, void *dst, uint8_t fill, uint64_t nbytes, + spdk_accel_completion_cb cb) +{ + struct accel_io_channel *accel_ch = spdk_io_channel_get_ctx(ch); + + accel_req->cb = cb; + return accel_ch->engine->batch_prep_fill(accel_req->offload_ctx, accel_ch->ch, + batch, dst, fill, nbytes, _accel_engine_done); +} + /* Accel framework public API for compare function */ int spdk_accel_submit_compare(struct spdk_accel_task *accel_req, struct spdk_io_channel *ch, @@ -626,6 +641,29 @@ sw_accel_batch_prep_compare(void *cb_arg, struct spdk_io_channel *ch, return 0; } +static int +sw_accel_batch_prep_fill(void *cb_arg, struct spdk_io_channel *ch, + struct spdk_accel_batch *batch, void *dst, uint8_t fill, + uint64_t nbytes, spdk_accel_completion_cb cb) +{ + struct sw_accel_op *op; + struct sw_accel_io_channel *sw_ch = spdk_io_channel_get_ctx(ch); + + op = _prep_op(cb_arg, sw_ch, batch, cb); + if (op == NULL) { + return -EINVAL; + } + + /* Command specific. */ + op->dst = dst; + op->fill_pattern = fill; + op->nbytes = nbytes; + op->op_code = SW_ACCEL_OPCODE_MEMFILL; + TAILQ_INSERT_TAIL(&sw_ch->batch, op, link); + + return 0; +} + static int sw_accel_batch_submit(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch, spdk_accel_completion_cb cb) @@ -657,6 +695,9 @@ sw_accel_batch_submit(void *cb_arg, struct spdk_io_channel *ch, struct spdk_acce case SW_ACCEL_OPCODE_COMPARE: cmd_status = memcmp(op->src, op->src2, op->nbytes); break; + case SW_ACCEL_OPCODE_MEMFILL: + memset(op->dst, op->fill_pattern, op->nbytes); + break; default: assert(false); break; @@ -759,6 +800,7 @@ static struct spdk_accel_engine sw_accel_engine = { .batch_prep_copy = sw_accel_batch_prep_copy, .batch_prep_dualcast = sw_accel_batch_prep_dualcast, .batch_prep_compare = sw_accel_batch_prep_compare, + .batch_prep_fill = sw_accel_batch_prep_fill, .batch_submit = sw_accel_batch_submit, .compare = sw_accel_submit_compare, .fill = sw_accel_submit_fill, diff --git a/lib/accel/spdk_accel.map b/lib/accel/spdk_accel.map index c6dbc37d4..e7f2f0546 100644 --- a/lib/accel/spdk_accel.map +++ b/lib/accel/spdk_accel.map @@ -13,6 +13,7 @@ spdk_accel_batch_prep_copy; spdk_accel_batch_prep_dualcast; spdk_accel_batch_prep_compare; + spdk_accel_batch_prep_fill; spdk_accel_batch_submit; spdk_accel_submit_copy; spdk_accel_submit_dualcast;