Skip to main content

LatentKvCache

Struct LatentKvCache 

Source
pub struct LatentKvCache {
    pub layers: Vec<Option<Vec<LatentSlot>>>,
    pub cached_len: usize,
    pub slot_trailing: Vec<Vec<usize>>,
    pub max_seq_len: usize,
    pub dtype: DType,
    /* private fields */
}
Expand description

Cross-graph, cross-forward-pass persistent N-slot decode cache — the KvCache generalization for latent-caching attention architectures.

KvCache hardwires a symmetric K/V pair (two buffers per layer, same shape). That’s wrong for compression architectures:

  • Multi-head Latent Attention (DeepSeek-V2 MLA): per layer, a low-rank compressed latent [kv_lora_rank] (slot 0) and a single-head RoPE key [qk_rope_head_dim] (slot 1) — two slots of different trailing shape, neither a [n_kv_heads, head_dim] K/V.
  • Two-projection attention / QKV pruning: a single retained projection per layer — one slot.

LatentKvCache is this module’s counterpart to crate::lazy_latent_cache::LatentCache — that type makes the exact same per-layer, ordered list of latent buffers with independent trailing shapes generalization for the per-forward- pass (single fuel_graph::Graph-anchored, functional append-and-thread) lifecycle. LatentKvCache is the persistent sibling: device-resident Arc<RwLock<Storage>> buffers that survive across graphs/forward calls and are mutated in place via Op::WriteSlice, exactly the relationship KvCache has to a plain per-pass K/V cache. Read both modules’ docs together for the two lifecycles side by side.

§Shape contract

Slot s of every layer is a buffer [max_seq_len, ...slot_trailing[s]] — the capacity axis is dim 0. This differs from KvCache’s [1, n_kv_heads, max_seq_len, head_dim] convention (capacity axis 2): a latent is a per-token vector, not a per-head plane, so there is no head axis to lead with. Matches [crate::lazy_latent_cache:: LatentCache]’s dim-0 convention exactly — this type’s per-slot buffer is byte-for-byte what that type’s slot_buffer_full realizes, modulo device residency.

Fields§

§layers: Vec<Option<Vec<LatentSlot>>>

layers[l] is None until populated; Some(slots) holds one LatentSlot per slot index (pipeline-parallel friendly — mirrors KvCache::layers).

§cached_len: usize§slot_trailing: Vec<Vec<usize>>

Per-slot trailing shape (past the leading capacity axis); its length is the per-layer slot count.

§max_seq_len: usize§dtype: DType

Implementations§

Source§

impl LatentKvCache

Source

pub fn with_capacity( n_layers: usize, max_seq_len: usize, slot_trailing: Vec<Vec<usize>>, dtype: DType, device: &Device, ) -> Result<Self>

Pre-allocated N-slot latent cache. Every layer’s slot buffers are allocated up-front as zero buffers on device with dtype, shaped [max_seq_len, ...slot_trailing[s]]. Mirrors [KvCache:: with_capacity]’s Op::Alloc → Op::ZeroFill graph-emission pattern exactly, generalized from a fixed 2-buffer (K, V) layer to slot_trailing.len() buffers of independent shape.

Returns Err for degenerate geometry (n_layers == 0, max_seq_len == 0, or no slots) or if any per-layer allocation fails (e.g. CUDA OOM / an unwired device).

Source

pub fn slot_storage( &self, layer_idx: usize, slot: usize, ) -> Option<Arc<RwLock<Storage>>>

Borrow the slot s storage Arc for layer layer_idx. None if the layer is unpopulated or either index is out of range. Used by the forward path to bind cache storage to per-step Const nodes via InferenceContext::insert. Mirrors KvCache::slot_storage.

Source

pub fn bump_version(&mut self, layer_idx: usize, slot: usize)

Bump slot s’s monotonic version counter for layer_idx. No-op (never panics) if either index is out of range. Mirrors KvCache::bump_version.

Source

pub fn n_layers(&self) -> usize

Source

pub fn n_slots(&self) -> usize

Number of slots per layer.

Source

pub fn slot_trailing(&self, s: usize) -> &[usize]

Trailing shape of slot s (past the leading capacity axis).

Source

pub fn alloc_id(&self) -> KvAllocId

Identity of the storage this cache currently owns. Mirrors KvCache::alloc_id; see KvAllocId.

Source

pub fn clear(&mut self)

Drop every layer; reset cached_len to zero. Mirrors KvCache::clear, including the Self::alloc_id re-mint — every storage Arc is released, so a plan welded to them must be rebuilt.

Source

pub fn truncate_to(&mut self, new_len: usize)

Shrink the cache to new_len cached positions — metadata-only, same Phase E.3.0 limitation and rationale as [KvCache:: truncate_to]: the underlying storages are not shrunk; the pre-allocated buffers’ trailing rows simply stop being read until overwritten by a later Op::WriteSlice at the same positions.

Deliberately preserves Self::alloc_id — a rewind is not a re-allocation. Same rule as KvCache::truncate_to.

Trait Implementations§

Source§

impl KvRebindSource for LatentKvCache

Source§

fn alloc_id(&self) -> KvAllocId

Identity of this allocation. See KvAllocId.
Source§

fn rebind_location(&self) -> Option<DeviceLocation>

Where the storage lives, or None when that is not provable — which DecodeSession::rebind_kv treats as a refusal, never as a default.
Source§

fn rebind_slot( &self, layer: usize, which: usize, ) -> Option<Arc<RwLock<Storage>>>

Storage for slot which (0 or 1) of layer — the two halves of the plan’s kv_nodes[layer] pair, in the order the builder bound them.

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

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

Source§

impl<T> ErasedDestructor for T
where T: 'static,

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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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