Commit 6f5ba1bd authored by Tomasz Zawadzki's avatar Tomasz Zawadzki
Browse files

accel/dsa: separate task submission from queued tasks



DSA can queue up submitted accel task when spdk_idxd_submit_*()
fails with EBUSY, for example when there are no more free
batches on the channel.

After idxd_poll() processes currently outstanding commands,
queued tasks are then proceeded using the same function as
any new task (dsa_submit_tasks()).
The issue is with the queue_tasks label in dsa_submit_tasks(),
when not all entries from the queued_tasks list can be submitted.
Loop there basically rewrites whole queued_tasks list one by one.
With large enough queue depth a considerable portion of time
was spent rewriting that list.

This might have been an omission or was done to consolidate
single task and queued task submission in single function.

To address this, both cases are now separate. Simplifying
single task submission. Meanwhile queued tasks are removed
from list as they are submitted. This way avoiding
rewriting the list.

Signed-off-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Change-Id: I9162fe01c2d4ee406cf9eb5ec361c6bfd573c831
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/21186


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Mellanox Build Bot
parent 59ed0fd8
Loading
Loading
Loading
Loading
+40 −43
Original line number Diff line number Diff line
@@ -191,53 +191,60 @@ _process_single_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
}

static int
dsa_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *first_task)
dsa_submit_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
{
	struct idxd_io_channel *chan = spdk_io_channel_get_ctx(ch);
	struct spdk_accel_task *task, *tmp;
	int rc = 0;

	task = first_task;
	assert(TAILQ_NEXT(task, link) == NULL);

	if (chan->state == IDXD_CHANNEL_ERROR) {
		while (task) {
			tmp = TAILQ_NEXT(task, link);
	if (spdk_unlikely(chan->state == IDXD_CHANNEL_ERROR)) {
		spdk_accel_task_complete(task, -EINVAL);
			task = tmp;
		}
		return 0;
	}

	if (!TAILQ_EMPTY(&chan->queued_tasks)) {
		goto queue_tasks;
		TAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
		return 0;
	}

	/* The caller will either submit a single task or a group of tasks that are
	 * linked together but they cannot be on a list. For example, see idxd_poll()
	 * where a list of queued tasks is being resubmitted, the list they are on
	 * is initialized after saving off the first task from the list which is then
	 * passed in here.  Similar thing is done in the accel framework.
	 */
	while (task) {
		tmp = TAILQ_NEXT(task, link);
	rc = _process_single_task(ch, task);

	if (rc == -EBUSY) {
			goto queue_tasks;
		TAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
	} else if (rc) {
		spdk_accel_task_complete(task, rc);
	}
		task = tmp;

	return 0;
}

static int
dsa_submit_queued_tasks(struct idxd_io_channel *chan)
{
	struct spdk_accel_task *task, *tmp;
	struct spdk_io_channel *ch = spdk_io_channel_from_ctx(chan);
	int rc = 0;

	if (spdk_unlikely(chan->state == IDXD_CHANNEL_ERROR)) {
		/* Complete queued tasks with error and clear the list */
		while ((task = TAILQ_FIRST(&chan->queued_tasks))) {
			TAILQ_REMOVE(&chan->queued_tasks, task, link);
			spdk_accel_task_complete(task, -EINVAL);
		}
		return 0;
	}

queue_tasks:
	while (task != NULL) {
		tmp = TAILQ_NEXT(task, link);
		TAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
		task = tmp;
	TAILQ_FOREACH_SAFE(task, &chan->queued_tasks, link, tmp) {
		rc = _process_single_task(ch, task);
		if (rc == -EBUSY) {
			return rc;
		}
		TAILQ_REMOVE(&chan->queued_tasks, task, link);
		if (rc) {
			spdk_accel_task_complete(task, rc);
		}
	}

	return 0;
}

@@ -245,23 +252,13 @@ static int
idxd_poll(void *arg)
{
	struct idxd_io_channel *chan = arg;
	struct spdk_accel_task *task = NULL;
	struct idxd_task *idxd_task;
	int count;

	count = spdk_idxd_process_events(chan->chan);

	/* Check if there are any pending ops to process if the channel is active */
	if (chan->state == IDXD_CHANNEL_ACTIVE) {
		/* Submit queued tasks */
	if (!TAILQ_EMPTY(&chan->queued_tasks)) {
			task = TAILQ_FIRST(&chan->queued_tasks);
			idxd_task = SPDK_CONTAINEROF(task, struct idxd_task, task);

			TAILQ_INIT(&chan->queued_tasks);

			dsa_submit_tasks(spdk_io_channel_from_ctx(idxd_task->chan), task);
		}
		dsa_submit_queued_tasks(chan);
	}

	return count > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
@@ -306,7 +303,7 @@ static struct spdk_accel_module_if g_dsa_module = {
	.name			= "dsa",
	.supports_opcode	= dsa_supports_opcode,
	.get_io_channel		= dsa_get_io_channel,
	.submit_tasks		= dsa_submit_tasks
	.submit_tasks		= dsa_submit_task
};

static int