Skip to content

Commit 0c2952e

Browse files
authored
[None][fix] DSA indexer: persistent topk-output buffer to avoid CUDA-graph stale-pointer IMA (NVIDIA#16290)
Signed-off-by: Iman Tabrizian <10105175+tabrizian@users.noreply.github.com>
1 parent f81b9d2 commit 0c2952e

2 files changed

Lines changed: 86 additions & 2 deletions

File tree

tensorrt_llm/_torch/attention_backend/sparse/dsa.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,10 +2388,12 @@ def sparse_attn_indexer(
23882388
has_prefill = num_contexts > 0
23892389
num_gen_tokens = num_tokens - num_ctx_tokens
23902390

2391-
topk_indices_buffer = torch.empty(
2391+
topk_indices_buffer = metadata.get_empty(
2392+
metadata.cuda_graph_buffers,
23922393
(hidden_states.shape[0], self.index_topk),
2394+
cache_name="indexer_topk_out_buffer",
23932395
dtype=torch.int32,
2394-
device=hidden_states.device)
2396+
capture_graph=metadata.is_cuda_graph)
23952397
if not use_custom_topk:
23962398
topk_indices_buffer[:hidden_states.shape[0]] = -1
23972399

tests/unittest/_torch/attention/sparse/dsa/test_dsa_indexer.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3163,3 +3163,85 @@ def test_prepare_swaps_and_restore_recovers(self):
31633163
assert meta.kv_cache_manager is original_kv_mgr
31643164
torch.testing.assert_close(meta.kv_cache_block_offsets, original_offsets)
31653165
torch.testing.assert_close(meta.host_kv_cache_block_offsets, original_host_offsets)
3166+
3167+
3168+
@pytest.mark.skipif(not has_deep_gemm(), reason="DeepGEMM not available")
3169+
@skip_pre_hopper
3170+
def test_topk_indices_buffer_cuda_graph():
3171+
from tensorrt_llm._torch.memory_buffer_utils import Buffers
3172+
3173+
batch_size, next_n = 4, 3
3174+
head_dim, block_size = 128, 64
3175+
index_topk = 2048
3176+
kv_len = 512
3177+
layer_idx = 0
3178+
num_tokens = batch_size * next_n
3179+
3180+
cache_manager, sparse_attn_config = create_dsa_cache_manager(
3181+
batch_size=batch_size,
3182+
head_dim=head_dim,
3183+
tokens_per_block=block_size,
3184+
max_seq_len=kv_len,
3185+
num_layers=1,
3186+
index_topk=index_topk,
3187+
)
3188+
indexer = create_indexer(sparse_attn_config, layer_idx=layer_idx)
3189+
3190+
request_ids = list(range(batch_size))
3191+
kv_lens = torch.tensor([kv_len] * batch_size, dtype=torch.int32)
3192+
cache_manager.add_dummy_requests(
3193+
request_ids=request_ids,
3194+
token_nums=kv_lens.tolist(),
3195+
is_gen=False,
3196+
prepare_resource=True,
3197+
)
3198+
3199+
metadata = _create_mock_metadata(
3200+
request_ids,
3201+
batch_size,
3202+
num_contexts=0,
3203+
num_generations=batch_size,
3204+
seq_lens=torch.tensor([next_n] * batch_size, dtype=torch.int32),
3205+
kv_lens=kv_lens.clone(),
3206+
num_cached_tokens=[kv_len - next_n] * batch_size,
3207+
cache_manager=cache_manager,
3208+
num_ctx_tokens=0,
3209+
num_tokens=num_tokens,
3210+
max_draft_tokens=next_n - 1,
3211+
index_topk=index_topk,
3212+
enable_indexer_skip=True,
3213+
)
3214+
assert metadata.skip_indexer_for_gen_reqs, (
3215+
"test setup must hit the skip-indexer path (kv_len <= index_topk)"
3216+
)
3217+
3218+
metadata.is_cuda_graph = True
3219+
metadata.cuda_graph_buffers = Buffers()
3220+
3221+
hidden_states = torch.zeros((num_tokens, 1), device="cuda", dtype=torch.bfloat16)
3222+
dummy = torch.zeros((num_tokens, 1), device="cuda", dtype=torch.bfloat16)
3223+
3224+
def _run_indexer():
3225+
return indexer.sparse_attn_indexer(
3226+
metadata,
3227+
hidden_states,
3228+
q_fp8=dummy,
3229+
k_fp8=dummy,
3230+
k_scale=dummy,
3231+
weights=dummy,
3232+
update_k_cache=False,
3233+
)
3234+
3235+
out1 = _run_indexer()
3236+
ptr1 = out1.data_ptr()
3237+
out2 = _run_indexer()
3238+
ptr2 = out2.data_ptr()
3239+
3240+
assert ptr1 == ptr2, (
3241+
f"indexer topk-output buffer address changed across calls "
3242+
f"({ptr1:#x} -> {ptr2:#x}); under CUDA-graph capture it must be a "
3243+
f"persistent reserved-arena buffer to avoid stale-pointer IMA"
3244+
)
3245+
assert "indexer_topk_out_buffer" in metadata.cuda_graph_buffers.buffers, (
3246+
"indexer topk-output buffer must be drawn from the cuda_graph_buffers arena"
3247+
)

0 commit comments

Comments
 (0)