[Misc] DeepGEMM : Avoid JIT generation in the hot-path - #22215
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels. Just a reminder: PRs would not trigger full CI run by default. Instead, it would only run Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add 🚀 |
There was a problem hiding this comment.
Code Review
This pull request refactors the DeepGEMM kernel warmup logic to avoid JIT compilation in the hot path of model inference. It introduces a dedicated warmup phase during model initialization. The changes are well-structured and correctly move the warmup logic. My main feedback is to improve the performance of one of the warmup loops, which could be excessively slow for large max_tokens values.
There was a problem hiding this comment.
Trigger for the DeepGEMM warmup kernels.
I have added a new folder vllm/warmup where we can add kernel warmup code going forward.
There was a problem hiding this comment.
I was initially thinking this would be in profile_run or capture_model in the model_runner, but I think this is a better place
There was a problem hiding this comment.
yeah. Didn't want to affect profile_run with arbitrary code that might mess up the peak memory usage.
There was a problem hiding this comment.
I was initially thinking this would be in profile_run or capture_model in the model_runner, but I think this is a better place
There was a problem hiding this comment.
Could you use _valid_deep_gemm_shape here?
There was a problem hiding this comment.
no. In addition to checking the weight dimensions _valid_deep_gemm_shape employs runtime heuristics on the M dimension which we don't have here.
There was a problem hiding this comment.
deep gemm can also be called by the triton fused_experts under the right conditions. not sure how easy that is to check though.
There was a problem hiding this comment.
deep gemm can also be called by the triton fused_experts under the right conditions
Hey @bnellnm I not sure which invocation you are referring to. Can you point me at it please.
If you are referring to TritonOrDeepGemmExperts ? I have a condition to handle below this.
There was a problem hiding this comment.
fused_experts in fused_moe.py at line ~1290 it can call deep_gemm_moe_fp8 if the flags+size are set properly. It might not be easy to check for this though.
There was a problem hiding this comment.
Oh I considered that. we return True here to account for that.
if module.quant_method.fused_experts is not a modular kernel, then we assume that we might be invoking deep_gemm kernels and conservatively do the warmup.
About checking for the exact set of conditions, it is hard to keep them in sync and I think it is instead better to default to doing the warmup.
- The actual jitting during the warmups is done only once per model. It should complete in a reasonable time. But if it is undesirable, users can always opt-out with the
VLLM_SKIP_DEEP_GEMM_WARMUPflag. - On subsequent runs, this loop should be fast as it'd just be only executing a series kernels.
what do you think ?
5900173 to
8a368d3
Compare
27cdc3a to
3e9397e
Compare
There was a problem hiding this comment.
Hi @zou3519 . The changes to this file is due to the lint-and-deploy CI job failing with,
(EngineCore_0 pid=34) File "/opt/venv/lib/python3.12/site-packages/vllm/model_executor/layers/fused_moe/fused_moe.py", line 1060, in <module>
(EngineCore_0 pid=34) direct_register_custom_op(
(EngineCore_0 pid=34) File "/opt/venv/lib/python3.12/site-packages/vllm/utils/__init__.py", line 2491, in direct_register_custom_op
(EngineCore_0 pid=34) schema_str = torch.library.infer_schema(op_func,
(EngineCore_0 pid=34) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(EngineCore_0 pid=34) File "/opt/venv/lib/python3.12/site-packages/torch/_library/infer_schema.py", line 106, in infer_schema
(EngineCore_0 pid=34) error_fn(
(EngineCore_0 pid=34) File "/opt/venv/lib/python3.12/site-packages/torch/_library/infer_schema.py", line 58, in error_fn
(EngineCore_0 pid=34) raise ValueError(
(EngineCore_0 pid=34) ValueError: infer_schema(func): Parameter block_shape has unsupported type typing.Optional[list[int]]. The valid types are: dict_keys([<class 'torch.Tensor'>, typing.Optional[torch.Tensor], typing.Sequence[torch.Tensor], typing.List[torch.Tensor], typing.Sequence[typing.Optional[torch.Tensor]], typing.List[typing.Optional[torch.Tensor]], <class 'int'>, typing.Optional[int], typing.Sequence[int], typing.List[int], typing.Optional[typing.Sequence[int]], typing.Optional[typing.List[int]], <class 'float'>, typing.Optional[float], typing.Sequence[float], typing.List[float], typing.Optional[typing.Sequence[float]], typing.Optional[typing.List[float]], <class 'bool'>, typing.Optional[bool], typing.Sequence[bool], typing.List[bool], typing.Optional[typing.Sequence[bool]], typing.Optional[typing.List[bool]], <class 'str'>, typing.Optional[str], typing.Union[int, float, bool], typing.Union[int, float, bool, NoneType], typing.Sequence[typing.Union[int, float, bool]], typing.List[typing.Union[int, float, bool]], <class 'torch.dtype'>, typing.Optional[torch.dtype], <class 'torch.device'>, typing.Optional[torch.device]]). Got func with signature (hidden_states: torch.Tensor, w1: torch.Tensor, w2: torch.Tensor, topk_weights: torch.Tensor, topk_ids: torch.Tensor, activation: str = 'silu', is_act_and_mul: bool = True, apply_router_weight_on_input: bool = False, use_fp8_w8a8: bool = False, use_int8_w8a8: bool = False, use_int8_w8a16: bool = False, use_int4_w4a16: bool = False, use_mxfp4_w4a4: bool = False, per_channel_quant: bool = False, global_num_experts: int = -1, expert_map: Optional[torch.Tensor] = None, w1_scale: Optional[torch.Tensor] = None, w2_scale: Optional[torch.Tensor] = None, w1_zp: Optional[torch.Tensor] = None, w2_zp: Optional[torch.Tensor] = None, a1_scale: Optional[torch.Tensor] = None, a2_scale: Optional[torch.Tensor] = None, block_shape: Optional[list[int]] = None) -> None)
example failing instance https://github.com/vllm-project/vllm/actions/runs/16761346188/job/47457097769?pr=22215
I did some debugging and it looks like the failure is triggered by the inspection of the fused_experts object in file deep_gemm_warmup.py and function _fused_moe_grouped_gemm_may_use_deep_gemm (Both added in this PR). I am not sure why the error wasn't triggered before. However, is this the right fix ? Appreciate any comments / thoughts to make this better. Thanks 🙌
There was a problem hiding this comment.
The fix is good. The behavior change is weird, infer_schema should accept both list and List. Is the lint job using the right version of PyTorch? (needs >= 2.6)
There was a problem hiding this comment.
Okay, the problem is that infer_schema doesn't support Optional[list[Tensor]], but it does support Optional[List[Tensor]]. infer_schema supports list[] in some other situations.
That being said, I don't know why the logic in this PR changed. It sounds like we were not calling infer_schema on inplace_fused_experts before, but now we are. Do you have a sense of why?
There was a problem hiding this comment.
It is not just inplace_fused_experts , but also outplace_fused_experts and flashinfer_fused_moe_blockscale_fp8. I had to use List in all of those prototype.
Like I mentioned before, it looks like inspecting module.quant_method.fused_experts triggers torch.library.infer_schema . Also, note that I don't run into this issue locally (using Nvidia GPUs), it seems to happen only the lint-and-deploy job that uses the vllm-cpu docker image.
Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
Head branch was pushed to by a user without write access
3e9397e to
dbd991c
Compare
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Signed-off-by: Jinzhen Lin <linjinzhen@hotmail.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Signed-off-by: Noam Gat <noamgat@gmail.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Signed-off-by: Paul Pak <paulpak58@gmail.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Signed-off-by: Diego-Castan <diego.castan@ibm.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Signed-off-by: Xiao Yu <xiao.yu@amd.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
…22215) Signed-off-by: Varun Sundar Rabindranath <vsundarr@redhat.com> Co-authored-by: Varun Sundar Rabindranath <vsundarr@redhat.com>
Purpose
DeepGemm JITs the its GEMM kernels. This JIT generation depends on the Gemm input tensor shapes. We want to avoid generating JITs during actual model inference. To this effect, this PR introduces a "Kernel Warmup" phase during which all the DeepGEMM kernels are invoked with possible input shapes for the model so all JIT generation is complete.
Test Plan
Notes:
fp8_gemm_ntwarmup took 83sm_grouped_fp8_gemm_nt_contiguouswarmup took 48sTest Result
Performance
IMPORTANT: Note that numbers are better with this PR. This simply means that
mainin steady-state (i.e. when run long enough to have all the kernels JIT'ed) will also produce these numbers.