Skip to content

CUDA graph support for prefix caching on hybrid models - #3922

Merged
lmcafee-nvidia merged 21 commits into
NVIDIA:mainfrom
lmcafee-nvidia:prefix-caching-mamba-cg
Mar 25, 2026
Merged

lmcafee-nvidia merged 21 commits into
NVIDIA:mainfrom
lmcafee-nvidia:prefix-caching-mamba-cg

Conversation

@lmcafee-nvidia

Copy link
Copy Markdown
Contributor

Summary

  • Make Mamba state extraction compatible with CUDA graphs during prefix caching
  • Enable CUDA graphs for chunked prefill on hybrid (transformer + Mamba) models
  • Add comprehensive correctness tests for prefix caching + CUDA graph interactions

Test plan

  • test_prefix_caching_cuda_graphs.py passes
  • Existing test_dynamic_prefix_caching.py tests still pass
  • test_dynamic_engine.py chunked prefill + CUDA graph tests pass

🤖 Generated with Claude Code

lmcafee-nvidia and others added 4 commits March 18, 2026 06:09
Make intermediate SSM and conv state extraction fully CUDA graph
compatible by replacing Python loops and .item() calls with
pre-allocated fixed-size buffers and vectorized tensor ops.

MambaMetadata precomputes chunk indices and absolute positions
during update() (before graph capture/replay). MambaSlotAllocator
provides pre-allocated output buffers that _ssm_prefill writes to
via GPU ops captured in the graph. commit_intermediate_states()
reads from these buffers after the graph completes.

This removes the requires_mamba_state_extraction guard that
previously forced eager mode for prefill steps needing extraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers every combination of model type (transformer, hybrid) and batch
structure (prefill, decode, mixed) — 6 cases total. Each case runs the
same prefix-sharing scenario with and without CUDA graphs, asserting
token correctness and verifying actual CUDA graph usage at the expected
step types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove two blanket guards that disabled CUDA graphs for all hybrid
chunked prefill steps:

1. Guard in match_graph_config() that returned None whenever
   explicit_chunked_prefill was set and prefill requests were present.
   Also removes the now-unused explicit_chunked_prefill parameter from
   match_graph_config() and adjust_batch_dims_for_expert_parallelism().

2. Guard in is_chunked_prefill_enabled() that disabled chunked prefill
   during CUDA graph capture for hybrid models.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…h for continuation chunks

Test 1 (test_dynamic_engine.py): parameterized test across model type
(gpt/mamba) x chunked prefill (off/on) x CUDA graphs (off/on), verifying
output tokens match a baseline config. Uses constrained max_tokens to
force actual chunking with multiple active prefill requests.

Test 2 (test_prefix_caching_cuda_graphs.py): hybrid model test where one
request is mid-chunk (Mamba intermediate state being extracted) while
another has Mamba state restored from the prefix cache.

Bug fix (dynamic_context.py): the Mamba match count check in
`_compute_prefix_match` was incorrectly applied to continuation chunks,
where `_mamba_num_matched_blocks` (set over the whole prompt) was compared
against the KV match count for only the continuation block range. Added
`finished == 0` guard so Mamba match logic only runs for the first chunk.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lmcafee-nvidia
lmcafee-nvidia requested review from a team as code owners March 18, 2026 13:16
@copy-pr-bot

copy-pr-bot Bot commented Mar 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@svcnvidia-nemo-ci
svcnvidia-nemo-ci marked this pull request as draft March 18, 2026 13:16
@github-actions

Copy link
Copy Markdown
Contributor

This PR has been automatically converted to draft because all PRs must start as drafts.

When you are ready for review, click Ready for Review to begin the review process. This will:

  1. Add the oncall reviewer (optional reviewer)
  2. Add required review teams based on your changes

See the contribution guide for more details.

…for Mamba dynamic-batching prefill

The per-request causal_conv1d_fn loop was a legacy fallback incompatible with
CUDA graphs. The Triton causal_conv1d_varlen_fn path is strictly superior and
was already force-enabled during graph capture. This removes the fallback
entirely along with the use_triton_conv1d config/CLI plumbing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lmcafee-nvidia lmcafee-nvidia self-assigned this Mar 18, 2026
@lmcafee-nvidia
lmcafee-nvidia marked this pull request as ready for review March 19, 2026 00:57
@svcnvidia-nemo-ci
svcnvidia-nemo-ci requested a review from a team March 19, 2026 00:57
lmcafee-nvidia and others added 2 commits March 18, 2026 18:18
@lmcafee-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test 44b7f29

@svcnvidia-nemo-ci svcnvidia-nemo-ci added this to the Core 0.16 milestone Mar 19, 2026
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lmcafee-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test 49c7f97

Comment thread megatron/core/inference/contexts/attention_context/mamba_metadata.py Outdated
Comment on lines +357 to +371
for i in range(real_prefill_count):
seq_start = cu_seqlens_real[i]
seq_len = cu_seqlens_real[i + 1] - seq_start
num_chunks = max(1, (seq_len + chunk_size - 1) // chunk_size)
first_chunk_idx = cumulative_chunks
offsets = intermediate_token_offsets[i]
count = 0
for offset in offsets:
chunk_idx = first_chunk_idx + (offset // chunk_size) - 1
abs_pos = seq_start + offset
chunk_indices_list.append(chunk_idx)
abs_positions_list.append(abs_pos)
count += 1
per_request_counts.append(count)
cumulative_chunks += num_chunks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @kvareddy alluded to, can we vectorize this / directly construct the tensors rather than using lists and loops?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, we now use vectorized GPU ops here. please take another look

Comment thread megatron/core/inference/contexts/attention_context/mamba_metadata.py Outdated
Comment thread megatron/core/inference/contexts/mamba_slot_allocator.py Outdated
Comment thread megatron/core/ssm/mamba_mixer.py Outdated
Comment on lines +396 to +423
# Commit intermediate states from output buffers
intermediate_count = metadata.intermediate_count
if intermediate_count > 0:
per_request_counts = metadata.per_request_intermediate_counts
ssm_offset = 0
req_batch_idx = 0
for count in per_request_counts:
ctx_idx = prefill_start + req_batch_idx
block_ids = self._intermediate_block_ids[ctx_idx]

if count > 0 and block_ids is not None:
for j in range(count):
bid = block_ids[j]
slot = self.allocate_slot(bid)

# Copy states from output buffers for all layers
for layer_idx in range(self.num_mamba_layers):
self.ssm_states[layer_idx, slot].copy_(
self._intermediate_ssm_out[layer_idx, ssm_offset + j]
)
self.conv_states[layer_idx, slot].copy_(
self._intermediate_conv_out[layer_idx, ssm_offset + j]
)

# Register in mamba hash map
block_hash = ctx.kv_block_allocator.block_hashes[bid].item()
if block_hash > 0:
self.register_block_hash(bid, block_hash)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about potential vectorization

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method has been partially vectorized, in the sense that block IDs and hashes are batch-transferred from the GPU via a single .tolist(). the loop isn't easily parallelizable though because it may trigger LRU eviction with side effects like deregistration and free-pool mutation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to do the copy into conv_states and ssm_states as a first step and then do the block hash registration as a second step? And if so, maybe we could more effectively parallelize at least the copy into conv_states and ssm_states (maybe with a Triton kernel?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method has been completely rewritten into a pipeline of batch-operation sub-methods. I think the biggest improvement here comes from batching the slot allocation (allocate_slots_batch()), since this potentially results in eviction which is costly. please take another look.

lmcafee-nvidia and others added 4 commits March 19, 2026 06:07
…nd GPU syncs

- Replace per-layer state copy loop with all-layers-at-once [:, slot] indexing
- Replace per-block invalidate_block loop with batch _invalidate_blocks_batch
- Replace conv1d metadata Python loop with torch.repeat_interleave on GPU
- Replace while-loop padding with extend([x]*n) bulk allocation
- Replace inner while chunk boundary loop with list comprehension + extend

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…or reduced syncs

Replace 3 Python lists (_intermediate_offsets, _intermediate_block_ids,
_eos_cache_block_id) with fixed-size GPU tensors. Vectorize block ID
lookups via GPU gather, metadata computation via cumsum/masked indexing,
and hash fetching via batch .tolist(). Reduces ~24 .item() GPU syncs per
step to ~3 bulk transfers for 8 prefill requests with 2 offsets each.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ttr naming

- Extract hardcoded 3 to MAX_INTERMEDIATE_OFFSETS_PER_REQUEST constant
  with comment explaining the three candidates (KV divergence, last
  block-aligned, penultimate block boundaries).
- Expand "safe defaults" padding comment to explain why chunk_indices=0
  and abs_positions=d_conv are safe for CUDA graph replay.
- Remove leading underscore from intermediate_ssm_out, intermediate_conv_out,
  and conv_gather_offsets since they are accessed from mamba_mixer.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lmcafee-nvidia
lmcafee-nvidia added this pull request to the merge queue Mar 24, 2026
@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/23504961449

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 24, 2026
@lmcafee-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test aecc1da

@lmcafee-nvidia
lmcafee-nvidia added this pull request to the merge queue Mar 25, 2026
@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/23539131087

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 25, 2026
@lmcafee-nvidia
lmcafee-nvidia added this pull request to the merge queue Mar 25, 2026
@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/23541111332

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 25, 2026
@lmcafee-nvidia

Copy link
Copy Markdown
Contributor Author

/ok to test 2a6dcd4

@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/23546919235

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Mar 25, 2026
@lmcafee-nvidia
lmcafee-nvidia added this pull request to the merge queue Mar 25, 2026
@svcnvidia-nemo-ci

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started!

You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/23552861542

Merged via the queue into NVIDIA:main with commit d45fa3e Mar 25, 2026
62 of 63 checks passed
@lmcafee-nvidia
lmcafee-nvidia deleted the prefix-caching-mamba-cg branch March 25, 2026 17:21
yangbofun pushed a commit to xlm-research/Megatron-LM that referenced this pull request May 22, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
yhgalaxy pushed a commit to yhgalaxy/Megatron-LM that referenced this pull request Jun 17, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: yhgalaxy <yhgalaxy@outlook.com>
jon-barker pushed a commit to jon-barker/Megatron-LM that referenced this pull request Jul 10, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jon Barker <jbarker@aws-cmh-slurm-1-vscode-02.cm.cluster>
terminator123 pushed a commit to 021ai/Megatron-LM that referenced this pull request Aug 3, 2026
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
test — 2a6dcd41 Deployed Mar 25, 2026 by copy-pr-bot[bot] via cicd-wait-in-queue #10485
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Approved All necessary approvals have been made complexity: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants