mstar.engine.resources.attn.dense#
Attention as one dense varlen pass: FlashAttention-3, AITER on ROCm, or FlashInfer’s ragged prefill where neither has a kernel for the GPU.
Classes
|
Attention as one dense varlen pass over a contiguous [frozen prefix | fresh tokens] sequence, through a prefixed ragged wrapper: FA3's (AITER on ROCm), or FlashInfer's where FA3 has no kernel for the GPU ( |
|
dense plan layout. |
|
(request, label) of dense plan; frozen prefix and fresh tokens |
- class mstar.engine.resources.attn.dense.DenseAttentionManager(kv_cache, device, dtype, kv_config, wrapper_class, flashinfer_backend='auto')[source]#
Bases:
AttentionManagerAttention as one dense varlen pass over a contiguous [frozen prefix | fresh tokens] sequence, through a prefixed ragged wrapper: FA3’s (AITER on ROCm), or FlashInfer’s where FA3 has no kernel for the GPU (
ragged.base.dense_or_flashinferpicks;AttentionManager.buildpasses the class).For a workload that recomputes every one of its K/V every step and only reuses a small frozen prefix — diffusion denoise, where the prefix is the text conditioning — the paged path’s per-step full-buffer K/V write and
wrapper.planare pure overhead. This gathers the prefix once per (stream, layer), concatenates it with the freshly projected K/V, and runs one kernel. The gathered prefix is reused across steps: it is keyed on the stream’sgeneration, so a fork, a reset, or a page-table move invalidates it (CacheStream.generation).The layer does not write its K/V to the pages here (
requires_kv_writeis False) — nothing would ever read it back.Eager-only. The gather and the concatenation are shape-dependent and allocate, so there is nothing to capture; a node that runs this walk under a graph should name the paged backend for it.
NOTE on the step declaration: the fresh tokens are declared as ordinary spans on
KVStepwithcommit=False, exactly as they would be for the paged backend, so the query lengths arrive as the KV plan’sto_computeand the prefix aslength - to_compute. That is what keeps the backend a spec-time choice: the same declaration runs either way, and positions still take their packing off the KV plan output. The alternative — declaring the fresh tokens zero-span and carrying their lengths onAttentionStep’s own segments — is what the v0 dense path did and would save the pages that are reserved here and never written; it costs the swappability, since a model would then have to declare its step differently per backend, and a zero-span label yields no packing for any resource that derives from it (PositionManagerwould only work for labels supplying explicit pos_ids).- Parameters:
kv_cache (str)
device (device)
dtype (dtype)
kv_config (PagedKVConfig)
wrapper_class (type[PrefixedPrefillWrapper])
flashinfer_backend (str)
- fingerprint()[source]#
What this resource contributes to the prefix cache’s root.
Everything a stored page depends on beyond its own tokens. None leaves the resource out of the root, which is right only where it cannot change what a page holds.
- Return type:
- property force_double_buffer#
Whether this resource needs double-buffering even off the pre-plan path.
A resource that stages a step’s layout into a reused host buffer and issues a non-blocking H2D into a graph-read device buffer has a race the moment the CPU runs ahead of the GPU: plan(N+1) can overwrite the buffer before step N’s DMA has retired, and the replay attends with N+1’s data. The buffer need not be ours — FlashInfer’s
planholds one per wrapper, which is why the attention managers key theirs per slot. The main runner already double-buffers whenever a resourcesupports_preplan; this flag extends that to a runner that has no pre-plan path but still replays such a resource — notably the piecewise runner — and makes_exec_per_requestfence before it reuses a slot, since its sub-steps all run inside one step. Off by default; a resource opts in only if it has this hazard.
- ingest_request(rid, overrides=None)[source]#
Must be idempotent: the conductor sends one NewRequest per partition, so a worker serving several partitions of a request ingests it once for each, possibly after a node has already run a step for it.
- Parameters:
rid (str)
- plan(step, ctx)[source]#
ret is immutable and opaque to runner; only gives to ctx.plan_results
- Parameters:
step (AttentionStep)
ctx (StepContext)
- property requires_kv_write: bool#
Whether a layer must write this step’s K/V through the KV resource before calling
run.False only for backends that take the fresh K/V straight into the kernel (the dense one). A layer therefore reads
- if self.attn.requires_kv_write:
self.kv.write_kv(k, v, layer_idx=i, label=label)
out = self.attn.run(q, label, kv.layer_view(i), k=k, v=v, layer_idx=i)
and stays correct whichever backend the spec named.
- class mstar.engine.resources.attn.dense.DensePlan(segments, cu_q, cu_k, max_q, max_k, causal, wrapper=None)[source]#
Bases:
objectdense plan layout. once per step and read by each layer run
- Parameters:
segments (tuple[DenseSegment, ...])
max_q (int)
max_k (int)
causal (bool)
wrapper (PrefixedPrefillWrapper | None)
- segments: tuple[DenseSegment, ...]#
- wrapper: PrefixedPrefillWrapper | None = None#