Skip to content

AITER MLA backend: Avoid CPU sync in _build_decode - #35765

Merged
tjtanaa merged 11 commits into
vllm-project:mainfrom
pschlan-amd:rocm_aiter_mla_fix_sync
Mar 11, 2026
Merged

tjtanaa merged 11 commits into
vllm-project:mainfrom
pschlan-amd:rocm_aiter_mla_fix_sync

Conversation

@pschlan-amd

@pschlan-amd pschlan-amd commented Mar 2, 2026 •

Copy link
Copy Markdown
Contributor

This uses the same triton kernel as flashinfer.py to prevent a CPU sync when preparing the page_indices buffer.

NOTE: This is my first time working on this type of code, and I'd appreciate thorough reviews.

Purpose

Fix a long sync when running _build_decode. This was found during profiling.

Before the change:
image

After the change:
image

(not up to scale)

Test Plan

  • Ran DeepSeek R1 inference pre and post change
  • Captured inference output and profile

Test Result

  • Profile improved (see above), sync is gone
  • Inference output still makes sense and looks coherent

Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • The test plan, such as providing test command.
  • The test results, such as pasting the results comparison before and after, or e2e results
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model.
  • (Optional) Release notes update. If your change is user facing, please update the release notes draft in the Google Doc.

This uses the same triton kernel as flashinfer.py to prevent
a CPU sync when preparing the page_indices buffer.

Signed-off-by: Patrick Schlangen <pschlan@amd.com>
@mergify mergify Bot added rocm Related to AMD ROCm v1 labels Mar 2, 2026
@github-project-automation github-project-automation Bot moved this to Todo in AMD Mar 2, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request successfully resolves a CPU synchronization issue in the ROCm AITer MLA backend by replacing a data-dependent indexing operation with a custom Triton kernel. The approach is sound and aligns with the PR's objective. I've identified a potential critical issue in the new Triton kernel related to memory access patterns, which could lead to incorrect behavior if the block_table_tensor is not contiguous on its last dimension. My suggestion makes the kernel more robust by explicitly handling tensor strides.

Comment on lines +187 to +213
@triton.jit
def _copy_page_indices_kernel(
page_indices,
block_table,
block_table_stride,
cu_num_blocks,
BLOCK_SIZE: tl.constexpr,
):
"""Copy block table rows into a flat page_indices buffer using indptr.
Avoids blocking boolean mask indexing (tensor[mask]) which has
data-dependent output size and forces sync.
This is the same kernel as introduced in backends/flashinfer.py.
"""
req_idx = tl.program_id(0)
row_ptr = block_table + req_idx * block_table_stride
start_idx = tl.load(cu_num_blocks + req_idx)
end_idx = tl.load(cu_num_blocks + req_idx + 1)
num_blocks = end_idx - start_idx

offset = tl.arange(0, BLOCK_SIZE)
for i in tl.range(0, num_blocks, BLOCK_SIZE):
block_ids = tl.load(row_ptr + i + offset, mask=i + offset < num_blocks)
tl.store(
page_indices + start_idx + i + offset,
block_ids,
mask=i + offset < num_blocks,
)

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.

critical

The new Triton kernel _copy_page_indices_kernel assumes that the block_table tensor is contiguous along its last dimension (i.e., stride(1) == 1) because it uses simple pointer arithmetic (row_ptr + i + offset) to access elements within a row. If block_table_tensor is ever a non-contiguous view (e.g., from transpose or advanced indexing), this kernel will read incorrect data, leading to silent correctness issues or crashes.

To make the kernel more robust, it's better to explicitly use the stride of the second dimension for memory access. This ensures correctness regardless of the tensor's memory layout.

@triton.jit
def _copy_page_indices_kernel(
    page_indices,
    block_table,
    block_table_stride_0,
    block_table_stride_1,
    cu_num_blocks,
    BLOCK_SIZE: tl.constexpr,
):
    """Copy block table rows into a flat page_indices buffer using indptr.
    Avoids blocking boolean mask indexing (tensor[mask]) which has
    data-dependent output size and forces sync.
    This is the same kernel as introduced in backends/flashinfer.py.
    """
    req_idx = tl.program_id(0)
    row_ptr = block_table + req_idx * block_table_stride_0
    start_idx = tl.load(cu_num_blocks + req_idx)
    end_idx = tl.load(cu_num_blocks + req_idx + 1)
    num_blocks = end_idx - start_idx

    offset = tl.arange(0, BLOCK_SIZE)
    for i in tl.range(0, num_blocks, BLOCK_SIZE):
        current_offsets = i + offset
        mask = current_offsets < num_blocks
        block_ids = tl.load(row_ptr + current_offsets * block_table_stride_1, mask=mask)
        tl.store(
            page_indices + start_idx + current_offsets,
            block_ids,
            mask=mask,
        )

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 doesn't seem to be a concern in flashinfer (where this kernel is invented), but will try to check the codebase if this can become an issue

Comment on lines +142 to +148
_copy_page_indices_kernel[(num_reqs,)](
self.paged_kv_indices,
block_table_tensor,
block_table_tensor.stride(0),
paged_kv_indptr,
BLOCK_SIZE=1024,
)

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.

critical

To support the suggested change in the _copy_page_indices_kernel, you'll need to pass block_table_tensor.stride(1) to the kernel as well.

Suggested change
_copy_page_indices_kernel[(num_reqs,)](
self.paged_kv_indices,
block_table_tensor,
block_table_tensor.stride(0),
paged_kv_indptr,
BLOCK_SIZE=1024,
)
_copy_page_indices_kernel[(num_reqs,)](
self.paged_kv_indices,
block_table_tensor,
block_table_tensor.stride(0),
block_table_tensor.stride(1),
paged_kv_indptr,
BLOCK_SIZE=1024,
)

@pschlan-amd pschlan-amd changed the title Rocm aiter mla fix sync AITER MLA backend: Fix CPU sync in _build_decode Mar 2, 2026
@pschlan-amd pschlan-amd changed the title AITER MLA backend: Fix CPU sync in _build_decode AITER MLA backend: Avoid CPU sync in _build_decode Mar 2, 2026
@pschlan-amd
pschlan-amd marked this pull request as ready for review March 4, 2026 09:15
@pschlan-amd
pschlan-amd requested a review from tjtanaa as a code owner March 4, 2026 09:15
@tjtanaa

tjtanaa commented Mar 5, 2026

Copy link
Copy Markdown
Member

@pschlan-amd I think it looks good. Before approving can you share the lm_eval score of DeepSeek-R1 model after this changes? and also share end-to-end benchmark metrics to show the perf gain?

@pschlan-amd

pschlan-amd commented Mar 5, 2026 •

Copy link
Copy Markdown
Contributor Author

@pschlan-amd I think it looks good. Before approving can you share the lm_eval score of DeepSeek-R1 model after this changes? and also share end-to-end benchmark metrics to show the perf gain?

Thanks for checking!

I ran lm_eval / gsm8k against DeepSeek-R1-0528, TP=8 on a test system with 8x MI355X.

Pre change

|Tasks|Version|     Filter     |n-shot|  Metric   |   |Value|   |Stderr|
|-----|------:|----------------|-----:|-----------|---|----:|---|-----:|
|gsm8k|      3|flexible-extract|     5|exact_match|↑  |0.956|±  |0.0056|
|     |       |strict-match    |     5|exact_match|↑  |0.956|±  |0.0056|

Post change

|Tasks|Version|     Filter     |n-shot|  Metric   |   |Value |   |Stderr|
|-----|------:|----------------|-----:|-----------|---|-----:|---|-----:|
|gsm8k|      3|flexible-extract|     5|exact_match|↑  |0.9591|±  |0.0055|
|     |       |strict-match    |     5|exact_match|↑  |0.9568|±  |0.0056|

Latency benchmark results (vllm bench latency) with the same model:

Pre change

Avg latency: 1.9370135884266346 seconds
10% percentile latency: 1.9240199869964272 seconds
25% percentile latency: 1.9261687785037793 seconds
50% percentile latency: 1.9353763204999268 seconds
75% percentile latency: 1.9445194983272813 seconds
90% percentile latency: 1.951035475707613 seconds
99% percentile latency: 1.967707827873528 seconds

Post change

Avg latency: 1.9219131177679325 seconds
10% percentile latency: 1.8991735702380539 seconds
25% percentile latency: 1.9077737962361425 seconds
50% percentile latency: 1.9222694630734622 seconds
75% percentile latency: 1.9336206344305538 seconds
90% percentile latency: 1.9377175537403672 seconds
99% percentile latency: 1.9586094858613796 seconds

@tjtanaa tjtanaa added the ready ONLY add when PR is ready to merge/full CI is needed label Mar 6, 2026

@tjtanaa tjtanaa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@tjtanaa
tjtanaa enabled auto-merge (squash) March 6, 2026 15:59
@tjtanaa
tjtanaa merged commit eac2dc2 into vllm-project:main Mar 11, 2026
52 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in AMD Mar 11, 2026
@pschlan-amd
pschlan-amd deleted the rocm_aiter_mla_fix_sync branch March 11, 2026 07:48
wendyliu235 pushed a commit to wendyliu235/vllm-public that referenced this pull request Mar 18, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
khairulkabir1661 pushed a commit to khairulkabir1661/vllm that referenced this pull request Mar 27, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
mtparet pushed a commit to blackfuel-ai/vllm that referenced this pull request Apr 9, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
mystous pushed a commit to mystous/vllm_hybrid that referenced this pull request May 10, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
my-other-github-account pushed a commit to my-other-github-account/vllm that referenced this pull request May 15, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
0826joyce pushed a commit to 0826joyce/vllm-serving-optimization that referenced this pull request May 19, 2026
Signed-off-by: Patrick Schlangen <pschlan@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready ONLY add when PR is ready to merge/full CI is needed rocm Related to AMD ROCm v1

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants