Skip to main content

CpuExecutionContext

Struct CpuExecutionContext 

Source
pub struct CpuExecutionContext { /* private fields */ }
Expand description

Caller-owned CPU execution domain for plain, graph, and eager-AD work.

The context owns one CpuBackend and lends its engine to one caller at a time. A session entered from a Rayon worker runs inline on a fresh serial engine that shares the context engine’s prepared-plan cache instead of waiting for the context engine: a worker that waits for a pool install is handed more of the enclosing pool’s work, and that work may enter a session itself (tensor4all-rs#830). Graph preparation caches, the engine’s buffer pool and the eager runtime are owned by this context and are released when it is dropped.

§Examples

use tensor4all_tensorbackend::CpuExecutionContext;
use tensor4all_tensorbackend::CpuBackend;

let context = CpuExecutionContext::from_backend(CpuBackend::with_threads(1)?);
let threads = context.with_backend(|backend| backend.num_threads());
assert_eq!(threads, 1);

Implementations§

Source§

impl CpuExecutionContext

Source

pub fn from_backend(backend: CpuBackend) -> Self

Create an execution context from a caller-selected CPU backend.

Runtime construction is lazy, so creating a context cannot fail and does not allocate another executor or consult environment configuration.

Source

pub fn with_backend<R>(&self, f: impl FnOnce(&mut CpuBackend) -> R) -> R

Run a plain tensor operation with this context’s engine.

The closure runs while the context-local engine lock is held. A lock poisoned by a panic is recovered, and the engine is kept: it carries the caller’s pool, allocation domain, batch policy and runtime engine id, so a broken engine keeps refusing operations with tenferro’s typed CpuEngineError::Broken instead of being silently replaced by a default one. The caller builds a new context when it needs a new engine. The session entries recover the same way.

This borrows the engine for the whole closure, so a session entry from inside f on this thread is rejected with CpuExecutionContextError::Reentered instead of waiting for the engine. Calling with_backend from inside a session of this context is the caller’s obligation not to do: this entry cannot report an error, so it would wait for the engine the session already holds.

Source

pub fn with_session<R>( &self, f: impl FnOnce(&mut CpuEngine) -> R, ) -> Result<R, CpuExecutionContextError>

Run f in one session of this context’s engine.

This is the engine-borrow entry for callers that need the concrete engine (for example to hand it to an eager AD session). The context lends its engine to one caller at a time for the whole of f.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context.

§Examples
use tensor4all_tensorbackend::{CpuBackend, CpuExecutionContext};

let context = CpuExecutionContext::from_backend(CpuBackend::with_threads(1)?);
let threads = context.with_session(|engine| engine.num_threads())?;
assert_eq!(threads, 1);
Source

pub fn compile_graph( &self, graph: &TracedGraph, ) -> Result<CompiledGraph, CpuExecutionContextError>

Compile a backend-neutral traced graph using this context’s compiler cache.

§Errors

Returns CpuExecutionContextError::Graph when graph compilation fails.

Source

pub fn run_graph( &self, graph: &CompiledGraph, inputs: &[&Tensor], ) -> Result<Vec<Tensor>, CpuExecutionContextError>

Execute a compiled graph in this context’s runtime and prepared-plan cache.

CompiledGraph is backend-neutral. Backend-prepared executables and workspaces never leave this context-owned runtime.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context, and CpuExecutionContextError::Initialization, CpuExecutionContextError::Graph when runtime initialization, preparation, or execution fails.

Source

pub fn eager_runtime( &self, ) -> Result<Arc<EagerRuntime>, CpuExecutionContextError>

Return this context’s eager reverse-AD runtime.

The runtime is engine-independent: it is built once from an [AdContext] with the linalg AD rules and the einsum/linalg extension modules installed under this context engine’s runtime id, and every call takes the caller’s engine ([EagerRuntime::with_eager_session]). Repeated calls return the same runtime and therefore the same eager compilation cache. The runtime registers itself with the eager-runtime owner table once, when it is built.

§Errors

Returns CpuExecutionContextError when linalg AD-rule or eager-runtime registration fails.

Source

pub fn graph_cache_stats( &self, ) -> Result<RuntimeCacheStats, CpuExecutionContextError>

Return statistics for this context’s runtime-owned graph caches.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context, and CpuExecutionContextError when graph initialization or the cache statistics query fails.

Source

pub fn graph_buffer_pool_stats( &self, ) -> Result<BufferPoolStats, CpuExecutionContextError>

Return retained-buffer statistics for this context’s engine.

buffers counts the retained allocations and capacity_bytes their total element capacity. A context whose pool has just been released by Self::reset_graph_buffer_pool reports zero.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context.

§Examples
use tensor4all_tensorbackend::CpuExecutionContext;
use tenferro::program::{CoreSemanticOp, ProgramInputSpec};
use tenferro::{DType, Tensor, TraceContext};
use tensor4all_tensorbackend::CpuBackend;

let context = CpuExecutionContext::from_backend(CpuBackend::with_threads(1)?);

let mut trace = TraceContext::new();
let input = trace.input(ProgramInputSpec::new(DType::F64, [2_usize.into()]))?;
let output = trace.add_op(CoreSemanticOp::Neg, &[input])?[0];
let graph = trace.finish(&[output])?;
let compiled = context.compile_graph(&graph)?;
let values = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, -2.0])?;
let output = context.run_graph(&compiled, &[&values])?;
assert_eq!(output[0].as_slice::<f64>()?, &[-1.0, 2.0]);

// Releasing the pool empties it.
context.reset_graph_buffer_pool()?;
let after = context.graph_buffer_pool_stats()?;
assert_eq!(after.buffers, 0);
assert_eq!(after.capacity_bytes, 0);
Source

pub fn reset_graph_buffer_pool(&self) -> Result<(), CpuExecutionContextError>

Release retained buffers owned by this context’s engine.

The graph runtime, its compiled plans and its prepared-plan cache are kept, so callers can keep running previously compiled graphs afterwards.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context.

§Examples
use tensor4all_tensorbackend::CpuExecutionContext;
use tensor4all_tensorbackend::CpuBackend;

let context = CpuExecutionContext::from_backend(CpuBackend::with_threads(1)?);
context.reset_graph_buffer_pool()?;

// The pool retains nothing afterwards, and the runtime stays usable.
let stats = context.graph_buffer_pool_stats()?;
assert_eq!(stats.buffers, 0);
assert_eq!(stats.capacity_bytes, 0);
Source

pub fn reset_graph_runtime(&self) -> Result<(), CpuExecutionContextError>

Recreate this context’s graph runtime and release its prepared caches.

§Errors

Returns CpuExecutionContextError::Reentered when this thread is already inside a session of this context.

Source§

impl CpuExecutionContext

Source

pub fn with_concrete_session<R>( &self, f: impl FnOnce(&mut Session<'_>) -> R, ) -> Result<R, CpuExecutionContextError>

Run f inside one explicit concrete session of this context.

The context’s engine is borrowed once for the whole closure, so a stage borrows it once and reuses its prepared plans and buffer pool. All routes on the Session run on that engine only: nothing here consults the process-global default context, and nothing falls back to it.

§Examples
use tensor4all_tensorbackend::CpuExecutionContext;
use tenferro::Tensor;
use tensor4all_tensorbackend::CpuBackend;

let context = CpuExecutionContext::from_backend(CpuBackend::with_threads(1)?);
let x = Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 3.0])?;
let doubled = context.with_concrete_session(|session| session.reshape(&x, &[2]))??;
assert_eq!(doubled.as_slice::<f64>()?, &[1.0, 3.0]);
§Errors

Returns CpuExecutionContextError::Reentered when the calling thread is already inside a session of this context. A session entered from a Rayon worker runs inline on a serial engine that shares the context engine’s prepared-plan cache, so a worker entry completes instead of waiting for a pool it belongs to (tensor4all-rs#830).

§Panics

Never. A panic in f propagates after the engine borrow is released.

Source§

impl CpuExecutionContext

Source

pub fn reconstruct( &self, tensor: &LogicalTensor, ) -> Result<Tensor, LogicalTensorError>

Reconstruct a logical host tensor in this receiving execution domain.

The returned value carries only host tensor data. Its first plain, graph, or eager operation must use this same explicit context.

§Errors

Returns LogicalTensorError if tenferro rejects the validated shape or dtype payload.

Trait Implementations§

Source§

impl Debug for CpuExecutionContext

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> ByRef<T> for T

§

fn by_ref(&self) -> &T

§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

§

fn simd_from(_simd: S, value: T) -> T

§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

§

fn simd_into(self, simd: S) -> T

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V