Skip to content

Commit 64a8b06

Browse files
authored
perf(nvidia): add opt-in Hopper long-context routing (#384)
## Summary - add an architecture-specific dispatch profile for NVIDIA Hopper - route full-attention to the CUDA vendor backend so FlashAttention-3 is selected - blacklist FlagGems `mm` and `mm_out` so dense projections use native CUDA GEMM - keep the optimization disabled by default; enable it with `VLLM_FL_HOPPER_LONG_CONTEXT_OPT=1` for direct A/B testing - preserve the existing NVIDIA configuration on non-Hopper devices and when capability probing is unavailable ## Motivation Nsight Systems analysis of a 16k-input serving workload showed two independent Hopper bottlenecks: - Triton unified-attention full prefill was about 11x slower than FA3 for the profiled head shape and accounted for 76.2% of the GPU-time gap. - FlagGems Hopper host-TMA `aten::mm.out` was slower than native dense GEMM for the projection shapes. The measured output throughput moved from 535.340 tok/s to 691.895 tok/s with the attention route alone, and to 785.631 tok/s with both routes enabled, reaching 96.09% of the native baseline. ## Usage ```bash # baseline behavior, also the default unset VLLM_FL_HOPPER_LONG_CONTEXT_OPT # Hopper optimized route export VLLM_FL_HOPPER_LONG_CONTEXT_OPT=1 ``` ## Validation - 44 dispatch/config/FlagGems unit tests passed in the vLLM 0.24.0 stack. - On an H100 process, flag off selected `nvidia.yaml`, FlagOS attention, and no `mm/mm_out` blacklist. - On the same H100 process, flag on selected `nvidia_hopper.yaml`, vendor attention, and the `mm/mm_out` blacklist. - Ruff and `git diff --check` passed.
1 parent 7cf3a7b commit 64a8b06

4 files changed

Lines changed: 140 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (c) 2026 BAAI. All rights reserved.
2+
3+
from types import SimpleNamespace
4+
from unittest.mock import patch
5+
6+
from vllm_fl.dispatch.config.utils import get_config_path, load_platform_config
7+
8+
9+
def _platform_with_capability(major: int, minor: int = 0):
10+
return SimpleNamespace(
11+
get_device_capability=lambda: SimpleNamespace(major=major, minor=minor)
12+
)
13+
14+
15+
def test_hopper_optimization_is_disabled_by_default(monkeypatch):
16+
monkeypatch.delenv("VLLM_FL_HOPPER_LONG_CONTEXT_OPT", raising=False)
17+
platform = _platform_with_capability(9)
18+
with patch("vllm.platforms.current_platform", platform):
19+
path = get_config_path("nvidia")
20+
config = load_platform_config("nvidia")
21+
22+
assert path is not None
23+
assert path.name == "nvidia.yaml"
24+
assert config["op_backends"]["attention_backend"][0] == "flagos"
25+
assert "mm" not in config["flagos_blacklist"]
26+
27+
28+
def test_hopper_uses_architecture_specific_config_when_enabled(monkeypatch):
29+
monkeypatch.setenv("VLLM_FL_HOPPER_LONG_CONTEXT_OPT", "1")
30+
platform = _platform_with_capability(9)
31+
with patch("vllm.platforms.current_platform", platform):
32+
path = get_config_path("nvidia")
33+
config = load_platform_config("nvidia")
34+
35+
assert path is not None
36+
assert path.name == "nvidia_hopper.yaml"
37+
assert config["op_backends"]["attention_backend"][0] == "vendor"
38+
assert {"mm", "mm_out"}.issubset(config["flagos_blacklist"])
39+
40+
41+
def test_non_hopper_nvidia_keeps_vendor_wide_config(monkeypatch):
42+
monkeypatch.setenv("VLLM_FL_HOPPER_LONG_CONTEXT_OPT", "1")
43+
platform = _platform_with_capability(8)
44+
with patch("vllm.platforms.current_platform", platform):
45+
path = get_config_path("nvidia")
46+
config = load_platform_config("nvidia")
47+
48+
assert path is not None
49+
assert path.name == "nvidia.yaml"
50+
assert config["op_backends"]["attention_backend"][0] == "flagos"
51+
assert "mm" not in config["flagos_blacklist"]
52+
53+
54+
def test_capability_probe_failure_falls_back_to_vendor_config(monkeypatch):
55+
monkeypatch.setenv("VLLM_FL_HOPPER_LONG_CONTEXT_OPT", "true")
56+
platform = SimpleNamespace(
57+
get_device_capability=lambda: (_ for _ in ()).throw(RuntimeError("no GPU"))
58+
)
59+
with patch("vllm.platforms.current_platform", platform):
60+
path = get_config_path("nvidia")
61+
62+
assert path is not None
63+
assert path.name == "nvidia.yaml"

vllm_fl/dispatch/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ Environment variables can override specific items from platform config. If not s
323323
| `VLLM_FL_PREFER` | `flagos` | Preferred backend: `flagos`, `vendor`, `reference` |
324324
| `VLLM_FL_STRICT` | `0` | Strict mode: `1` = fail on error, `0` = try fallback |
325325
| `VLLM_FL_PER_OP` | (none) | Per-operator order: `op1=a\|b\|c;op2=x\|y` |
326+
| `VLLM_FL_HOPPER_LONG_CONTEXT_OPT` | `0` | On NVIDIA Hopper, route attention to FA3 and `mm`/`mm_out` to native CUDA |
326327
| `VLLM_FL_ALLOW_VENDORS` | (none) | Vendor whitelist, comma-separated |
327328
| `VLLM_FL_DENY_VENDORS` | (none) | Vendor blacklist, comma-separated |
328329

@@ -385,6 +386,9 @@ export VLLM_FL_FLAGOS_WHITELIST="silu_and_mul,rms_norm"
385386
# Specify per-operator order
386387
export VLLM_FL_PER_OP="rms_norm=vendor|flagos|reference"
387388
389+
# Opt in to the NVIDIA Hopper long-context routing for an A/B run
390+
export VLLM_FL_HOPPER_LONG_CONTEXT_OPT=1
391+
388392
# Use completely custom config file
389393
export VLLM_FL_CONFIG=/path/to/my_config.yaml
390394
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# vLLM-FL Dispatch Configuration for NVIDIA Hopper GPUs
2+
3+
# Keep FlagOS as the default implementation and override only the operators
4+
# whose Hopper paths have a measured regression against the CUDA vendor stack.
5+
# This config is opt-in via VLLM_FL_HOPPER_LONG_CONTEXT_OPT=1.
6+
prefer: flagos
7+
strict: false
8+
9+
allow_vendors:
10+
- cuda
11+
12+
op_backends:
13+
# FlashAttention-3 is substantially faster than Triton unified attention
14+
# for long-context full-attention prefill on Hopper.
15+
attention_backend:
16+
- vendor
17+
- flagos
18+
- reference
19+
rms_norm:
20+
- flagos
21+
- vendor
22+
- reference
23+
silu_and_mul:
24+
- flagos
25+
- vendor
26+
- reference
27+
rotary_embedding:
28+
- flagos
29+
- vendor
30+
- reference
31+
32+
flagos_blacklist:
33+
- index_put_
34+
- index_put
35+
- _index_put_impl_
36+
- nonzero
37+
- copy_
38+
- to_copy
39+
- index
40+
# FlagGems' Hopper host-TMA mm.out path is slower than the native dense
41+
# GEMM for the long-context projection shapes used by vLLM.
42+
- mm
43+
- mm_out

vllm_fl/dispatch/config/utils.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@
4141
_CONFIG_DIR = Path(__file__).parent
4242

4343

44+
def _get_arch_config_name(platform: str) -> Optional[str]:
45+
"""Return an architecture-specific config name when one is available."""
46+
if platform != "nvidia":
47+
return None
48+
if os.environ.get("VLLM_FL_HOPPER_LONG_CONTEXT_OPT", "0").lower() not in (
49+
"1",
50+
"true",
51+
):
52+
return None
53+
54+
try:
55+
from vllm.platforms import current_platform
56+
57+
capability = current_platform.get_device_capability()
58+
except Exception:
59+
# Device discovery is not guaranteed to be available in API-only or
60+
# model-inspection processes. Fall back to the vendor-wide defaults.
61+
return None
62+
63+
if capability is not None and capability.major == 9:
64+
return "nvidia_hopper"
65+
return None
66+
67+
4468
def get_platform_name() -> str:
4569
"""
4670
Detect the current hardware platform.
@@ -75,6 +99,12 @@ def get_config_path(platform: Optional[str] = None) -> Optional[Path]:
7599
if platform is None:
76100
platform = get_platform_name()
77101

102+
arch_config = _get_arch_config_name(platform)
103+
if arch_config is not None:
104+
config_file = _CONFIG_DIR / f"{arch_config}.yaml"
105+
if config_file.exists():
106+
return config_file
107+
78108
# Try platform-specific config
79109
config_file = _CONFIG_DIR / f"{platform}.yaml"
80110
if config_file.exists():

0 commit comments

Comments
 (0)