BufferArena

Struct BufferArena 

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

Pre-allocated GPU buffers for a single forward pass.

Each buffer is sized for max_batch_tokens tokens through the model. Buffers are reused across steps — no per-step allocation.

Expert output buffers are sized for max(k_max, max_batch_tokens) to support both speculative decode (K=3) and batched MoE prefill. At N=512, this adds ~31 MB (vs the old grouped-GEMM approach that needed 260 MB and caused a 15% decode regression). The GEMV-based prefill kernels only touch k_max slots during decode, so the extra pages don’t affect decode bandwidth on unified memory.

Implementations§

Source§

impl BufferArena

Source

pub fn hidden_states(&self) -> DevicePtr

Source

pub fn residual(&self) -> DevicePtr

Source

pub fn norm_output(&self) -> DevicePtr

Source

pub fn qkv_output(&self) -> DevicePtr

Source

pub fn attn_output(&self) -> DevicePtr

Source

pub fn gate_logits(&self) -> DevicePtr

Source

pub fn gate_logits_f32(&self) -> DevicePtr

Source

pub fn moe_router_in_f32(&self) -> DevicePtr

Source

pub fn moe_output(&self) -> DevicePtr

Source

pub fn logits(&self) -> DevicePtr

Source

pub fn ssm_qkvz(&self) -> DevicePtr

Source

pub fn ssm_ba(&self) -> DevicePtr

Source

pub fn ssm_deinterleaved(&self) -> DevicePtr

Sequential [Q|K|V|Z] after deinterleaving.

Source

pub fn ssm_gates(&self) -> DevicePtr

FP32 [gate, beta] for GDN (num_v_heads * 2 floats).

Source

pub fn ssm_conv_out_f32(&self) -> DevicePtr

FP32 conv1d output for SSM recurrent path (prevents BF16 precision drift).

Source

pub fn scratch(&self) -> DevicePtr

Scratch buffer for MoE routing + kernel metadata uploads.

Source

pub fn ssd_scratch(&self) -> DevicePtr

Mamba-2 SSD chunked-scan scratch (dt | dA_cumsum | CB). NULL if unused.

Source

pub fn token_ids(&self) -> DevicePtr

Token IDs [M] u32 — stable across the layer loop (DeepSeek-V4 hash-MoE reads tid2eid[token_id]). Upload the pass’s token IDs here before the layer loop; under CUDA-graph decode upload before each replay.

Source

pub fn scratch_bytes(&self) -> usize

Allocated byte size of the scratch buffer (#110: bounds-check batched metadata-staging uploads against this).

Source

pub fn expert_gate_out(&self) -> DevicePtr

Batched expert gate projection output.

Source

pub fn expert_up_out(&self) -> DevicePtr

Batched expert up projection output.

Source

pub fn expert_down_out(&self) -> DevicePtr

Batched expert down projection output.

Source

pub fn gdn_fla_scratch(&self) -> DevicePtr

Split-K decode attention workspace (F32 partials). GDN FLA chunked-prefill scratch base (W|U|S|uc sub-divided by the caller). DevicePtr::NULL unless this is a 128-dim-linear-head GDN model.

Source

pub fn ffn_act_q8(&self) -> DevicePtr

Shared dense-FFN q8_1 activation scratch (Q4_K MMQ gate/up). NULL for MoE.

Source

pub fn ffn_act_a(&self) -> DevicePtr

Shared dense-FFN int8/NVFP4 activation scratch (a_i8 / packed). NULL for MoE.

Source

pub fn ffn_act_scale(&self) -> DevicePtr

Shared dense-FFN int8/NVFP4 activation-scale scratch. NULL for MoE.

Source

pub fn fp8_act(&self) -> DevicePtr

Persistent FP8 block-scaled activation scratch for prefill projections. Replaces a per-projection alloc/sync/free in the W8A8+FP32-epilogue path.

Source

pub fn fp8_act_bytes(&self) -> usize

Allocated byte size of fp8_act (debug bounds-check at call sites).

Source

pub fn fp8_act_scale(&self) -> DevicePtr

Persistent per-128-block FP32 scales paired with fp8_act.

Source

pub fn q2_dequant_scratch(&self) -> DevicePtr

Persistent BF16 transient-dequant scratch for native keep-packed Q2_0 prefill. Reused per projection: dequant into it, GEMM reads it (same stream), no free. NULL unless ATLAS_GGUF_NATIVE_Q2.

Source

pub fn q2_dequant_scratch_bytes(&self) -> usize

Allocated byte size of q2_dequant_scratch (debug bounds-check).

Source

pub fn q2_act_q8(&self) -> DevicePtr

Persistent q8_1 activation scratch for native Q2_0 MMQ prefill (ATLAS_GGUF_NATIVE_Q2_MMQ). NULL unless the flag is set.

Source

pub fn q2_act_q8_bytes(&self) -> usize

Allocated byte size of q2_act_q8 (debug bounds-check).

Source

pub fn splitk_workspace(&self) -> DevicePtr

Source

pub fn o_latent(&self) -> DevicePtr

Grouped O-projection latent [M, o_groups*o_lora_rank] BF16 (V4-Flash).

Source

pub fn norm_unit_w(&self) -> DevicePtr

All-ones BF16 vector (max_dim) — weight for unweighted RMSNorm (q_b_norm).

Source

pub fn hc_streams(&self) -> DevicePtr

HC residual streams [M, hc_mult, hidden] BF16 (DeepSeek-V4 mHC).

Source

pub fn hc_lowrank_scratch(&self) -> DevicePtr

Low-rank mHC split-collapse scratch: [T<=64, hc*H] normed followed by [T<=64, rank] low, both F32. See sizes.rs.

Source

pub fn qsa_select_scratch(&self) -> DevicePtr

QSA stage-2 prefill-selection scratch, shared by the indexer layers (serial). Layout managed by layers::qsa; see sizes.rs.

Source

pub fn hc_post(&self) -> DevicePtr

HC post mixing weights [M, hc_mult] F32.

Source

pub fn hc_comb(&self) -> DevicePtr

HC comb Sinkhorn matrix [M, hc_mult, hc_mult] F32.

Source

pub fn max_batch_tokens(&self) -> usize

Source

pub fn decode_meta(&self) -> DecodeMetaLayout

Derived batched-decode metadata layout (rows/offsets). Byte-identical to the legacy fixed 32-row layout for every serve max_batch_size <= 32.

Source

pub fn sizes(&self) -> &BufferSizes

Source

pub fn lora_xa(&self) -> DevicePtr

Env-gated (ATLAS_SSM_SAVE_DUMP) per-buffer checksum probe.

CBD: localize a stale/uninitialized decode-scratch buffer on the prefix-cache skip path. Dumps sum/ssq/sabs over the FULL allocation (so leftover-from-prior-occupant bytes in unwritten rows are visible) for every reusable buffer. Treats raw bytes as f32 lanes — exact numeric meaning is irrelevant; we only need a stable fingerprint that differs iff the bytes differ. Synchronizes the stream first. LoRA compressed activation scratch xa = x@Aᵀ [M, max_rank] BF16. DevicePtr::NULL when no adapter is configured.

Source

pub fn lora_xa_bytes(&self) -> usize

Allocated byte size of lora_xa (0 when no adapter).

Source

pub fn lora_delta(&self) -> DevicePtr

LoRA expand scratch delta = xa@Bᵀ [M, max(hidden, intermediate)] BF16. DevicePtr::NULL when no adapter is configured.

Source

pub fn lora_delta_bytes(&self) -> usize

Allocated byte size of lora_delta (0 when no adapter).

Source

pub fn lora_hact(&self) -> DevicePtr

LoRA hidden-activation scratch [M, intermediate_size] BF16 for the runtime FFN delta path. DevicePtr::NULL when no adapter.

Source

pub fn lora_hact_bytes(&self) -> usize

Allocated byte size of lora_hact (0 when no adapter).

Source

pub fn lora_seq_slot(&self) -> DevicePtr

LoRA per-request routing slots [max_batch_tokens] i32 for the prefill path — one adapter SLOT index per prefilling token. DevicePtr::NULL when no adapter is configured.

Source

pub fn debug_buffer_checksum( &self, gpu: &dyn GpuBackend, stream: u64, tag: &str, )

Source

pub fn zero_prefill_essentials( &self, gpu: &dyn GpuBackend, stream: u64, ) -> Result<()>

Zero only buffers that carry residual state between requests.

During prefill, every buffer except hidden_states and residual is fully overwritten before being read within the layer loop:

  • norm_output, qkv_output, attn_output: written by each layer’s projection
  • gate_logits, moe_output: written by MoE gate/output
  • ssm_*: written by SSM projection
  • expert_*: written by expert compute
  • logits: written by LM head on last token
  • scratch: overwritten by metadata upload and MoE routing
  • splitk_workspace: written by attention kernel

This reduces per-chunk memset from 17 calls to 2, saving ~15 memset launches × bandwidth on the LPDDR5X bus per prefill chunk.

Source

pub fn zero_all_rows( &self, gpu: &dyn GpuBackend, stream: u64, tokens: usize, ) -> Result<()>

zero_all, but only the first tokens rows of every token-major arena.

🔴 Every buffer zero_all wipes is [max_batch_tokens, row]-major — verified against the allocated sizes: size / max_batch_tokens is exactly one token’s row for each of them (qkv_output 3x8192 BF16, attn_output 64x256, expert_gate_out topk2048, expert_down_out topk4096, …). A decode step carrying tokens tokens can therefore only ever read rows 0..tokens, and zeroing the rest is dead bandwidth.

Measured on GLM-5.3-Flash, 2 x GB10, max_batch_tokens = 4096 (nsys, 2026-08-28): zero_all issues 18 memsets totalling 1.59 GB and 8.01 ms on every single decode token — 9.4 % of an 85 ms step, all of it GPU-idle time before the first kernel.

logits, scratch and splitk_workspace are NOT token-major (metadata arenas / vocab-sized), so they keep the full wipe. They are 30 MB of the 1590.

Source

pub fn zero_all(&self, gpu: &dyn GpuBackend, stream: u64) -> Result<()>

Zero all reusable buffers to eliminate stale data between requests. Ensures deterministic computation regardless of request history.

Source§

impl BufferArena

Source

pub fn new( config: &ModelConfig, max_batch_tokens: usize, max_seq_len: usize, kv_block_size: usize, max_batch_size: usize, gpu: &dyn GpuBackend, ) -> Result<Self>

Allocate all intermediate buffers on the GPU.

Trait Implementations§

Source§

impl ModelResource<dyn GpuBackend> for BufferArena

Release every buffer this arena owns.

The destructure below is exhaustive on purpose — no ... A buffer added to BufferArena without a matching free is a leak that only shows up as the next model failing to fit, so the compiler is made to refuse the addition instead. If this line stops compiling, the fix is to free the new field, not to add a wildcard.

Source§

fn label(&self) -> &'static str

Human name, for the teardown report and for attributing a failure.
Source§

fn release(&mut self, gpu: &dyn GpuBackend) -> Result<()>

Release everything this owns. Must be idempotent: the host calls it, and a Drop backstop may call it again.

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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

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

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

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, 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

§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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