#[non_exhaustive]pub enum Exec<'a> {
Serial {
policy: BatchPolicy,
},
SerialWithWorkspace {
workspace: &'a dyn WorkspaceProvider,
policy: BatchPolicy,
},
Rayon {
pool: &'a Pool<'a>,
budget: NonZeroUsize,
policy: BatchPolicy,
},
}Expand description
Execution context passed to every operation that may run in parallel.
§Examples
use tcontract_exec::Exec;
assert_eq!(Exec::serial().budget(), 1);
assert!(!Exec::serial().is_worker());Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Serial
Everything on the calling thread, with call-local scratch. Carries the batch policy so a forced strategy is still resolved at one thread.
Fields
policy: BatchPolicyThe batch lane policy this context applies.
SerialWithWorkspace
Everything on the calling thread, with caller-owned reusable scratch.
Fields
workspace: &'a dyn WorkspaceProviderThe caller-owned storage.
policy: BatchPolicyThe batch lane policy this context applies.
Rayon
A borrowed pool with a thread budget <= pool.size().
Fields
budget: NonZeroUsizeMost threads an operation may occupy.
policy: BatchPolicyThe batch lane policy this context applies.
Implementations§
Source§impl<'a> Exec<'a>
impl<'a> Exec<'a>
Sourcepub fn serial_with_workspace(workspace: &'a dyn WorkspaceProvider) -> Self
pub fn serial_with_workspace(workspace: &'a dyn WorkspaceProvider) -> Self
Serial execution with caller-owned reusable storage.
Sourcepub fn rayon(pool: &'a Pool<'a>) -> Self
pub fn rayon(pool: &'a Pool<'a>) -> Self
Use pool with its full size as budget and the default batch policy.
Sourcepub fn with_budget(self, max_threads: usize) -> Result<Self, ExecError>
pub fn with_budget(self, max_threads: usize) -> Result<Self, ExecError>
Limit the budget; values above the pool size are clamped.
§Errors
ExecError::ZeroBudget when max_threads == 0.
§Examples
use tcontract_exec::{Exec, ExecError};
assert_eq!(Exec::serial().with_budget(0).unwrap_err(), ExecError::ZeroBudget);Sourcepub fn batch_policy(&self) -> &BatchPolicy
pub fn batch_policy(&self) -> &BatchPolicy
The batch lane policy this context applies.
A serial context has one thread but still carries a policy, so a forced strategy is resolved (and can be refused) at one thread as well.
§Examples
use tcontract_exec::{BatchPolicy, BatchStrategy, Exec};
assert_eq!(Exec::serial().batch_policy().strategy, BatchStrategy::Auto);
let tp = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
let pool = tcontract_exec::Pool::borrow(&tp);
let exec = Exec::rayon(&pool).with_batch_policy(BatchPolicy::new(BatchStrategy::Outer));
assert_eq!(exec.batch_policy().strategy, BatchStrategy::Outer);Sourcepub fn with_batch_policy(self, policy: BatchPolicy) -> Self
pub fn with_batch_policy(self, policy: BatchPolicy) -> Self
Return this context with a different batch lane policy.
A serial context has one thread, so the policy cannot change its lane
count, but it is preserved: a forced
BatchStrategy::WholeBatchVendor
is still refused at one thread instead of silently running Auto.
§Examples
use tcontract_exec::{BatchPolicy, BatchStrategy, Exec};
let exec = Exec::serial().with_batch_policy(BatchPolicy::new(BatchStrategy::Outer));
assert_eq!(exec.batch_policy().strategy, BatchStrategy::Outer);Sourcepub fn batch_decision(
&self,
query: &BatchQuery,
) -> Result<BatchDecision, ExecError>
pub fn batch_decision( &self, query: &BatchQuery, ) -> Result<BatchDecision, ExecError>
Decide the batch route for query on this context’s budget and policy.
This is the one decision function every operation that owns batch lanes
calls; see crate::batch. It resolves availability before the caller
writes anything.
§Errors
ExecError::StrategyUnavailable for a forced
BatchStrategy::WholeBatchVendor
on a query without a vendor batch route.
§Examples
use tcontract_exec::{BatchQuery, Exec};
let d = Exec::serial().batch_decision(&BatchQuery::new(4, 1000.0)).unwrap();
assert_eq!((d.lanes, d.item_threads), (1, 1));Sourcepub fn workspace(&self) -> Option<&'a dyn WorkspaceProvider>
pub fn workspace(&self) -> Option<&'a dyn WorkspaceProvider>
Storage the operations on this context may share, or none.
A pool lends its own arena to every operation that runs on it; a serial
context owns nothing, so a caller that wants reuse keeps a provider of
its own and lends it through Exec::serial_with_workspace.
Sourcepub fn install<R: Send>(&self, k: usize, op: impl FnOnce(Par) -> R + Send) -> R
pub fn install<R: Send>(&self, k: usize, op: impl FnOnce(Par) -> R + Send) -> R
Run op with min(k, budget) threads of parallelism.
Width one runs op(Par::Seq) inline on the caller. Otherwise op
runs inside the pool, which is entered once, or in place when the
caller is already one of its workers.
Sourcepub fn for_each_partition(&self, k: usize, f: &(dyn Fn(usize) + Sync))
pub fn for_each_partition(&self, k: usize, f: &(dyn Fn(usize) + Sync))
Barrier-free partition: runs f(i) exactly once for each i < k,
on at most budget workers in contiguous lanes.
Tasks are not guaranteed to run concurrently, so f must never wait
on another index.
§Examples
use std::sync::atomic::{AtomicUsize, Ordering};
let n = AtomicUsize::new(0);
tcontract_exec::Exec::serial().for_each_partition(5, &|_| {
n.fetch_add(1, Ordering::Relaxed);
});
assert_eq!(n.into_inner(), 5);Sourcepub fn broadcast(
&self,
width: usize,
f: &(dyn Fn(usize) + Sync),
) -> Result<(), ExecError>
pub fn broadcast( &self, width: usize, f: &(dyn Fn(usize) + Sync), ) -> Result<(), ExecError>
Co-scheduled SPMD execution: f(t) for every t < width runs
concurrently on distinct workers, so f may use barriers counting
width participants.
Width one runs f(0) inline. On a pool the whole pool is dispatched
(Rayon broadcast); workers with index >= width return at once.
Broadcasts through one Pool wrapper are serialized (use one
wrapper per ThreadPool). A broadcast waits until every worker reaches
a scheduling point, so a worker busy in another host’s long job delays
it. A panic in a barrier-free f propagates to the caller after every
participant has finished; if f panics before a barrier the other
participants wait at it forever, so barrier-bearing f must not panic.
§Errors
ExecError::Unavailable when co-scheduling cannot be guaranteed
(Serial with width > 1, or the caller is already a worker of the
pool, where an outer job may hold workers at a barrier); nothing runs
then, and the caller uses its barrier-free variant.
ExecError::WidthExceedsPool when width exceeds the pool, and
ExecError::WidthExceedsBudget when it exceeds the budget (the
active width is capped by the budget even though the whole pool is
dispatched).
§Examples
use tcontract_exec::{Exec, ExecError};
assert_eq!(Exec::serial().broadcast(2, &|_| {}), Err(ExecError::Unavailable));Sourcepub fn width_for(&self, serial_ns: f64, policy: &WidthPolicy) -> usize
pub fn width_for(&self, serial_ns: f64, policy: &WidthPolicy) -> usize
Partition width for work estimated at serial_ns on one thread,
minimizing the WidthPolicy cost model within the budget.
§Examples
use tcontract_exec::{Exec, WidthPolicy};
assert_eq!(Exec::serial().width_for(1e9, &WidthPolicy::default()), 1);Trait Implementations§
Auto Trait Implementations§
impl<'a> !RefUnwindSafe for Exec<'a>
impl<'a> !UnwindSafe for Exec<'a>
impl<'a> Freeze for Exec<'a>
impl<'a> Send for Exec<'a>
impl<'a> Sync for Exec<'a>
impl<'a> Unpin for Exec<'a>
impl<'a> UnsafeUnpin for Exec<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more