Foundation
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
Foundation::Core::JobGraph Class Reference

A small, transient CPU job graph layered on top of ThreadPool. More...

#include <JobGraph.hpp>

Classes

struct  IJobWork
 
struct  IndexWork
 
struct  Node
 
struct  ParallelForJob
 
struct  SingleWork
 
struct  WorkerJob
 

Public Types

enum class  NodeKind { Worker , ParallelFor , Main , Barrier }
 

Public Member Functions

 JobGraph (ThreadPool &pool, Allocator *allocator)
 
 JobGraph (JobGraph const &)=delete
 
JobGraphoperator= (JobGraph const &)=delete
 
 ~JobGraph ()
 
template<typename Fn >
JobHandle AddJob (StringView name, ExecutionPolicy policy, Fn &&fn)
 A single body that runs once on a pool worker (or the main thread under Seq / no workers).
 
template<typename Fn >
JobHandle AddMain (StringView name, Fn &&fn)
 A single body that always runs on the thread calling Wait / PumpMainThread.
 
template<typename Fn >
JobHandle AddParallelFor (StringView name, ExecutionPolicy policy, size_t count, Fn &&fn)
 Index parallel-for body invoked as fn(i) or fn(i, workerId) for each index.
 
template<typename It , typename Fn >
requires std::random_access_iterator<It>
JobHandle AddParallelFor (StringView name, ExecutionPolicy policy, It first, It last, Fn &&fn)
 Iterator-range parallel-for (random-access iterators), like the ThreadPool overload.
 
JobHandle AddBarrier (StringView name)
 A work-less join node that completes once all its producers complete.
 
template<typename... Producers>
void DependsOn (JobHandle consumer, Producers... producers)
 Declares that consumer may only run after every producers has completed.
 
void Submit ()
 Arms the graph and schedules all dependency-free nodes. Call exactly once.
 
void Wait (JobHandle target)
 Runs ready main-thread nodes on the caller, then blocks until target completes.
 
void Wait ()
 Blocks until the whole graph completes (pumping main-thread nodes on the caller).
 
void PumpMainThread ()
 Runs every currently-ready main-thread node on the caller without blocking.
 
size_t MainWorkerId () const noexcept
 Worker id handed to main-thread node bodies (== ThreadPool::GetWorkerCount).
 

Private Member Functions

size_t AddNode (NodeKind kind, StringView name, UniquePtr< IJobWork > work, size_t total, ExecutionPolicy policy)
 
void AddEdge (size_t producer, size_t consumer)
 
void Schedule (size_t id)
 
void DispatchWorker (size_t id)
 
void DispatchParallelFor (size_t id)
 
void EnqueueMain (size_t id)
 
void RunMainNode (size_t id)
 
void OnNodeFinished (size_t id)
 

Private Attributes

ThreadPoolmPool
 
AllocatormAllocator
 
Vector< UniquePtr< Node > > mNodes
 
Mutex mMutex
 
CondVar mCond
 
Queue< size_t > mMainReady
 
size_t mNodesRemaining {0}
 
size_t mMainWorkerId {0}
 
bool mSubmitted {false}
 

Detailed Description

A small, transient CPU job graph layered on top of ThreadPool.

The pool stays a flat worker executor; JobGraph adds first-class dependency handles so a caller can express a frame's CPU work as nodes + edges instead of hand-placed futures. A node becomes schedulable once all of its producers complete:

Build (single-threaded) -> Submit -> do other work -> Wait. The graph object must outlive its in-flight work; Wait (and the destructor) block until it drains.

Note
Worker ids handed to node bodies follow the pool's contract: pool workers see ids in [0, ThreadPool::GetWorkerCount); main-thread nodes see MainWorkerId() (== worker count), matching ThreadPool::GetParallelForConcurrency so per-worker scratch sized to that concurrency stays race-free.
Scope is intentionally small: no cancellation, no result values, no persistent/nested graphs. Build a fresh graph per logical batch.

Member Enumeration Documentation

◆ NodeKind

Enumerator
Worker 
ParallelFor 
Main 
Barrier 

Constructor & Destructor Documentation

◆ JobGraph() [1/2]

Foundation::Core::JobGraph::JobGraph ( ThreadPool pool,
Allocator allocator 
)

◆ JobGraph() [2/2]

Foundation::Core::JobGraph::JobGraph ( JobGraph const &  )
delete

◆ ~JobGraph()

Foundation::Core::JobGraph::~JobGraph ( )

Member Function Documentation

◆ AddBarrier()

JobHandle Foundation::Core::JobGraph::AddBarrier ( StringView  name)

A work-less join node that completes once all its producers complete.

◆ AddEdge()

void Foundation::Core::JobGraph::AddEdge ( size_t  producer,
size_t  consumer 
)
private

◆ AddJob()

template<typename Fn >
JobHandle Foundation::Core::JobGraph::AddJob ( StringView  name,
ExecutionPolicy  policy,
Fn &&  fn 
)
inline

A single body that runs once on a pool worker (or the main thread under Seq / no workers).

◆ AddMain()

template<typename Fn >
JobHandle Foundation::Core::JobGraph::AddMain ( StringView  name,
Fn &&  fn 
)
inline

A single body that always runs on the thread calling Wait / PumpMainThread.

◆ AddNode()

size_t Foundation::Core::JobGraph::AddNode ( NodeKind  kind,
StringView  name,
UniquePtr< IJobWork work,
size_t  total,
ExecutionPolicy  policy 
)
private

◆ AddParallelFor() [1/2]

template<typename It , typename Fn >
requires std::random_access_iterator<It>
JobHandle Foundation::Core::JobGraph::AddParallelFor ( StringView  name,
ExecutionPolicy  policy,
It  first,
It  last,
Fn &&  fn 
)
inline

Iterator-range parallel-for (random-access iterators), like the ThreadPool overload.

◆ AddParallelFor() [2/2]

template<typename Fn >
JobHandle Foundation::Core::JobGraph::AddParallelFor ( StringView  name,
ExecutionPolicy  policy,
size_t  count,
Fn &&  fn 
)
inline

Index parallel-for body invoked as fn(i) or fn(i, workerId) for each index.

◆ DependsOn()

template<typename... Producers>
void Foundation::Core::JobGraph::DependsOn ( JobHandle  consumer,
Producers...  producers 
)
inline

Declares that consumer may only run after every producers has completed.

Note
Build-time only (before Submit). Edges are not deduplicated.

◆ DispatchParallelFor()

void Foundation::Core::JobGraph::DispatchParallelFor ( size_t  id)
private

◆ DispatchWorker()

void Foundation::Core::JobGraph::DispatchWorker ( size_t  id)
private

◆ EnqueueMain()

void Foundation::Core::JobGraph::EnqueueMain ( size_t  id)
private

◆ MainWorkerId()

size_t Foundation::Core::JobGraph::MainWorkerId ( ) const
inlinenoexcept

Worker id handed to main-thread node bodies (== ThreadPool::GetWorkerCount).

◆ OnNodeFinished()

void Foundation::Core::JobGraph::OnNodeFinished ( size_t  id)
private

◆ operator=()

JobGraph & Foundation::Core::JobGraph::operator= ( JobGraph const &  )
delete

◆ PumpMainThread()

void Foundation::Core::JobGraph::PumpMainThread ( )

Runs every currently-ready main-thread node on the caller without blocking.

◆ RunMainNode()

void Foundation::Core::JobGraph::RunMainNode ( size_t  id)
private

◆ Schedule()

void Foundation::Core::JobGraph::Schedule ( size_t  id)
private

◆ Submit()

void Foundation::Core::JobGraph::Submit ( )

Arms the graph and schedules all dependency-free nodes. Call exactly once.

◆ Wait() [1/2]

void Foundation::Core::JobGraph::Wait ( )
inline

Blocks until the whole graph completes (pumping main-thread nodes on the caller).

◆ Wait() [2/2]

void Foundation::Core::JobGraph::Wait ( JobHandle  target)

Runs ready main-thread nodes on the caller, then blocks until target completes.

Member Data Documentation

◆ mAllocator

Allocator* Foundation::Core::JobGraph::mAllocator
private

◆ mCond

CondVar Foundation::Core::JobGraph::mCond
private

◆ mMainReady

Queue<size_t> Foundation::Core::JobGraph::mMainReady
private

◆ mMainWorkerId

size_t Foundation::Core::JobGraph::mMainWorkerId {0}
private

◆ mMutex

Mutex Foundation::Core::JobGraph::mMutex
private

◆ mNodes

Vector<UniquePtr<Node> > Foundation::Core::JobGraph::mNodes
private

◆ mNodesRemaining

size_t Foundation::Core::JobGraph::mNodesRemaining {0}
private

◆ mPool

ThreadPool& Foundation::Core::JobGraph::mPool
private

◆ mSubmitted

bool Foundation::Core::JobGraph::mSubmitted {false}
private

The documentation for this class was generated from the following files: