Commit 59f55d23 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

accel: add support for appending a decompress operation



Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I5f091a554e08f0e052ab9e7eb9a1789d381b885f
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15635


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
parent 6293ac87
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -319,6 +319,32 @@ int spdk_accel_append_fill(struct spdk_accel_sequence **seq, struct spdk_io_chan
			   struct spdk_memory_domain *domain, void *domain_ctx, uint8_t pattern,
			   int flags, spdk_accel_step_cb cb_fn, void *cb_arg);

/**
 * Append a decompress operation to a sequence.
 *
 * \param seq Sequence object.  If NULL, a new sequence object will be created.
 * \param ch I/O channel.
 * \param dst_iovs Destination I/O vector array.
 * \param dst_iovcnt Size of the `dst_iovs` array.
 * \param dst_domain Memory domain to which the destination buffers belong.
 * \param dst_domain_ctx Destination buffer domain context.
 * \param src_iovs Source I/O vector array.
 * \param src_iovcnt Size of the `src_iovs` array.
 * \param src_domain Memory domain to which the source buffers belong.
 * \param src_domain_ctx Source buffer domain context.
 * \param flags Accel operation flags.
 * \param cb_fn Callback to be executed once this operation is completed.
 * \param cb_arg Argument to be passed to `cb_fn`.
 *
 * \return 0 if operation was successfully added to the sequence, negative errno otherwise.
 */
int spdk_accel_append_decompress(struct spdk_accel_sequence **seq, struct spdk_io_channel *ch,
				 struct iovec *dst_iovs, size_t dst_iovcnt,
				 struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
				 struct iovec *src_iovs, size_t src_iovcnt,
				 struct spdk_memory_domain *src_domain, void *src_domain_ctx,
				 int flags, spdk_accel_step_cb cb_fn, void *cb_arg);

/**
 * Finish a sequence and execute all its operations. After the completion callback is executed, the
 * sequence object is automatically freed.
+51 −0
Original line number Diff line number Diff line
@@ -662,6 +662,57 @@ spdk_accel_append_fill(struct spdk_accel_sequence **pseq, struct spdk_io_channel
	return 0;
}

int
spdk_accel_append_decompress(struct spdk_accel_sequence **pseq, struct spdk_io_channel *ch,
			     struct iovec *dst_iovs, size_t dst_iovcnt,
			     struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
			     struct iovec *src_iovs, size_t src_iovcnt,
			     struct spdk_memory_domain *src_domain, void *src_domain_ctx,
			     int flags, spdk_accel_step_cb cb_fn, void *cb_arg)
{
	struct accel_io_channel *accel_ch = spdk_io_channel_get_ctx(ch);
	struct spdk_accel_task *task;
	struct spdk_accel_sequence *seq = *pseq;

	if (dst_domain != NULL || src_domain != NULL) {
		SPDK_ERRLOG("Memory domains are currently unsupported\n");
		return -EINVAL;
	}

	if (seq == NULL) {
		seq = accel_sequence_get(accel_ch);
		if (spdk_unlikely(seq == NULL)) {
			return -ENOMEM;
		}
	}

	assert(seq->ch == accel_ch);
	task = accel_sequence_get_task(accel_ch, seq, cb_fn, cb_arg);
	if (spdk_unlikely(task == NULL)) {
		if (*pseq == NULL) {
			accel_sequence_put(seq);
		}

		return -ENOMEM;
	}

	task->dst_domain = dst_domain;
	task->dst_domain_ctx = dst_domain_ctx;
	task->d.iovs = dst_iovs;
	task->d.iovcnt = dst_iovcnt;
	task->src_domain = src_domain;
	task->src_domain_ctx = src_domain_ctx;
	task->s.iovs = src_iovs;
	task->s.iovcnt = src_iovcnt;
	task->flags = flags;
	task->op_code = ACCEL_OPC_DECOMPRESS;

	TAILQ_INSERT_TAIL(&seq->tasks, task, seq_link);
	*pseq = seq;

	return 0;
}

static void
accel_sequence_complete_tasks(struct spdk_accel_sequence *seq)
{
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
	spdk_accel_write_config_json;
	spdk_accel_append_copy;
	spdk_accel_append_fill;
	spdk_accel_append_decompress;
	spdk_accel_sequence_finish;
	spdk_accel_sequence_abort;
	spdk_accel_sequence_reverse;
+162 −0
Original line number Diff line number Diff line
@@ -848,6 +848,15 @@ test_sequence_append_error(void)
	CU_ASSERT_EQUAL(rc, -ENOMEM);
	CU_ASSERT_PTR_NULL(seq);

	dst_iovs.iov_base = buf;
	dst_iovs.iov_len = 2048;
	src_iovs.iov_base = &buf[2048];
	src_iovs.iov_len = 2048;
	rc = spdk_accel_append_decompress(&seq, ioch, &dst_iovs, 1, NULL, NULL,
					  &src_iovs, 1, NULL, NULL, 0, ut_sequence_step_cb, NULL);
	CU_ASSERT_EQUAL(rc, -ENOMEM);
	CU_ASSERT_PTR_NULL(seq);

	/* Check that the same happens when the sequence queue is empty */
	TAILQ_SWAP(&tasks, &accel_ch->task_pool, spdk_accel_task, link);
	TAILQ_SWAP(&seqs, &accel_ch->seq_pool, spdk_accel_sequence, link);
@@ -866,6 +875,15 @@ test_sequence_append_error(void)
	CU_ASSERT_EQUAL(rc, -ENOMEM);
	CU_ASSERT_PTR_NULL(seq);

	dst_iovs.iov_base = buf;
	dst_iovs.iov_len = 2048;
	src_iovs.iov_base = &buf[2048];
	src_iovs.iov_len = 2048;
	rc = spdk_accel_append_decompress(&seq, ioch, &dst_iovs, 1, NULL, NULL,
					  &src_iovs, 1, NULL, NULL, 0, ut_sequence_step_cb, NULL);
	CU_ASSERT_EQUAL(rc, -ENOMEM);
	CU_ASSERT_PTR_NULL(seq);

	TAILQ_SWAP(&tasks, &accel_ch->task_pool, spdk_accel_task, link);

	spdk_put_io_channel(ioch);
@@ -1033,6 +1051,147 @@ test_sequence_completion_error(void)
	poll_threads();
}

#ifdef SPDK_CONFIG_ISAL
static void
ut_compress_cb(void *cb_arg, int status)
{
	int *completed = cb_arg;

	CU_ASSERT_EQUAL(status, 0);

	*completed = 1;
}

static void
test_sequence_decompress(void)
{
	struct spdk_accel_sequence *seq = NULL;
	struct spdk_io_channel *ioch;
	struct ut_sequence ut_seq;
	char buf[4096], tmp[2][4096], expected[4096];
	struct iovec src_iovs[2], dst_iovs[2];
	uint32_t compressed_size;
	int rc, completed = 0;

	ioch = spdk_accel_get_io_channel();
	SPDK_CU_ASSERT_FATAL(ioch != NULL);

	memset(expected, 0xa5, sizeof(expected));
	src_iovs[0].iov_base = expected;
	src_iovs[0].iov_len = sizeof(expected);
	rc = spdk_accel_submit_compress(ioch, tmp[0], sizeof(tmp[0]), &src_iovs[0], 1,
					&compressed_size, 0, ut_compress_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	while (!completed) {
		poll_threads();
	}

	/* Check a single decompress operation in a sequence */
	seq = NULL;
	completed = 0;

	dst_iovs[0].iov_base = buf;
	dst_iovs[0].iov_len = sizeof(buf);
	src_iovs[0].iov_base = tmp[0];
	src_iovs[0].iov_len = compressed_size;
	rc = spdk_accel_append_decompress(&seq, ioch, &dst_iovs[0], 1, NULL, NULL,
					  &src_iovs[0], 1, NULL, NULL, 0,
					  ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	ut_seq.complete = false;
	rc = spdk_accel_sequence_finish(seq, ut_sequence_complete_cb, &ut_seq);
	CU_ASSERT_EQUAL(rc, 0);

	poll_threads();

	CU_ASSERT_EQUAL(completed, 1);
	CU_ASSERT(ut_seq.complete);
	CU_ASSERT_EQUAL(ut_seq.status, 0);
	CU_ASSERT_EQUAL(memcmp(buf, expected, sizeof(buf)), 0);

	/* Put the decompress operation in the middle of a sequence with a copy operation at the
	 * beginning and a fill at the end modifying the first 2048B of the buffer.
	 */
	memset(expected, 0xfe, 2048);
	memset(buf, 0, sizeof(buf));
	seq = NULL;
	completed = 0;

	dst_iovs[0].iov_base = tmp[1];
	dst_iovs[0].iov_len = compressed_size;
	src_iovs[0].iov_base = tmp[0];
	src_iovs[0].iov_len = compressed_size;
	rc = spdk_accel_append_copy(&seq, ioch, &dst_iovs[0], 1, NULL, NULL,
				    &src_iovs[0], 1, NULL, NULL, 0,
				    ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	dst_iovs[1].iov_base = buf;
	dst_iovs[1].iov_len = sizeof(buf);
	src_iovs[1].iov_base = tmp[1];
	src_iovs[1].iov_len = compressed_size;
	rc = spdk_accel_append_decompress(&seq, ioch, &dst_iovs[1], 1, NULL, NULL,
					  &src_iovs[1], 1, NULL, NULL, 0,
					  ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	rc = spdk_accel_append_fill(&seq, ioch, buf, 2048, NULL, NULL, 0xfe, 0,
				    ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	ut_seq.complete = false;
	rc = spdk_accel_sequence_finish(seq, ut_sequence_complete_cb, &ut_seq);
	CU_ASSERT_EQUAL(rc, 0);

	poll_threads();

	CU_ASSERT_EQUAL(completed, 3);
	CU_ASSERT(ut_seq.complete);
	CU_ASSERT_EQUAL(ut_seq.status, 0);
	CU_ASSERT_EQUAL(memcmp(buf, expected, sizeof(buf)), 0);

	/* Check sequence with decompress at the beginning: decompress -> copy */
	memset(expected, 0xa5, sizeof(expected));
	memset(buf, 0, sizeof(buf));
	seq = NULL;
	completed = 0;

	dst_iovs[0].iov_base = tmp[1];
	dst_iovs[0].iov_len = sizeof(tmp[1]);
	src_iovs[0].iov_base = tmp[0];
	src_iovs[0].iov_len = compressed_size;
	rc = spdk_accel_append_decompress(&seq, ioch, &dst_iovs[0], 1, NULL, NULL,
					  &src_iovs[0], 1, NULL, NULL, 0,
					  ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	dst_iovs[1].iov_base = buf;
	dst_iovs[1].iov_len = sizeof(buf);
	src_iovs[1].iov_base = tmp[1];
	src_iovs[1].iov_len = sizeof(tmp[1]);
	rc = spdk_accel_append_copy(&seq, ioch, &dst_iovs[1], 1, NULL, NULL,
				    &src_iovs[1], 1, NULL, NULL, 0,
				    ut_sequence_step_cb, &completed);
	CU_ASSERT_EQUAL(rc, 0);

	ut_seq.complete = false;
	rc = spdk_accel_sequence_finish(seq, ut_sequence_complete_cb, &ut_seq);
	CU_ASSERT_EQUAL(rc, 0);

	poll_threads();

	CU_ASSERT_EQUAL(completed, 2);
	CU_ASSERT(ut_seq.complete);
	CU_ASSERT_EQUAL(ut_seq.status, 0);
	CU_ASSERT_EQUAL(memcmp(buf, expected, sizeof(buf)), 0);

	spdk_put_io_channel(ioch);
	poll_threads();
}
#endif

static int
test_sequence_setup(void)
{
@@ -1094,6 +1253,9 @@ main(int argc, char **argv)
	CU_ADD_TEST(seq_suite, test_sequence_abort);
	CU_ADD_TEST(seq_suite, test_sequence_append_error);
	CU_ADD_TEST(seq_suite, test_sequence_completion_error);
#ifdef SPDK_CONFIG_ISAL /* accel_sw requires isa-l for compression */
	CU_ADD_TEST(seq_suite, test_sequence_decompress);
#endif

	suite = CU_add_suite("accel", test_setup, test_cleanup);
	CU_ADD_TEST(suite, test_spdk_accel_task_complete);