86 std::uint8_t num_user_threads = 0;
87 std::uint8_t num_threads = 0;
88 std::uint16_t main_queue_size = 256;
89 std::uint16_t normal_queue_size = 1024;
90 std::uint16_t worker_queue_size = 32;
91 std::uint64_t job_steal_rng_seed = 0u;
123 void Initialize(
const JobSystemMemoryRequirements& memory_requirements = {},
void*
const memory =
nullptr)
noexcept;
289 template<typename T, typename... Args>
337 template<typename Closure>
395 template<typename ConditionFn>
404 }
while (condition());
482 return data.
size >=
sizeof(T) ?
static_cast<T*
>(data.
ptr) :
nullptr;
485 template<
typename T,
typename... Args>
490 JobAssert(data.
size >=
sizeof(T),
"Attempting to store an object too large to fit within a task's storage buffer.");
492 new (data.
ptr) T(std::forward<Args>(args)...);
498 TaskEmplaceData<T>(
task, data);
504 TaskDataAs<T>(
task)->~T();
507 template<
typename Closure>
518 ::new (private_data) Closure(std::forward<Closure>(
function));
548 static Splitter EvenSplit(
const std::size_t total_num_items, std::size_t num_groups_per_thread = 1u)
550 if (num_groups_per_thread < 1u)
552 num_groups_per_thread = 1u;
566 return Splitter{max_data_size /
sizeof(T)};
606 template<
typename F,
typename S>
607 Task*
ParallelFor(
const std::size_t start,
const std::size_t count, S&& splitter, F&& fn,
Task* parent =
nullptr)
610 [=, splitter = std::move(splitter), fn = std::move(fn)](
Task*
const task) {
611 if (count > 1u && splitter(count))
613 const std::size_t left_count = count / 2;
614 const std::size_t right_count = count - left_count;
622 for (std::size_t offset = 0u; offset < count; ++offset)
624 fn(
task, start + offset);
631 template<
typename Splitter,
typename Reducer>
635 [=, splitter = std::move(splitter), reduce = std::move(reduce)](
Task*
const task) {
643 std::size_t count_left = count;
644 while (count_left > 1)
646 const std::size_t stride = count_left / 2;
648 const auto ReduceRange = [stride, &reduce](
Task*
const sub_task,
const std::size_t index) {
649 reduce(sub_task, index, index + stride);
654 if ((count_left & 1) != 0)
656 reduce(
task, start, start + count_left - 1);
700 template<
typename T,
typename F,
typename S>
704 std::size_t(0), count, std::move(splitter), [data, fn = std::move(fn)](
Task*
const task,
const std::size_t index) {
705 fn(
task, data + index);
727 template<
typename... F>
731 [=](
Task*
const parent_task)
mutable {
Assertion macro for this library.
#define JobAssert(expr, msg)
void * taskReservePrivateUserData(Task *const task, const std::size_t num_bytes, const std::size_t alignment) noexcept
void * taskGetPrivateUserData(Task *const task, const std::size_t alignment) noexcept
QueueType taskQType(const Task *task) noexcept
bool mainQueueTryRunTask(void) noexcept
TaskData TaskGetData(Task *const task, const std::size_t alignment) noexcept
Returns you the user-data buffer you way write to get data into your TaskFn.
std::size_t size
The size of the buffer.
void * ptr
The start of the buffer you may write to.
void TaskSubmitAndWait(Task *const self, const QueueType queue=QueueType::NORMAL) noexcept
Same as calling taskSubmit followed by waitOnTask.
void WaitOnTask(const Task *const task) noexcept
Waits until the specified task is done executing. This function will block but do work while being bl...
void(*)(Task *) TaskFn
The signature of the type of function for a single Task.
T * TaskDataAs(Task *const task) noexcept
Grabs the user-data pointer as the T you specified. No safety is guaranteed, this is just a dumb cast...
void TaskAddContinuation(Task *const self, Task *const continuation, const QueueType queue=QueueType::NORMAL) noexcept
A 'continuation' is a task that will be added to a queue after the 'self' Task has finished running.
Task * ParallelInvoke(Task *const parent, F &&... fns)
Invokes each passed in function object in parallel.
void YieldTimeSlice() noexcept
Asks the OS to yield this threads execution to another thread on the current cpu core.
std::uint16_t NumWorkers() noexcept
Returns the number of workers created by the system. This function can be called by any thread concur...
QueueType
Determines which threads the task will be allowed to run on.
@ MAIN
Tasks in this queue will only be run by the main thread.
@ NORMAL
Tasks in this queue will run on either the main or worker threads.
@ WORKER
Tasks in this queue will never run on the main thread.
Task * TaskMake(const TaskFn function, Task *const parent=nullptr) noexcept
Creates a new Task that should be later submitted by calling 'TaskSubmit'.
const char * ProcessorArchitectureName() noexcept
An implementation defined name for the CPU architecture of the device. This function can be called by...
void TaskSetData(Task *const task, const T &data)
Copies 'data' into the user-data buffer by calling the T copy constructor.
void SetupUserThread()
Must be called in the callstack of the thread to be setup.
void Shutdown() noexcept
This will deallocate any memory used by the system and shutdown any threads created by 'bfJob::initia...
Task * ParallelFor(const std::size_t start, const std::size_t count, S &&splitter, F &&fn, Task *parent=nullptr)
Parallel for algorithm, splits the work up recursively splitting based on the splitter passed in.
void TaskEmplaceData(Task *const task, Args &&... args)
Calls the constructor of T on the user-data buffer.
WorkerID CurrentWorker() noexcept
The current id of the current thread. This function can be called by any thread concurrently.
void TaskIncRef(Task *const task) noexcept
Increments the task's ref count preventing it from being garbage collected.
std::uint16_t WorkerID
The id type of each worker thread.
bool IsMainThread() noexcept
Allows for querying if we are currently executing in the main thread.
void PauseProcessor() noexcept
CPU pause instruction to indicate when you are in a spin wait loop.
void TaskDecRef(Task *const task) noexcept
Decrements the task's ref count allow it to be garbage collected.
void TickMainQueue(ConditionFn &&condition) noexcept
Runs tasks from the main queue as long as there are tasks available and condition returns true.
std::size_t NumSystemThreads() noexcept
Makes some system calls to grab the number threads / processors on the device. This function can be c...
void Initialize(const JobSystemMemoryRequirements &memory_requirements={}, void *const memory=nullptr) noexcept
Sets up the Job system and creates all the worker threads. The thread that calls 'Job::Initialize' is...
void TaskSubmit(Task *const self, const QueueType queue=QueueType::NORMAL) noexcept
Submits the task to the specified queue.
void TaskDestructData(Task *const task)
Helper for calling destructor on the task's user data.
Task * ParallelReduce(const std::size_t start, const std::size_t count, Splitter &&splitter, Reducer &&reduce, Task *parent=nullptr)
bool TaskIsDone(const Task *const task) noexcept
Returns the done status of the task.
The runtime configuration for the Job System.
A buffer for user-data you can write to, maybe large enough to store task data inline.
The memory requirements for a given configuration JobSystemCreateOptions.
JobSystemMemoryRequirements(const JobSystemCreateOptions &options={}) noexcept
std::size_t alignment
The base alignment the pointer should be.
std::size_t byte_size
The number of bytes the job system needed.
JobSystemCreateOptions options
The options used to create the memory requirements.
static Splitter EvenSplit(const std::size_t total_num_items, std::size_t num_groups_per_thread=1u)
Splits work evenly across the threads depending on the number of workers.
static constexpr Splitter MaxDataSize(const std::size_t max_data_size)
constexpr bool operator()(const std::size_t count) const
static constexpr Splitter MaxItemsPerTask(const std::size_t max_items)