[Bugfix] CustomAR + TritonAttn[AMPERE] + FULL_CG - gpt-oss#30650
[Bugfix] CustomAR + TritonAttn[AMPERE] + FULL_CG - gpt-oss#30650bbrowning wants to merge 1 commit intovllm-project:mainfrom
Conversation
Full CUDA graph capture + replay (the default since vLLM v0.11.0) could lead to memory correctness issues in the custom_all_reduce implementation due to previous logic that skipped running the actual all_reduce operation during the compile and warmup phase. This resulted in compile and warmup seeing a memory allocation, but not observing the custom op call or the actual reduce operation which could lead to optmizations being taken assuming purely functional code with no side-effects when in fact the reduce operation inherently has side effects. To fix this, instead of allocating an empty tensor to mimic the reduce operation, we now call the actual all_reduce during compile and warmup as well. Multiple users reported an issue that tracks back to this root cause on Ampere hardware, which is one platform where we use custom_all_reduce by default if tensor parallelism is used and NVLink is available. Examples: - vllm-project#26480 - vllm-project#29998 - vllm-project#30498 Note that until I rebased this on top of a very recent main, I also had to tag the all_reduce custom op registration in parallel_state.py with `torch.Tag.maybe_aliasing_or_mutating` to fix the reproducer described in vllm-project#29998. The tag is no longer required on latest main, although I have no identified exactly why or what changed that fixed that. Signed-off-by: Ben Browning <bbrownin@redhat.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
There was a problem hiding this comment.
Code Review
This pull request addresses a memory correctness issue in custom_all_reduce when using full CUDA graph capture. The previous implementation skipped the actual all-reduce operation during the warmup phase, leading to inconsistencies between warmup, capture, and replay, which could cause hangs. The fix correctly replaces the dummy tensor allocation with a call to the actual all_reduce operation during warmup. This ensures that the memory allocation, copy, and collective behaviors are consistent across all phases. The change is logical, well-explained, and directly resolves the reported bug. The code is clean and the fix is appropriate.
|
While all user reports of this that I've come across have been on Ampere hardware (A5500, A6000, A1000 80GB), I have also been able to reproduce this on H100 GPUs when Triton ATTN is in use. After reproducing the same issue on an H100 (by setting |
Thanks for the fix! Curious why skipping all_reduce operation would only cause problem for Triton ATTN? |
I'm not 100% sure that doesn't cause problems for other attention backends. However, the reproducers we've had reported from users all had Triton ATTN in common, and were all on Ampere hardware (where we use Triton ATTN by default). By manually forcing Triton ATTN on H100 hardware, I was also able to reproduce it there. There could theoretically be correctness issues with other attention backends in certain scenarios that this fixes, but I have no direct evidence of that myself. |
|
Hey @mgoin , could you please help review this PR? Thanks! |
|
I have been reliably producing this issue on 4x 40 GB A100 but not on 2x 80 GB H100 with the current master branch. I will let you know if this PR fixes this issue. |
| else: | ||
| # If warm up, mimic the allocation pattern since custom | ||
| # allreduce is out-of-place. | ||
| return torch.empty_like(input) |
There was a problem hiding this comment.
This could maybe accomplish the same thing if it was torch.zeros_like(input)? Initial tests seem promising, but I'm not sure how to interpret what that means as far as the root issue here and what this actually fixes.
|
So I was able to test this PR, and while it does prevent GPT OSS from simply generating nothing now, it appears that some bugs that were fixed in #28729 are back, particularly the one that I described where no final answer is produced I have also noticed a few scenarios where it seems like the model is outputting reasoning content in the content field. Attached is a request body you can reproduce the first issue where no final answer is produced: Here are the startup args I use for 4x A100 40gb, I use --async-scheduling as mentioned in the GPT OSS vLLM cookbook: And for 2x H100 80gb I have attached the raw output for the two different machines as well. My H100s are using the commit based on #28729 I did not specify my attention backend in either scenario, so I am using the default for H100, and for the A100, TRITON_ATTN is used. |
|
https://buildkite.com/vllm/ci/builds/44101#019b2fd3-5b62-45c0-8dee-44765da232a2 Can this PR fix this issue? |
|
@chaunceyjiang This fix is likely unrelated to that error. That error looks like maybe someone changed the way we generate harmony messages and forgot to update a test? But, those tests are testing for correctness, so it may be that the change itself is wrong and the test is right. The test wants 3 messages - one with a system role, one with a developer role, and one with a user role and specific content. It looks like something wrongly converted those to a single message instsead. |
|
I believe this is just a fancy bandaid of the underlying issue, and #30887 fixes the underlying issue with Triton attention and sliding window models (like gpt-oss). |
|
With the merging of #30887, I believe this fix is no longer needed. |
@bbRLdev I am looking into this using the sample request you gave to see if I can reproduce it on top of the latest main. I appreciate the detailed report, and it might be best to pull your comment out to a new issue so that we can properly track finding the root cause and solving what you're seeing. I believe you've hit on a separate real bug that we need to fix, as with your reproducer even in non-streaming mode I see the model is generating tool calls but we're not properly getting those back to the caller for whatever reason. |
|
@bbRLdev To fully track this down, I'll need to find the full parameters Cline is sending to vLLM here, including the |
|
hello, I meet something silimar, I'm trying to run gpt-oss-120b with EAGLE3 speculative decoding on vLLM, but getting CUDA errors during graph capture.
|
Purpose
Full CUDA graph capture + replay (the default since vLLM v0.11.0) could lead to memory correctness issues in the custom_all_reduce implementation due to previous logic that skipped running the actual all_reduce operation during the compile and warmup phase. This resulted in compile and warmup seeing a memory allocation, but not observing the custom op call or the actual reduce operation which could lead to optmizations being taken assuming purely functional code with no side-effects when in fact the reduce operation inherently has side effects.
To fix this, instead of allocating an empty tensor to mimic the reduce operation, we now call the actual all_reduce during compile and warmup as well.
Multiple users reported an issue that tracks back to this root cause on Ampere hardware, which is one platform where we use custom_all_reduce by default if tensor parallelism is used and NVLink is available.
Examples:
Note that until I rebased this on top of a very recent main, I also had to tag the all_reduce custom op registration in parallel_state.py with
torch.Tag.maybe_aliasing_or_mutatingto fix the reproducer described in #29998. The tag is no longer required on latest main, although I have not identified exactly why or what changed that fixed that.Test Plan
On Ampere hardware with NVLink enabled (2x A5500 in my case), start gpt-oss-20b with tensor-parallel-size 2:
Then, execute the curl reproducer from #29998 in a loop:
I also exercised the reproducer from #30498, slightly modified to point to gpt-oss-20b (instead of 120b) and to raise the max_tokens to 8192 as it was generating valid but verbose output for the first few iterations of the loop.
Test Result
Before this change, the 2nd time the curl loop from #29998 executed it always hung and the vLLM continued to generated token id 0 indefinitely. After this change, the 2nd and all subsequent curl requests succeed as expected.
Before this change, the the python requests loop from #30498 always hung by the 2nd or 3rd request. After this change, it continues to work for multiple subsequent requests.
I was able to successfully reproduce the test cases in both of those issues on my hardware and this change fixes both of those.