pub struct EngineConfig {
pub max_memory_bytes: usize,
pub epoch_tick: Duration,
pub strategy: Strategy,
pub component_model: bool,
pub backend: MemoryBackend,
pub max_module_cache_entries: usize,
pub max_instances: Option<usize>,
pub max_module_bytes: usize,
pub max_concurrent_compiles: Option<usize>,
pub auto_offload: bool,
pub auto_offload_detector: Option<DetectorConfig>,
pub max_instances_per_tenant: Option<usize>,
}Expand description
Configuration knobs for the engine.
Fields§
§max_memory_bytes: usizeMaximum allocated linear memory per instance (bytes).
epoch_tick: DurationPeriod between background increment_epoch ticks.
strategy: StrategyCompilation strategy. Strategy::Cranelift for production.
component_model: boolEnable Wasm component model.
backend: MemoryBackendLinear-memory backing strategy. See MemoryBackend for the
UnifiedBuffer vs PoolingMpk trade-off.
max_module_cache_entries: usizeMaximum number of compiled-module cache entries retained per
executor before LRU eviction kicks in. Closes exec S-5: an
unbounded DashMap<digest, Module> lets a misbehaving tenant
pin arbitrarily many compiled modules (each multi-MiB of host
RAM) by submitting unique wasm bytes in a loop. 1024 is enough
to hold the working set of a typical multi-tenant deployment
while bounding the worst case at ~a few GiB of compiled-code
pages.
max_instances: Option<usize>Hard upper bound on the number of concurrently-live instances
the executor will admit. Closes exec S-10: an unbounded
DashMap<InstanceId, ...> lets a tenant spawn instances in a
loop until the host OOMs. None disables the cap (useful for
tests / single-tenant deployments); production callers should
keep the default ceiling. When the limit is hit spawn_instance
returns crate::executor::ExecError::CapacityExhausted.
max_module_bytes: usizePre-compile cap on the byte length of a submitted Wasm module.
Bytes above this are rejected with
crate::executor::ExecError::ModuleTooLarge before
Module::from_binary runs, preventing pathological code
sections from forcing Cranelift to burn arbitrary CPU on
adversarial input. Default is
crate::executor::MAX_MODULE_BYTES (64 MiB); embedders may
tighten further but the constant is the documented floor.
max_concurrent_compiles: Option<usize>Upper bound on the number of Module::from_binary (Cranelift)
compiles allowed to run concurrently on the Tokio blocking pool.
Each compile is offloaded via tokio::task::spawn_blocking; the
blocking pool is a shared process resource (default 512 threads).
Without a bound, an adversary submitting a stream of unique large
modules — each a cache miss, each a multi-hundred-millisecond
Cranelift run — can saturate the pool and starve every other
blocking operation in the process. This cap is independent of
Self::max_instances (which bounds live instances, not in-flight
compiles) and is enforced by a per-executor
tokio::sync::Semaphore. None selects a default derived from
std::thread::available_parallelism (floored at 1) at executor
construction time.
auto_offload: boolOpt-in: activate the auto-offload Wasm rewrite on the spawn path.
When false (the default) the
auto_offload::analyse pass remains
consultation-only — it emits tracing verdicts but Wasmtime’s
Cranelift output is never replaced, exactly matching the historical
behaviour. When true,
TensorWasmExecutor::spawn_instance
runs the analyser and, if any function is flagged for offload, feeds
the module through
tensor_wasm_jit::rewrite::rewrite_wasm to produce a
trampoline-augmented module which is instantiated instead of the
original. The original bytes are always retained as a fallback: any
analysis or rewrite failure (or a rewrite that swaps nothing) is
logged and the spawn proceeds with the unmodified module, so enabling
this flag can never fail a spawn that would otherwise have succeeded.
Requires a KernelCache
attached to the executor via
TensorWasmExecutor::with_jit_cache
for the rewritten guest’s tensor-wasm:jit/host imports to link;
without one, the rewrite is skipped (the trampoline imports would be
unlinkable) and the original module is used.
auto_offload_detector: Option<DetectorConfig>Detector thresholds the auto-offload activation path uses to decide which function bodies are offload candidates.
None (the default) selects
tensor_wasm_jit::detector::DetectorConfig::default — the
production-conservative thresholds. Embedders (and tests) that want a
more aggressive offload policy can supply tuned thresholds here; the
same config is threaded into BOTH the consultation pass
(auto_offload::analyse_with_config)
and the
tensor_wasm_jit::rewrite::RewriteOptions::detector used for the
rewrite, so the consultation verdict and the rewrite always agree on
which functions to swap. Ignored entirely when
Self::auto_offload is false.
max_instances_per_tenant: Option<usize>Optional per-tenant cap on the number of concurrently-live instances
a single TenantId may hold.
Complements the engine-wide Self::max_instances ceiling with a
fairness bound: one tenant spawning in a loop cannot starve every
other tenant of the shared instance budget. Enforced in the same
admission path as max_instances (keyed by the spawning
SpawnConfig::tenant_id),
with the same charge-before-compile / roll-back-on-failure
accounting. When a tenant exceeds its cap the spawn is refused with
ExecError::CapacityExhausted
(reused for the per-tenant case to keep the cross-crate error mapping
non-breaking; the offending tenant is logged server-side) carrying the
tenant’s own count and per-tenant limit, without affecting any other
tenant. None (the default) disables the per-tenant cap — only the
engine-wide max_instances applies.
Implementations§
Source§impl EngineConfig
impl EngineConfig
Sourcepub fn effective_memory_cap(&self) -> usize
pub fn effective_memory_cap(&self) -> usize
The effective per-instance linear-memory cap, in bytes, reconciling
the engine-wide Self::max_memory_bytes ceiling with the pooling
allocator’s own per-slot byte size when
MemoryBackend::PoolingMpk is selected (MED finding).
On the MemoryBackend::UnifiedBuffer path this is simply
max_memory_bytes. On the pooling path the physical slot size
(memory_bytes) is an independent hard ceiling the allocator
enforces at instantiation; a module larger than that slot would fail
to instantiate regardless of max_memory_bytes. Taking the minimum
of the two means the executor’s pre-instantiation module check
(check_module_memory_within_cap) rejects an
oversized module with the typed
ExecError::ModuleMemoryTooLarge
before the pooling allocator can surface an opaque
ExecError::Wasmtime, and the per-store
TensorWasmResourceLimiter
caps memory.grow against the same reconciled value.
Trait Implementations§
Source§impl Clone for EngineConfig
impl Clone for EngineConfig
Source§fn clone(&self) -> EngineConfig
fn clone(&self) -> EngineConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for EngineConfig
impl Debug for EngineConfig
Auto Trait Implementations§
impl Freeze for EngineConfig
impl RefUnwindSafe for EngineConfig
impl Send for EngineConfig
impl Sync for EngineConfig
impl Unpin for EngineConfig
impl UnsafeUnpin for EngineConfig
impl UnwindSafe for EngineConfig
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> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
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