blob: 9315dc6dbdfe3e4bec904ef4a85f7c89346e772f [file] [log] [blame]
// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef IREE_TASK_SUBMISSION_H_
#define IREE_TASK_SUBMISSION_H_
#include <stdbool.h>
#include "iree/base/api.h"
#include "iree/task/list.h"
#include "iree/task/task.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// A pending submission to a task queue made up of a DAG of tasks.
// Tasks are executed when ready in the order they were enqueued while observing
// all dependencies. This means that two tasks that have no dependencies may
// execute out of order/overlap.
//
// By keeping track of which tasks are ready for execution (ready_list) upon
// submission to a queue we avoid the need to walk the task list again and
// instead only touch the waiting tasks during construction and as they are made
// ready, avoiding needless work and cache thrashing.
//
// Waiting tasks (waiting_list) are those waiting on external dependencies such
// as file descriptor wait handles. Because we track all of these the executor
// can perform an efficient multi-wait across queues without needing to block
// (or even check) every waiting task individually.
//
// Because we only track roots of the DAG to release all tasks in a submission
// early (due to failure or shutdown) the DAG must be walked. Releasing just the
// lists will only handle the roots and leave all the rest of the tasks
// dangling.
//
// Thread-compatible; designed to be used from a single thread producing the
// submission.
typedef struct iree_task_submission_t {
// List of tasks that are ready for execution immediately. Upon submission to
// a queue the tasks will be passed on to the executor with no delay.
//
// Tasks are stored in LIFO order; this allows us to quickly concat them with
// incoming/mailbox slists that are naturally in LIFO order and that may
// contain tasks from prior submissions. Note that we are representing a
// ready list - meaning that all tasks are able to start simultaneously (in
// the best case where tasks <= workers); this means that the ordering
// requirements here are purely for performance and ease of debugging. In
// cases where tasks >> workers we could also see some benefits from the
// eventual FIFO order matching how the tasks were allocated.
iree_task_list_t ready_list;
// List of tasks that are waiting for execution on external dependencies.
// These are root tasks that have no internal task dependencies.
// Order is not important here; the assumption is that all waiting tasks are
// more of a set than an ordered list and that they can all be waited on as a
// multi-wait-any.
iree_task_list_t waiting_list;
} iree_task_submission_t;
// Initializes a task submission.
void iree_task_submission_initialize(iree_task_submission_t* out_submission);
// Flushes the given |ready_slist| and initializes the submission with all tasks
// to the submission in LIFO order. All tasks in |ready_slist| are assumed to be
// ready for execution immediately.
void iree_task_submission_initialize_from_lifo_slist(
iree_atomic_task_slist_t* ready_slist,
iree_task_submission_t* out_submission);
// Resets the submission by dropping the list references.
void iree_task_submission_reset(iree_task_submission_t* submission);
// Discards all pending tasks in the submission. This is only safe to call if
// the submission has not yet been submitted to a queue for execution and should
// be used for failure cleanup during submission construction.
void iree_task_submission_discard(iree_task_submission_t* submission);
// Returns true if the submission has no tasks.
bool iree_task_submission_is_empty(iree_task_submission_t* submission);
// Enqueues |task| to the pending |submission|.
// The task will be checked to see whether it is immediately ready to execute
// and placed in an appropriate list; all dependencies must be declared prior to
// calling this method. After returning new tasks that depend on this task may
// still be defined. The submission takes ownership of the |task|.
void iree_task_submission_enqueue(iree_task_submission_t* submission,
iree_task_t* task);
// Enqueues all tasks in |list| to the pending |submission|.
// Ownership of the tasks transfers to the submission and the |list| will be
// reset upon return. Ready tasks may execute in any order.
void iree_task_submission_enqueue_list(iree_task_submission_t* submission,
iree_task_list_t* list);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // IREE_TASK_SUBMISSION_H_