Skip to content

[None][feat] Keep hybrid speculative replay state in private KV cache buffers - #21324

Draft
VALLIS-NERIA wants to merge 24 commits into
NVIDIA:mainfrom
VALLIS-NERIA:feat/hybrid-replay-private
Draft

VALLIS-NERIA wants to merge 24 commits into
NVIDIA:mainfrom
VALLIS-NERIA:feat/hybrid-replay-private

Conversation

@VALLIS-NERIA

Copy link
Copy Markdown
Collaborator

Description

Stacked on #21088 (layer and buffer reuse policies). Until that merges, this PR's diff also shows #21088's commits; the commits listed below are this PR's own.

Motivation

Hybrid models with speculative decoding keep per-request replay state next to their recurrent (SSM) state: the inputs of the draft tokens accepted since the last checkpoint, which the verify kernels replay instead of writing a new checkpoint every step. Under KVCacheManagerV2 that state had three problems:

  1. It was lost on suspend/resume (Mamba2, GDN). ReplayHistory (Nemotron) and GDNReplayState (Qwen3.5, Qwen4Exp) kept old_x/old_B/old_dt/..., the accepted-token count (PNAT) and the active double-buffer index in standalone tensors indexed by the SSM state slot. A V2 suspend can offload a request's SSM page and resume it into a different slot; the history stayed at the old slot, so the request continued from another request's (or a reset) history.
  2. It rode along in every snapshot (KDA). KimiK3 and Glm5Next stored their replay buffers in the REQUIRED SSM slot, so every committed prefix-reuse snapshot also carried replay bytes. Because the replay state still did not follow a request, suspend folded pending drafts into the recurrent state and resume re-seeded the replay caches, so a resumed request matched an unsuspended one only to kernel accuracy.
  3. It was sized by the wrong count. The Mamba2/GDN tensors were allocated for every SSM pool slot (snapshot slots included) and counted in no memory budget, although only living requests use replay state.

Design

KVCM: a fixed-capacity PRIVATE SSM pool. KVCacheManagerConfig.max_live_kv_caches (maxLiveKvCaches) bounds the living (active + suspended) KvCaches; createKvCache() rejects one beyond the bound. When it is set, the PRIVATE SSM lifecycle gets a pool group of its own with a fixed GPU capacity of ceil(max_live_kv_caches / max_util_for_resume) slots: PRIVATE pages never enter the radix tree and each living cache holds exactly one, so this keeps the group at or below the resume gate. Construction, adjust()/resize() and the tuner take the fixed group out of the quota first and split the rest by ratio; adjust() never resizes it, and the fixed count is the group's entry in the minimum slots, so a GPU quota too small for all floors is raised, as for the elastic floors. Beam widths above 1 are rejected while a fixed group exists. Without the field, layouts and slot counts are unchanged.

Hybrid managers: replay state as KVCM buffers with its own index.

  • MambaHybridCacheManagerV2 gains a replay declaration hook (_get_replay_layout(), _replay_reuse_policy()). Replay roles become buffers of the existing SSM layers, either PRIVATE (own lifecycle, own slot, own index) or coupled (inherit REQUIRED, share the state slot and index).
  • The manager resolves the replay group, fills per-request replay slots from get_ssm_block_base_index() next to the state slots, and carries them to the kernels through a static Mamba2Metadata.replay_state_indices buffer (CUDA-graph safe; it aliases state_indices when there is no PRIVATE group) and MambaAcceptanceBatch.replay_indices.
  • A request's replay slot is reset the first time it gets one, including generation-only dummies (CUDA-graph padding, warmup, ADP); free and preemption clear that mark, suspend does not.
  • max_live_kv_caches is set to the IndexMapper capacity (max_batch_size * pp_size * (2 if disagg or overlap) + reserved dummy slots + guard page), which already bounds every KvCache creation; _create_kv_cache() returns None at the bound like a full IndexMapper. Disaggregated context servers declare no replay buffers.
  • Replay bytes are a fixed intercept (ceil(N / util) replay slots) in the manager quota and the KV-cache estimate instead of per-state-slot bytes.
  • Python consumers on the hybrid path (pool mapping, page tables, stats, events, disaggregated transfer) resolve groups through get_buffer_group_id / buffer_grouping, re-applying the adoption from [None][feat] Support layer and buffer reuse policies for attention and SSM #21088's history for these sites; connector, sharing and non-hybrid sites keep the legacy API.

Per model family:

Family Managers Replay roles Policy Kernels taking a replay index
Mamba2 Nemotron old_x, old_B, old_dt, old_dA_cumsum per layer + 16-byte PNAT/active-buffer row PRIVATE replay_selective_state_update (all precompute/main kernels), work-item builders
GDN, Triton replay (default) Qwen3.5, Qwen4Exp old_x, old_B, old_dt per layer + 16-byte metadata row (unused old_dA_cumsum dropped) PRIVATE cached replay update, all-layer commit (explicit slot/layer strides or descriptor table)
GDN, FlashInfer ring replay (opt-in) Qwen3.5, Qwen4Exp k_ring, u_ring, g_ring + metadata row coupled REQUIRED none: FlashInfer takes one initial_state_indices; its strided mode reads the KVCM views
KDA KimiK3, Glm5Next conv windows, k/g/v/beta caches or draft records, accepted-draft count PRIVATE trtllm::kda_mtp_decode*, kda_mtp_commit_pending_drafts, KDA Triton helpers

The KDA suspend-time fold of pending drafts and resume-time re-seed are removed, together with the pending-draft commit path that only they used (kda_mtp_commit_pending_drafts, its replay-only kernel variant and Triton helpers); the disaggregated-transfer seeding is kept. V1 managers are unchanged; every kernel's replay index defaults to the state index.

Commits

Commit Change
Reserve fixed capacity for private SSM lifecycles KVCM maxLiveKvCaches, fixed PRIVATE SSM pool group, beam rejection, bindings
Resolve hybrid KV cache groups through buffer APIs behaviour-neutral consumer adoption for split SSM layers
Keep Mamba2 replay history in private KV cache buffers generic replay hook, index plumbing, fresh-page reset, max_live_kv_caches, estimator; Mamba2
Keep GDN replay history in KV cache buffers Qwen3.5 / Qwen4Exp, Triton PRIVATE and FlashInfer ring coupled; experimental engine
Keep KDA replay state in private KV cache buffers KimiK3 / Glm5Next, CuTe op and Triton helpers
Raise a small GPU quota for the fixed replay pool natively fixed group joins the native minimum-quota raise; removes a Python workaround
Remove replay leftovers and unrelated SWA scratch check dead KDA commit path, unused mapping, MambaReplayState protocol, cached group layer ids, shared guard-page parsing; drops an attention-only SWA scratch check that the buffer-API adoption had brought back

Known limitations

  • An explicit kv_cache_config.pool_ratio must now include an entry for the PRIVATE replay group (the hot tier ignores it, but the length must match the layer groups).
  • The PRIVATE pool is sized by the IndexMapper capacity, which doubles max_batch_size with the overlap scheduler or disaggregation. With prefix reuse enabled this is smaller than before; without it, replay memory can grow up to about 2x.
  • FlashInfer ring replay stays coupled to the recurrent-state slot, so its ring bytes are carried by snapshots and come out of the KV budget.
  • Disaggregated context-only servers are recognized through TRTLLM_DISAGG_ROLE=context (the existing KDA convention). A context server launched without it declares PRIVATE replay it never uses and bounds living caches by the IndexMapper capacity, so its early index release no longer admits extra requests while transfers are in flight; correctness is unaffected.
  • KV connectors are still rejected for hybrid managers (unchanged); the connector layout keeps the layer-level API.

Test Coverage

End-to-end (8x B300, sm_103 wheel): in progress, results will be added here. Planned runs: MTP GSM8K accuracy for Qwen3.5-35B-A3B and Qwen3-Next (Triton and FlashInfer ring replay) and Nemotron-3 Super NVFP4 TP8 with prefix reuse, plus Qwen3.5 and Nemotron runs with a small GPU KV budget and a host tier that force V2 suspend/resume (asserting suspended and resumed requests > 0).

Unit tests (B200, umbriel-b200-043, on the integrated branch):

  • C++ kvCacheManagerV2*Test: 208 passed, 0 failed (fixed-capacity sizing, tuner, living-cache bound across suspend, beam rejection, quota raise).
  • Python: 4,195 passed, 22 skipped, 92 subtests, 0 failed.
    • KVCM (kv_cache_manager_v2_tests, kvcm2 integration, csa2, estimation, mixed precision, deepseek_v41 snapshots, dual pool, extra buffers): 892 passed, 14 skipped.
    • Mamba managers and kernels (test_mamba_cache_manager.py, test_mamba_model_managers.py, _torch/modules/mamba/): 2,026 passed, 2 skipped.
    • KDA / GLM (_torch/modules/kimi_kda, glm_kpool, Kimi/GLM modeling, test_kda_decode.py): 743 passed, 6 skipped.
    • GDN experimental engine, Qwen4Exp/QSA, disaggregated transfer: 534 passed.
    • One earlier full run hit a single failure of the experimental engine's test_certified_cells[all_layer n=16 T=3 L=8 S=461 ...] (cached-replay kernel); it did not recur in 42 targeted reruns or the final full run.
  • New coverage, per family (Mamba2, GDN Triton and ring, KDA):
    • kernels with replay slots disjoint from state slots (strided metadata rows, NaN-filled unused rows), bit-exact against the coupled-index run;
    • suspend, give the request's SSM slot to other caches, resume: replay rows, PNAT and active buffer follow the request, and outputs and states match an unsuspended run bit-exactly;
    • commit for reuse excludes PRIVATE: after the source commits and frees, the PRIVATE pool is all free, reuse_status[private].complete is False and the reader starts from reset bookkeeping;
    • fresh-page reset of generation dummies; max_live_kv_caches equals the IndexMapper capacity and the Python guard returns None.
  • FlashInfer 0.6.18 ring replay on the manager's strided KVCM ring views vs contiguous copies: outputs, states and rings bit-exact over 12 steps including flushes.

PR Checklist

  • Description explains the behavior and rationale.
  • Changes follow the coding guidelines; pre-commit hooks pass.
  • Tests cover the new code paths.
  • No high-level LLM API contract or API stability reference changes.
  • No new dependencies or ownership changes.
  • Type stubs and the KVCacheManagerV2 C++ guide are updated.

🤖 Generated with Claude Code

jiaganc and others added 24 commits October 28, 2026 17:02
…on and SSM

Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Add an optional per-buffer reuse policy. A BufferConfig without one uses
its layer's policy. An SSM buffer may set a different policy and then
belongs to the SSM lifecycle of that policy while keeping its layer ID,
so one SSM layer can span several layer groups. Attention buffers must
use their layer's policy.

Lifecycle registration and the storage layout are built per buffer, and
per-layer storage attributes are keyed by (layer, lifecycle), so page
index converters use the buffer's own lifecycle.

Add getLayerGroupId(layerId, role) and its get_layer_group_id(layer_id,
role) binding. The one-argument overload throws when a layer's buffers
span several groups; layerGrouping lists such a layer under each group.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
…By Agent)

_remove_zero_size_buffers rebuilt SSM layer configs without their reuse
policy, which turned PRIVATE and OPTIONAL SSM layers into REQUIRED ones
whenever any layer had a zero-size buffer. Forward the layer policy; the
retained buffers keep their own policies.

Describe how the layer-group helpers handle an SSM layer listed under
several groups and cover them with a split layer.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
…ent)

Pool sizing treats every lifecycle as elastic, so a PRIVATE SSM pool got
the same ratio-derived slot count as the REQUIRED SSM pool, although its
pages never enter the radix tree and only living caches use them, one
slot each.

Add KVCacheManagerConfig::maxLiveKvCaches (max_live_kv_caches), an upper
bound on living (active or suspended) caches. When it is set,
createKvCache() rejects a cache beyond the bound, and the PRIVATE SSM
lifecycle gets a pool group of its own with a fixed GPU capacity of
ceil(maxLiveKvCaches / maxUtilForResume) slots.

ratioToSlotCountList() takes per-pool-group fixed slot counts out of the
quota before splitting the rest by ratio. Construction, resize/adjust
and tuner targets pass them, so adjust() never resizes the fixed group
and the tuner does not chase it. A GPU quota that cannot hold the fixed
group plus the other groups' minimum slots fails at construction, and
beam widths above one are rejected. initialPoolRatio keeps one entry per
layer group; the hot tier ignores the fixed group's entry.

Other PRIVATE lifecycles stay ratio-sized, cold tiers are unchanged, and
without the field the layout and slot counts are unchanged. The Python
binding, stub and dataclass field list gain the field; no production
caller sets it yet.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
…By Agent)

A recurrent buffer with its own reuse policy places one SSM layer in two
layer groups. get_layer_group_id() and layer_grouping raise for such a
layer, so a hybrid V2 manager could not be constructed once a Mamba layer
carried a PRIVATE buffer.

Re-apply the buffer-API consumer forms from 25c879c, b91d86e,
c624c86 and 2ffc2e5 (reverted by 256ac3b) for the sites the
hybrid managers reach:

- KVCacheManagerV2 counts pools and builds its layer, pool-mapping,
  page-table, event and stats metadata from buffer_grouping, resolving a
  split layer's execution group through one of its buffers. It again
  rejects attention layers whose K/V and scales need separate page tables
  and SWA scratch layouts that need split slot indices.
- MambaHybridCacheManagerV2 resolves the recurrent-state group and a
  Mamba layer's execution group through SSM_STATE and describes a group
  without SSM_STATE by its own role.
- Disaggregated transfer gives view-less groups no layers or slots and
  selects the Mamba state group by its pool views.

Connector, sharing and non-hybrid sites keep the legacy API. Without a
split layer every lookup returns the same group as before.

Restore the three split-layer tests the revert deleted and add a test
that a hybrid V2 manager whose Mamba layers carry a PRIVATE buffer
constructs, serves state indices and builds its disaggregated page table.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
…By Agent)

Mamba2 speculative-decoding replay history (old_x, old_B, old_dt,
old_dA_cumsum, PNAT and the active buffer index) lived in standalone
tensors indexed by the SSM state slot. A V2 suspend can move a request's
SSM page to another slot on resume, and the history stayed behind.

MambaHybridCacheManagerV2 gains a generic replay declaration:
- _get_replay_layout() lets a model manager declare per-layer replay
  roles; _replay_reuse_policy() makes them PRIVATE (the default) or lets
  them inherit the layer's REQUIRED policy and share the state slot.
- PRIVATE roles become PRIVATE buffers of the existing SSM layers. The
  manager resolves replay_layer_group_id, fills replay slots from
  get_ssm_block_base_index() next to the state slots, and serves them
  through get_replay_state_indices() and cuda_replay_state_indices.
  Without a PRIVATE group replay slots equal state slots, so GDN, KDA and
  the V1 managers keep their behaviour.
- A request's replay slot is reset the first time it gets one, including
  generation-only dummies; free and preemption clear that mark, suspend
  does not, so resumed history is never reset.
- max_live_kv_caches is set to the IndexMapper capacity, whose
  computation is hoisted into _compute_index_mapper_capacity().
  _create_kv_cache() returns None at the bound instead of letting the
  native manager raise. Disaggregated context servers declare no replay
  buffers.
- The fixed PRIVATE pool is a separate quota intercept, in the manager's
  quota and in the KV-cache estimate, not part of the per-state-slot
  bytes. A small GPU quota is raised so the fixed pool fits next to the
  other pools' minimum slots.
- Replay roles are disaggregation-ignored and the PRIVATE group is left
  out of recurrent-cache movement logging.

Mamba2 kernels and metadata take a separate replay slot:
- replay_selective_state_update() accepts replay_batch_indices (default:
  state_batch_indices) and strided PNAT / active-buffer rows; the
  precompute kernels address only replay buffers through it, and the main
  kernels address the state by state slot and the history by replay slot.
- Replay work items gain a replay-slot field; the builders read PNAT and
  the active buffer through the replay slots. The GDN all-layer commit
  accepts the wider rows.
- Mamba2Metadata keeps a static replay_state_indices buffer, filled in
  prepare() (aliasing state_indices without a PRIVATE group), and
  update_mamba_states() passes it to the acceptance update through
  MambaAcceptanceBatch.replay_indices.

NemotronHybridCacheManager declares ReplayHistory's roles as PRIVATE, with
a 16-byte metadata row on the first local layer. GDN and KDA are unchanged.

Tests cover the kernel with replay slots that differ from state slots,
the work-item builders, the static metadata buffer, the PRIVATE layout
and group, coupled declaration, fresh-page reset of generation dummies,
the living-cache bound and its Python guard, exclusion of replay history
from prefix reuse, and a suspended request whose SSM slot is taken while
it is suspended and that then decodes bit-identically to one never
suspended.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
Qwen3.5 and Qwen4Exp kept Gated-DeltaNet speculative-decoding replay
state in standalone tensors indexed by the SSM state slot. A V2 suspend
can move a request's SSM page to another slot on resume, and the history
stayed behind.

Both GDN managers declare their replay buffers through the manager's
replay hook (shared helpers in modules/fla/cache_manager.py):
- Triton double-buffer mode (default): old_x, old_B and old_dt on every
  local GDN layer plus a 16-byte metadata row on the first local layer
  ([PNAT, active buffer, ring start, padding]) are PRIVATE buffers with
  their own replay slots. The unused old_dA_cumsum is no longer allocated.
- FlashInfer ring mode (TRTLLM_USE_GDN_FLASHINFER_REPLAY): FlashInfer
  addresses the rings by the recurrent-state index, so k_ring, u_ring,
  g_ring and the metadata row inherit the layer's REQUIRED policy, share
  the recurrent-state slot and index, and move with the SSM page.
  FlashInfer's strided mode reads the block-strided ring views directly.
- A disaggregated context server declares no replay buffers; there, and
  wherever no pool is bound, the state allocates its history per state
  slot as before. V1 managers keep their own buffers, and their replay
  slots are the state slots.
- The cache estimate counts the Triton history as the fixed PRIVATE
  intercept and the rings as bytes of every recurrent-state slot.

The kernels address the history by a replay slot of its own:
- fused_recurrent_gated_delta_rule_cached_replay_update() takes
  replay_indices (default: state_indices), explicit history slot strides
  and element strides for PNAT and the active buffer, instead of
  requiring contiguous tensors.
- commit_gdn_cached_replay_history_layers() reads the replay slot from
  full-width work items, takes explicit layer and slot strides of stacked
  history, or a per-layer descriptor table from
  build_gdn_history_descriptors() for views that are not evenly spaced.
- _advance_replay_state() and _advance_ring_start() take replay indices;
  GDNReplayState.update() reads MambaAcceptanceBatch.replay_indices, and
  reset_replay_slots() clears fresh replay slots.
- The GDN mixer and the experimental Qwen4Exp engine pass
  mamba_metadata.replay_state_indices; the engine's replay checks size the
  bookkeeping and history by the replay slots, and its cached-replay op
  wrapper accepts replay_indices.

Tests cover both kernels with replay slots disjoint from the state slots
in strided and descriptor-addressed buffers with strided bookkeeping
(bit-exact against the coupled-index run), FlashInfer on block-strided
rings and on the manager's ring views (bit-exact against contiguous
rings), the PRIVATE layout, group and pool size, max_live_kv_caches,
the cache estimate, fresh-page reset of generation dummies and exclusion
from prefix reuse for Qwen3.5 and Qwen4Exp, the coupled ring layout, and
a request suspended while its SSM slot is taken that then decodes bit
for bit like one never suspended, in Triton and ring mode.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
…ent)

KimiK3 and Glm5Next kept every KDA fused-verify replay buffer (the conv
windows, the k/g/v/beta caches or the draft records, and the
accepted-draft count) in the REQUIRED SSM slot. Every snapshot slot
therefore carried replay bytes, and because the replay state did not
follow a request, a V2 suspend folded the pending drafts into the
recurrent state and the resume re-seeded the replay caches; later
verifies matched an unsuspended run only to the kernel's accuracy.

The KDA replay buffers now go through MambaHybridCacheManagerV2's replay
hook as PRIVATE buffers of the SSM layers:
- KDAReplayState.replay_layout() declares the roles, with the count row
  on the first local layer, and bind_replay_pool() takes the manager's
  views of the replay group, which has a slot count of its own. This
  replaces bind_kda_replay_pool and the managers' buffer-config,
  disagg-role and model-state overrides.
- Acceptance recording (also by the host drafter), context and
  fresh-page resets, disaggregated seeding and the pending-draft commit
  address the replay buffers by replay slot and the recurrent and conv
  states by state slot.
- A suspend no longer commits the pending drafts and a resume no longer
  re-seeds: the PRIVATE pages follow the request. A disaggregated
  generation request suspended before its transferred state seeded the
  replay caches is seeded when it resumes. Disaggregated context servers
  still declare no replay buffers.
- The replay bytes are a fixed intercept of one replay slot per living
  cache instead of per-state-slot bytes; only the stochastic-rounding
  seed stays per state slot.
- The enable_kv_pool_rebalance restriction is unchanged.

The kernels take a replay slot of their own, defaulting to the state
slot:
- trtllm::kda_mtp_decode, kda_mtp_decode_fp8 and
  kda_mtp_commit_pending_drafts take replay_state_indices (schema,
  compile key, validation and kernel). The conv and replay caches and,
  on the packed path, the accepted counts are addressed by replay slot
  and no longer need to cover the recurrent-state rows.
- The KDA Triton helpers (conv-window copy and store, draft-record
  replay, pending-draft commit) take replay indices.
- KimiK3MambaMetadata keeps a static 16-byte-aligned copy of the
  generation requests' replay slots, and the KDA mixer passes the
  metadata's replay slots to prefill, decode and verify.

Tests cover the op and the Triton helpers with replay slots that differ
from the state slots, bit for bit against shared slots; the aligned
metadata copy; for both managers the PRIVATE layout, group and pool
size, the fresh-page reset of generation dummies, exclusion of replay
state from prefix reuse and a suspended request whose replay state
follows it; and the living-cache bound. A request suspended with
pending drafts, whose SSM slot another cache takes meanwhile, now
verifies bit for bit like one never suspended.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
…y (By Agent)

KVCM raised a GPU quota that could not hold the elastic pool groups'
minimum slots, but rejected one that could not hold the fixed-capacity
PRIVATE SSM group. The Mamba V2 manager worked around that by guessing
KVCM's per-pool rounding in Python (_fit_fixed_replay_pool) and raising
the quota itself.

The fixed slot count is already the group's entry in mMinSlots, so drop
the construction-time rejection and let the existing minimum-quota raise
cover the fixed group too. Remove the Python workaround and its imports.
The KDA byte-limit test goes back to its 16 MiB limits, and the tests
that expected a rejection now check that the quota is raised and the
fixed group keeps its full size.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>
… (By Agent)

Clean up what the hybrid replay series left behind:

- KVCacheManagerV2 no longer rejects SWA scratch-reuse layouts whose
  coalesced share is not a whole layer block per slot. The check came
  back with the buffer-API adoption from a reverted series, but it only
  concerns non-hybrid SWA configurations; its test goes with it. The
  rejection of split coupled attention buffers and its test stay.
- Drop buffer_to_pool_mapping_dict, which nothing reads.
- Build _layer_ids_by_group once (functools.cached_property) instead of
  on every access, including the per-request
  get_page_indices_by_layer_group path: the buffer grouping is fixed
  once the native manager exists.
- The KV-cache estimate and the runtime decide whether a guard page is
  reserved with the same parse of TRTLLM_KV_GUARD_PAGE
  (_read_guard_page_setting). The estimate used to count any non-empty
  value, including ones the runtime ignores.
- MambaHybridCacheManagerV2._build_cache_config no longer passes the
  unchanged cache tiers back into replace().
- MambaState.reset_slots documents what the manager calls on every
  state, and a MambaReplayState protocol describes what it calls on a
  state that holds declared replay buffers: bind_replay_pool(),
  reset_replay_slots() and reset_slots(..., replay_slots=...).
- A suspend no longer commits KDA pending drafts, so the commit chain
  has no production caller. Remove KDAReplayState.commit_pending_drafts
  and the SSM views only it read, commit_kda_pending_drafts,
  replay_kda_token_records, store_kda_replay_conv_window, the
  kda_mtp_commit_pending_drafts launcher with its stand-in inputs, and
  the REPLAY_ONLY variant of the KDA MTP verify kernel with its
  replay_only launcher argument. The remaining kernel variants trace the
  same code as before. Remove the tests that exercised only these, and
  the suspend tests' checks that nothing was committed; the conv-window
  copy that disaggregated seeding uses keeps its separate-replay-slot
  test.

Signed-off-by: Xiwen Yu <13230610+VALLIS-NERIA@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants