Skip to main content

KernelCache

Struct KernelCache 

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

Thread-safe LRU cache of compiled kernels backed by dashmap::DashMap.

get and put are O(1) and (under typical concurrent workloads) lock- free except for the per-shard dashmap lock and the eviction-policy parking_lot::Mutex. The eviction lock is taken only on puts that would push the cache over capacity; reads never touch it.

Implementations§

Source§

impl KernelCache

Source

pub fn new() -> Self

Construct with default capacity.

Source

pub fn with_capacity(cap: usize) -> Self

Construct with explicit capacity. Anything below 1 is clamped to 1.

Source

pub fn with_config(config: KernelCacheConfig) -> Self

Construct from a full KernelCacheConfig. Anything below 1 in config.capacity is clamped to 1.

Source

pub fn with_disk_persistence(self, cfg: DiskCacheConfig) -> Self

Enable the on-disk L2 cache, persisting entries to cfg.dir under an HMAC-keyed integrity tag (jit S-3).

Construct via:

use std::path::PathBuf;
use tensor_wasm_jit::cache::{KernelCache, DiskCacheConfig};
let cache = KernelCache::new().with_disk_persistence(DiskCacheConfig {
    dir: PathBuf::from("/var/cache/tensor-wasm/kernels"),
    hmac_key: load_hmac_key_from_secret_store()?, /* loaded from secrets at startup */
});

jit S-3 (T13): the example deliberately routes the key through a load_hmac_key_from_secret_store() stub rather than an inline literal — operators have a habit of copy-pasting rustdoc examples verbatim, and an embedded [0xAB; 32] (or similar) would survive into production deployments as a fixed, attacker-known key.

The directory is created lazily on the first put. The HMAC key MUST be stable across process restarts AND treated as a server- side secret — possession of the key lets an attacker forge cache entries that the loader will accept as authentic (and that would then be handed to cust::module::Module::from_ptx as trusted GPU code).

Source

pub fn put(&self, key: CacheKey, kernel: CachedKernel)

Insert (or replace) a kernel. If the insert pushes the cache over the count cap (or, when configured, the byte cap), evicts LRU entries from storage and the policy queue until both caps are satisfied.

jit S-3: the kernel’s integrity_hash is recomputed and compared against the stored hash; a mismatch is treated as a programmer error (CachedKernel constructed via struct-literal with a wrong hash), logged at error!, and the entry is dropped rather than admitted. Use CachedKernel::new for the correct-by- construction path. The on-disk L2 also writes the entry when configured.

Source

pub fn get(&self, key: &CacheKey) -> Option<Arc<CachedKernel>>

Look up a kernel; best-effort touches the LRU position.

T20 perf: returns Option<Arc<CachedKernel>> rather than the previous Option<CachedKernel> so a cache hit shares the wrapper allocation via refcount bump instead of cloning the 32-byte integrity hash + fingerprint + inner-Arc refcount bump. The inner PTX text was already shared; this closes the matching gap on the outer wrapper.

Source

pub fn get_for( &self, tenant_id: TenantId, blueprint: &TensorWasmKernelBlueprint, sm_version: u32, ) -> Option<Arc<CachedKernel>>

Look up by blueprint + sm_version for a given tenant; convenience wrapper around Self::get.

T20 perf: returns Option<Arc<CachedKernel>> to mirror Self::get; callers that only need to peek at fields go through auto-deref unchanged.

Source

pub fn get_with_registry_fallback( &self, key: &CacheKey, resolver: &dyn BlueprintResolver, ) -> Option<Arc<CachedKernel>>

L1 → L2 → L3(registry) resolution path. v0.3.8 scaffold: invokes the registered resolver + registry on every miss; v0.4 may add a resolver-level cache to amortise the (blueprint → name@version) translation.

Source

pub fn len(&self) -> usize

Number of entries currently held.

Source

pub fn is_empty(&self) -> bool

True if empty.

Source

pub fn capacity(&self) -> usize

Configured capacity.

Source

pub fn total_bytes(&self) -> u64

Running sum of resident PTX-text bytes across all L1 entries (each entry contributes cached.ptx.text.len()). This is the quantity the optional KernelCacheConfig::max_total_bytes cap bounds. Surface on the Prometheus gauge tensor_wasm_jit_cache_bytes so operators can watch the L1 footprint against the configured byte cap. Always present (returns 0 for an empty cache, and tracks the live total whether or not a byte cap is configured).

Source

pub fn max_total_bytes(&self) -> Option<u64>

The configured byte cap, if any (mirror of KernelCacheConfig::max_total_bytes). None means count-only eviction. Useful for diagnostic endpoints that surface both the live Self::total_bytes and the ceiling it is measured against.

Source

pub fn active_disk_key_fingerprint(&self) -> Option<KeyFingerprint>

Fingerprint of the active on-disk HMAC key — the partition prefix every file this cache writes lands under — or None if no L2 disk cache is configured.

Pass this into the retain set of Self::gc_disk to keep the live generation (though gc_disk retains it unconditionally as a safety net).

Source

pub fn disk_key_fingerprints(&self) -> Result<Vec<KeyFingerprint>>

Enumerate the distinct HMAC-key fingerprints present in the on-disk L2 cache directory (one per key generation that has written at least one file). Returns an empty Vec when no disk cache is configured or the directory does not yet exist.

Use this to discover stale generations before a Self::gc_disk sweep — anything in this list that is not the active fingerprint and not a key you still want to honour is a rotation leftover.

Source

pub fn gc_disk(&self, retain: &[KeyFingerprint]) -> Result<usize>

Garbage-collect the on-disk L2 cache after an HMAC-key rotation: remove every persisted entry whose key fingerprint is NOT in retain, returning the number of files removed. A no-op returning Ok(0) when no disk cache is configured.

The active key’s fingerprint is always retained — even if the caller omits it from retain — so a sweep can never delete the live generation’s entries. Only stale-fingerprint files are removed, and only files matching the cache’s own naming scheme are considered (unrelated files in the directory are left untouched).

§Example
use std::path::PathBuf;
use tensor_wasm_jit::cache::{KernelCache, DiskCacheConfig};

// After rotating to a fresh HMAC key, stand up a cache under it…
let cache = KernelCache::new().with_disk_persistence(DiskCacheConfig {
    dir: PathBuf::from("/var/cache/tensor-wasm/kernels"),
    hmac_key: load_hmac_key_from_secret_store()?,
});

// …then sweep every previous generation's files. Retaining only the
// active key (which `gc_disk` keeps regardless) drops all the rest.
let active = cache.active_disk_key_fingerprint().into_iter().collect::<Vec<_>>();
let removed = cache.gc_disk(&active)?;
println!("swept {removed} stale-fingerprint cache files");
Source

pub fn config(&self) -> &KernelCacheConfig

Borrow the construction-time KernelCacheConfig. Useful for tests and diagnostic endpoints that want to surface whether verify_on_get is on for this cache instance.

Source

pub fn verify_skipped_total(&self) -> u64

Cumulative count of L1 get hits that skipped the BLAKE3 integrity recompute because KernelCacheConfig::verify_on_get is false. Surface this on the Prometheus counter tensor_wasm_jit_cache_verify_skipped_total so operators can see how often the cache is trusting an L1 entry without re-hashing the PTX. The counter is always present (returns 0 when verify_on_get is on) so dashboards can scrape it unconditionally.

Source

pub fn cache_hits_total(&self) -> u64

Cumulative L1/L2/L3 cache hit count. Incremented once per get call that returns Some. Surface on the Prometheus counter tensor_wasm_jit_cache_hits_total so operators can compute the hit ratio against Self::cache_misses_total. (T20 perf.)

Source

pub fn cache_misses_total(&self) -> u64

Cumulative cache miss count. Incremented once per get call that returns None — including the rare path where an L1 entry failed integrity verification and was evicted. Surface on the Prometheus counter tensor_wasm_jit_cache_misses_total. (T20 perf.)

Source

pub fn integrity_reject_total(&self) -> u64

Cumulative count of entries refused on get because they failed integrity verification — an L1 BLAKE3 recompute mismatch, an all-zero integrity_hash on the verify-skip path, or an L2 disk integrity failure (artifact-store HMAC/content-hash mismatch, inner-envelope magic/header/length/UTF-8 corruption). These also bump Self::cache_misses_total, but this dedicated counter lets operators alarm on tamper attempts specifically rather than drown them in ordinary cold-cache misses. Surface on the Prometheus counter tensor_wasm_jit_cache_integrity_reject_total.

Trait Implementations§

Source§

impl Clone for KernelCache

Source§

fn clone(&self) -> KernelCache

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for KernelCache

Source§

fn default() -> Self

Returns the “default value” for a type. 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
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Send + Sync>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

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

Initializes a with the given initializer. Read more
Source§

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

Dereferences the given pointer. Read more
Source§

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

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

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

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more