[ROCm] Remove stale SDPA and skinny GEMM workarounds (#50907)
Signed-off-by: Andreas Karatzas <Andreas.Karatzas@amd.com> Signed-off-by: Andreas Karatzas <akaratza@amd.com> Co-authored-by: OpenAI Codex <codex@openai.com>
Andreas Karatzas committed
Aug 11, 2026 at 13:19 UTC
1ab2801ddebe31b75dd6022c69113b610bbdc950
56 files changed
+500
-558
csrc/libtorch_stable/moe/moe_align_sum_kernels.cu
+3
-1
@@ -532,7 +532,9 @@ __global__ void moe_lora_align_block_size_kernel(
532
533
// Populate the token_mask based on the token-LoRA mapping
534
int num_tokens = numel / topk_num;
535
- if (threadIdx.x == 0) {
535
+ // Only the even counting block owns per-LoRA metadata. The odd block only
536
+ // initializes sorted_token_ids and must not race the final count write.
537
+ if (blockIdx.x % 2 == 0 && threadIdx.x == 0) {
538
total_tokens_post_pad[lora_id] = 0;
539
540
for (int i = 0; i < num_tokens; i++) {
examples/rl/rlhf_async_new_apis.py
-2
@@ -173,8 +173,6 @@ ray_env_vars = {}
173
if current_platform.is_rocm():
174
# Workaround for RCCL bug. See https://github.com/ROCm/rocm-systems/issues/5756
175
ray_env_vars["RAY_EXPERIMENTAL_NOSET_HIP_VISIBLE_DEVICES"] = "1"
176
- # For ROCm, BATCH_INVARIANT vllm is not supported
177
- ray_env_vars["VLLM_ROCM_USE_SKINNY_GEMM"] = "0"
176
else:
177
# Enable batch invariance for deterministic outputs on NVIDIA
178
ray_env_vars["VLLM_BATCH_INVARIANT"] = "1"
tests/entrypoints/multimodal/openai/chat_completion/test_vision.py
+1
-2
@@ -9,7 +9,7 @@ import pytest_asyncio
9
from transformers import AutoProcessor
10
11
from tests.entrypoints.multimodal.conftest import TEST_IMAGE_ASSETS
12
-from tests.utils import ROCM_ENV_OVERRIDES, ROCM_EXTRA_ARGS, RemoteOpenAIServer
12
+from tests.utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
13
from vllm.multimodal.media import MediaWithBytes
14
from vllm.multimodal.utils import encode_image_url, fetch_image
15
from vllm.platforms import current_platform
@@ -92,7 +92,6 @@ def server():
92
# ROCm: Increase timeouts to handle potential network delays and slower
93
# video processing when downloading multiple videos from external sources
94
env_overrides = {
95
- **ROCM_ENV_OVERRIDES,
95
**(
96
{
97
"VLLM_VIDEO_FETCH_TIMEOUT": "120",
tests/entrypoints/openai/chat_completion/test_completion_with_function_calling.py
+2
-4
@@ -10,7 +10,7 @@ import pytest
10
import pytest_asyncio
11
12
# downloading lora to test lora requests
13
-from tests.utils import ROCM_ENV_OVERRIDES, ROCM_EXTRA_ARGS, RemoteOpenAIServer
13
+from tests.utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
14
15
# any model with a chat template should work here
16
MODEL_NAME = "Qwen/Qwen3-0.6B"
@@ -144,9 +144,7 @@ def server():
144
"--enforce-eager",
145
] + ROCM_EXTRA_ARGS
146
147
- with RemoteOpenAIServer(
148
- MODEL_NAME, args, env_dict=ROCM_ENV_OVERRIDES
149
- ) as remote_server:
147
+ with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
148
yield remote_server
149
150
tests/entrypoints/pooling/basic/test_encode.py
-8
@@ -7,7 +7,6 @@ import pytest
7
8
from vllm import LLM, PoolingParams
9
from vllm.distributed import cleanup_dist_env_and_memory
10
-from vllm.platforms import current_platform
10
11
MODEL_NAME = "intfloat/multilingual-e5-small"
12
@@ -30,12 +29,6 @@ TOKEN_IDS = [
29
30
@pytest.fixture(scope="module")
31
def llm():
33
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
34
- # that supports encoder-only models on ROCm.
35
- attention_config = None
36
- if current_platform.is_rocm():
37
- attention_config = {"backend": "FLEX_ATTENTION"}
38
-
32
# pytest caches the fixture so we use weakref.proxy to
33
# enable garbage collection
34
llm = LLM(
@@ -45,7 +38,6 @@ def llm():
38
gpu_memory_utilization=0.75,
39
enforce_eager=True,
40
seed=0,
48
- attention_config=attention_config,
41
)
42
43
yield weakref.proxy(llm)
tests/entrypoints/pooling/basic/test_truncation.py
-5
@@ -7,7 +7,6 @@ import pytest
7
import pytest_asyncio
8
9
from tests.utils import RemoteOpenAIServer
10
-from vllm.platforms import current_platform
10
11
MODEL_NAME = "sentence-transformers/all-MiniLM-L12-v2"
12
max_model_len = 128
@@ -39,10 +38,6 @@ def server():
38
str(max_model_len),
39
]
40
42
- # ROCm: Use Flex Attention to support encoder-only self-attention.
43
- if current_platform.is_rocm():
44
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
45
-
41
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
42
yield remote_server
43
tests/entrypoints/pooling/embed/conftest.py
deleted
-28
@@ -1,28 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Pytest configuration for vLLM pooling embed tests."""
4
-
5
-import warnings
6
-
7
-import torch
8
-
9
-from vllm.platforms import current_platform
10
-
11
-
12
-def pytest_collection_modifyitems(config, items):
13
- """Configure ROCm-specific settings based on collected tests."""
14
- if not current_platform.is_rocm():
15
- return
16
-
17
- # Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
18
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
19
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
20
- torch.backends.cuda.enable_flash_sdp(False)
21
- torch.backends.cuda.enable_mem_efficient_sdp(False)
22
- torch.backends.cuda.enable_math_sdp(True)
23
- warnings.warn(
24
- "ROCm: Disabled flash_sdp and mem_efficient_sdp, enabled math_sdp "
25
- "to avoid HuggingFace Transformers accuracy issues",
26
- UserWarning,
27
- stacklevel=1,
28
- )
tests/entrypoints/pooling/embed/test_correctness_mteb.py
-5
@@ -11,7 +11,6 @@ from tests.models.language.pooling_mteb_test.mteb_embed_utils import (
11
run_mteb_embed_task,
12
)
13
from tests.utils import RemoteOpenAIServer
14
-from vllm.platforms import current_platform
14
15
os.environ["VLLM_LOGGING_LEVEL"] = "WARNING"
16
@@ -23,10 +22,6 @@ MAIN_SCORE = 0.7422994752439667
22
def server():
23
args = ["--runner", "pooling", "--enforce-eager", "--disable-uvicorn-access-log"]
24
26
- # ROCm: Use Flex Attention to support encoder-only self-attention.
27
- if current_platform.is_rocm():
28
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
29
-
25
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
26
yield remote_server
27
tests/entrypoints/pooling/embed/test_offline.py
-8
@@ -8,7 +8,6 @@ import torch.nn.functional as F
8
9
from vllm import LLM, EmbeddingRequestOutput, PoolingParams
10
from vllm.distributed import cleanup_dist_env_and_memory
11
-from vllm.platforms import current_platform
11
from vllm.tasks import PoolingTask
12
13
MODEL_NAME = "intfloat/multilingual-e5-small"
@@ -20,12 +19,6 @@ embedding_size = 384
19
20
@pytest.fixture(scope="module")
21
def llm():
23
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
24
- # that supports encoder-only models on ROCm.
25
- attention_config = None
26
- if current_platform.is_rocm():
27
- attention_config = {"backend": "FLEX_ATTENTION"}
28
-
22
# pytest caches the fixture so we use weakref.proxy to
23
# enable garbage collection
24
llm = LLM(
@@ -35,7 +28,6 @@ def llm():
28
gpu_memory_utilization=0.75,
29
enforce_eager=True,
30
seed=0,
38
- attention_config=attention_config,
31
)
32
assert embedding_size == llm.model_config.embedding_size
33
tests/entrypoints/pooling/embed/test_online.py
+9
-11
@@ -50,14 +50,6 @@ input_tokens = [
50
2,
51
]
52
53
-if current_platform.is_rocm():
54
- # Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
55
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
56
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
57
- torch.backends.cuda.enable_flash_sdp(False)
58
- torch.backends.cuda.enable_mem_efficient_sdp(False)
59
- torch.backends.cuda.enable_math_sdp(True)
60
-
53
# On ROCm, floating-point reductions in attention and GEMM kernels are
54
# non-associative and sensitive to batch geometry. Force LLM instances
55
# into an identical, deterministic execution mode:
@@ -507,11 +499,17 @@ async def test_base64_embedding(hf_model, client: openai.AsyncOpenAI, model_name
499
"The best thing about vLLM is that it supports many different models",
500
]
501
502
+ def check_outputs(outputs: list[list[float]]) -> None:
503
+ # The embeddings endpoint executes list elements as separate scheduler
504
+ # requests, so use the same per-request geometry for the HF reference.
505
+ for input_text, output in zip(input_texts, outputs, strict=True):
506
+ run_embedding_correctness_test(hf_model, [input_text], [output])
507
+
508
responses_float = await client.embeddings.create(
509
input=input_texts, model=model_name, encoding_format="float"
510
)
511
float_data = [d.embedding for d in responses_float.data]
514
- run_embedding_correctness_test(hf_model, input_texts, float_data)
512
+ check_outputs(float_data)
513
514
responses_base64 = await client.embeddings.create(
515
input=input_texts, model=model_name, encoding_format="base64"
@@ -522,14 +520,14 @@ async def test_base64_embedding(hf_model, client: openai.AsyncOpenAI, model_name
520
np.frombuffer(base64.b64decode(data.embedding), dtype="float32").tolist()
521
)
522
525
- run_embedding_correctness_test(hf_model, input_texts, base64_data)
523
+ check_outputs(base64_data)
524
525
# Default response is float32 decoded from base64 by OpenAI Client
526
responses_default = await client.embeddings.create(
527
input=input_texts, model=model_name
528
)
529
default_data = [d.embedding for d in responses_default.data]
532
- run_embedding_correctness_test(hf_model, input_texts, default_data)
530
+ check_outputs(default_data)
531
532
533
@pytest.mark.asyncio
tests/entrypoints/pooling/embed/test_online_dimensions.py
-5
@@ -12,7 +12,6 @@ from tests.models.language.pooling.embed_utils import run_embedding_correctness_
12
from tests.models.utils import EmbedModelInfo
13
from tests.utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
14
from vllm.entrypoints.pooling.embed.protocol import EmbeddingResponse
15
-from vllm.platforms import current_platform
15
16
MODELS = [
17
EmbedModelInfo("intfloat/multilingual-e5-small", is_matryoshka=False),
@@ -57,10 +56,6 @@ def server(model_info, dtype: str):
56
["--trust_remote_code", "--hf_overrides", '{"matryoshka_dimensions":[256]}']
57
)
58
60
- # ROCm: Use Flex Attention to support encoder-only self-attention.
61
- if current_platform.is_rocm():
62
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
63
-
59
with RemoteOpenAIServer(model_info.name, args) as remote_server:
60
yield remote_server
61
tests/entrypoints/pooling/embed/test_online_long_text.py
-5
@@ -16,7 +16,6 @@ import pytest_asyncio
16
17
from tests.utils import RemoteOpenAIServer
18
from vllm.entrypoints.pooling.embed.protocol import EmbeddingResponse
19
-from vllm.platforms import current_platform
19
20
21
def _generate_random_text(word_count: int) -> str:
@@ -225,10 +224,6 @@ def server_with_chunked_processing():
224
"0.8",
225
]
226
228
- # ROCm: Use Flex Attention to support encoder-only self-attention.
229
- if current_platform.is_rocm():
230
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
231
-
227
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
228
yield remote_server
229
tests/entrypoints/pooling/scoring/test_bi_encoder_offline.py
-8
@@ -8,7 +8,6 @@ import pytest
8
from tests.entrypoints.pooling.scoring.util import EncoderScoringHfRunner
9
from vllm import LLM
10
from vllm.distributed import cleanup_dist_env_and_memory
11
-from vllm.platforms import current_platform
11
12
MODEL_NAME = "intfloat/multilingual-e5-small"
13
PROMPT = "The chef prepared a delicious meal."
@@ -29,12 +28,6 @@ DTYPE = "half"
28
29
@pytest.fixture(scope="module")
30
def llm():
32
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
33
- # that supports encoder-only models on ROCm.
34
- attention_config = None
35
- if current_platform.is_rocm():
36
- attention_config = {"backend": "FLEX_ATTENTION"}
37
-
31
# pytest caches the fixture so we use weakref.proxy to
32
# enable garbage collection
33
llm = LLM(
@@ -44,7 +37,6 @@ def llm():
37
gpu_memory_utilization=0.75,
38
enforce_eager=True,
39
seed=0,
47
- attention_config=attention_config,
40
)
41
42
yield weakref.proxy(llm)
tests/entrypoints/pooling/scoring/test_bi_encoder_online.py
-5
@@ -8,7 +8,6 @@ from tests.entrypoints.pooling.scoring.util import EncoderScoringHfRunner
8
from tests.utils import RemoteOpenAIServer
9
from vllm.entrypoints.pooling.pooling.protocol import PoolingResponse
10
from vllm.entrypoints.pooling.scoring.protocol import RerankResponse, ScoreResponse
11
-from vllm.platforms import current_platform
11
12
MODEL_NAME = "BAAI/bge-base-en-v1.5"
13
input_text = "This product was excellent and exceeded my expectations"
@@ -30,10 +29,6 @@ TEXTS_2 = [
29
def server():
30
args = ["--enforce-eager", "--max-model-len", "100", "--dtype", DTYPE]
31
33
- # ROCm: Use Flex Attention to support encoder-only self-attention.
34
- if current_platform.is_rocm():
35
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
36
-
32
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
33
yield remote_server
34
tests/entrypoints/pooling/scoring/test_cross_encoder_correctness_mteb.py
-5
@@ -13,7 +13,6 @@ from tests.models.language.pooling_mteb_test.mteb_score_utils import (
13
run_mteb_rerank,
14
)
15
from tests.utils import RemoteOpenAIServer
16
-from vllm.platforms import current_platform
16
17
os.environ["VLLM_LOGGING_LEVEL"] = "WARNING"
18
@@ -25,10 +24,6 @@ st_main_score = 0.33457
24
def server():
25
args = ["--runner", "pooling", "--enforce-eager", "--disable-uvicorn-access-log"]
26
28
- # ROCm: Use Flex Attention to support encoder-only self-attention.
29
- if current_platform.is_rocm():
30
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
31
-
27
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
28
yield remote_server
29
tests/entrypoints/pooling/scoring/test_cross_encoder_offline.py
-8
@@ -9,7 +9,6 @@ import torch
9
from tests.models.utils import softmax
10
from vllm import LLM, PoolingParams
11
from vllm.distributed import cleanup_dist_env_and_memory
12
-from vllm.platforms import current_platform
12
13
MODEL_NAME = "tomaarsen/Qwen3-Reranker-0.6B-seq-cls"
14
PROMPT = "The chef prepared a delicious meal."
@@ -26,12 +25,6 @@ TEXTS_2 = [
25
26
@pytest.fixture(scope="module")
27
def llm():
29
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
30
- # that supports encoder-only models on ROCm.
31
- attention_config = None
32
- if current_platform.is_rocm():
33
- attention_config = {"backend": "FLEX_ATTENTION"}
34
-
28
# pytest caches the fixture so we use weakref.proxy to
29
# enable garbage collection
30
llm = LLM(
@@ -41,7 +34,6 @@ def llm():
34
gpu_memory_utilization=0.75,
35
enforce_eager=True,
36
seed=0,
44
- attention_config=attention_config,
37
)
38
39
yield weakref.proxy(llm)
tests/entrypoints/pooling/scoring/test_cross_encoder_online.py
-5
@@ -9,7 +9,6 @@ import torch.nn.functional as F
9
from tests.utils import RemoteOpenAIServer
10
from vllm.entrypoints.pooling.pooling.protocol import PoolingResponse
11
from vllm.entrypoints.pooling.scoring.protocol import RerankResponse, ScoreResponse
12
-from vllm.platforms import current_platform
12
13
MODEL_NAME = "BAAI/bge-reranker-base"
14
DTYPE = "half"
@@ -32,10 +31,6 @@ TEXTS_2 = [
31
def server():
32
args = ["--enforce-eager", "--max-model-len", "100", "--dtype", DTYPE]
33
35
- # ROCm: Use Flex Attention to support encoder-only self-attention.
36
- if current_platform.is_rocm():
37
- args.extend(["--attention-backend", "FLEX_ATTENTION"])
38
-
34
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
35
yield remote_server
36
tests/entrypoints/pooling/scoring/test_cross_encoder_online_vision.py
-7
@@ -53,12 +53,6 @@ BACKEND_ABS_TOL: dict[str, float] = {
53
"FLEX_ATTENTION": 0.006,
54
}
55
56
-# ROCm: disable skinny GEMM to avoid non-deterministic results from
57
-# atomic reductions in wvSplitKrc kernel.
58
-# See: https://github.com/vllm-project/vllm/pull/33493#issuecomment-3906083975
59
-ROCM_ENV_OVERRIDES = (
60
- {"VLLM_ROCM_USE_SKINNY_GEMM": "0"} if current_platform.is_rocm() else {}
61
-)
56
# ROCm: disable prefix caching and eliminate batch variance to reduce
57
# test flakiness.
58
ROCM_EXTRA_ARGS = (
@@ -132,7 +126,6 @@ def server(request):
126
args += ["--attention-config", json.dumps({"backend": backend})]
127
args += ROCM_EXTRA_ARGS
128
135
- env = dict(ROCM_ENV_OVERRIDES)
129
if backend != "ROCM_AITER_FA":
130
env["VLLM_ROCM_USE_AITER"] = "0"
131
tests/entrypoints/pooling/scoring/test_late_interaction_offline.py
-8
@@ -7,7 +7,6 @@ import pytest
7
8
from vllm import LLM
9
from vllm.distributed import cleanup_dist_env_and_memory
10
-from vllm.platforms import current_platform
10
11
from .util import ColBERTScoringHfRunner
12
@@ -32,12 +31,6 @@ DTYPE = "half"
31
32
@pytest.fixture(scope="module")
33
def llm():
35
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
36
- # that supports encoder-only models on ROCm.
37
- attention_config = None
38
- if current_platform.is_rocm():
39
- attention_config = {"backend": "FLEX_ATTENTION"}
40
-
34
# pytest caches the fixture so we use weakref.proxy to
35
# enable garbage collection
36
llm = LLM(
@@ -47,7 +40,6 @@ def llm():
40
gpu_memory_utilization=0.75,
41
enforce_eager=True,
42
seed=0,
50
- attention_config=attention_config,
43
)
44
45
yield weakref.proxy(llm)
tests/entrypoints/pooling/scoring/test_late_interaction_offline_vision.py
-8
@@ -7,7 +7,6 @@ import pytest
7
8
from vllm import LLM
9
from vllm.distributed import cleanup_dist_env_and_memory
10
-from vllm.platforms import current_platform
10
11
from .util import make_base64_image, make_image_mm_param
12
@@ -16,12 +15,6 @@ MODEL_NAME = "vidore/colpali-v1.3-hf"
15
16
@pytest.fixture(scope="module")
17
def llm():
19
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
20
- # that supports encoder-only models on ROCm.
21
- attention_config = None
22
- if current_platform.is_rocm():
23
- attention_config = {"backend": "FLEX_ATTENTION"}
24
-
18
# pytest caches the fixture so we use weakref.proxy to
19
# enable garbage collection
20
llm = LLM(
@@ -31,7 +24,6 @@ def llm():
24
gpu_memory_utilization=0.75,
25
enforce_eager=True,
26
seed=0,
34
- attention_config=attention_config,
27
)
28
29
yield weakref.proxy(llm)
tests/entrypoints/pooling/token_embed/test_offline.py
-8
@@ -7,7 +7,6 @@ import pytest
7
from vllm import LLM, PoolingRequestOutput
8
from vllm.config import PoolerConfig
9
from vllm.distributed import cleanup_dist_env_and_memory
10
-from vllm.platforms import current_platform
10
from vllm.tasks import PoolingTask
11
12
MODEL_NAME = "intfloat/multilingual-e5-small"
@@ -19,12 +18,6 @@ embedding_size = 384
18
19
@pytest.fixture(scope="module")
20
def llm():
22
- # ROCm: Use FLEX_ATTENTION backend as it's the only attention backend
23
- # that supports encoder-only models on ROCm.
24
- attention_config = None
25
- if current_platform.is_rocm():
26
- attention_config = {"backend": "FLEX_ATTENTION"}
27
-
21
# pytest caches the fixture so we use weakref.proxy to
22
# enable garbage collection
23
llm = LLM(
@@ -35,7 +28,6 @@ def llm():
28
gpu_memory_utilization=0.75,
29
enforce_eager=True,
30
seed=0,
38
- attention_config=attention_config,
31
)
32
assert embedding_size == llm.model_config.embedding_size
33
tests/entrypoints/scale_out/token_in_token_out/test_serving_multimodal_tokens.py
+1
-6
@@ -9,8 +9,6 @@ processor in the pytest parent process to keep os.fork() in sibling
9
tests (e.g. test_weight_transfer_llm.py) deadlock-free.
10
"""
11
12
-import os
13
-
12
import httpx
13
import pytest
14
import pytest_asyncio
@@ -41,10 +39,7 @@ def server():
39
"--no-enable-prefix-caching",
40
]
41
44
- envs = os.environ.copy()
45
- envs["VLLM_ROCM_USE_SKINNY_GEMM"] = "0"
46
-
47
- with RemoteOpenAIServer(MODEL_NAME, args, env_dict=envs) as remote_server:
42
+ with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
43
yield remote_server
44
45
tests/entrypoints/scale_out/token_in_token_out/test_serving_tokens.py
+1
-6
@@ -2,7 +2,6 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
import json
5
-import os
5
6
import httpx
7
import pytest
@@ -79,11 +78,7 @@ def server(request):
78
else [str(extra_args)]
79
)
80
82
- envs = os.environ.copy()
83
- # See: https://github.com/vllm-project/vllm/pull/33493#issuecomment-3888060787
84
- envs["VLLM_ROCM_USE_SKINNY_GEMM"] = "0"
85
-
86
- with RemoteOpenAIServer(MODEL_NAME, args, env_dict=envs) as remote_server:
81
+ with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
82
yield remote_server
83
84
tests/entrypoints/speech_to_text/conftest.py
-13
@@ -16,19 +16,6 @@ def add_attention_backend(server_args, attention_config):
16
server_args.extend(["--attention-backend", attention_config["backend"]])
17
18
19
-@pytest.fixture(scope="module")
20
-def rocm_aiter_fa_attention():
21
- """Return attention config for transcription/translation tests on ROCm.
22
-
23
- On ROCm, audio tests require ROCM_AITER_FA attention backend.
24
- """
25
- from vllm.platforms import current_platform
26
-
27
- if current_platform.is_rocm():
28
- return {"backend": "ROCM_AITER_FA"}
29
- return None
30
-
31
-
19
@pytest.fixture
20
def mary_had_lamb():
21
path = AudioAsset("mary_had_lamb").get_local_path()
tests/entrypoints/speech_to_text/realtime/test_realtime_validation.py
+5
-21
@@ -10,15 +10,13 @@ import pybase64 as base64
10
import pytest
11
import websockets
12
13
-from tests.entrypoints.speech_to_text.conftest import add_attention_backend
14
-from tests.utils import ROCM_ENV_OVERRIDES, ROCM_EXTRA_ARGS, RemoteOpenAIServer
13
+from tests.utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
14
from vllm.assets.audio import AudioAsset
15
from vllm.multimodal.media.audio import load_audio
16
17
# Increase engine iteration timeout for ROCm where first-use JIT compilation
18
# can exceed the default 60s, causing a silent deadlock in feed_tokens.
19
REALTIME_ENV_OVERRIDES = {
21
- **ROCM_ENV_OVERRIDES,
20
"VLLM_ENGINE_ITERATION_TIMEOUT_S": "600",
21
}
22
@@ -72,17 +70,13 @@ def mary_had_lamb_audio_chunks() -> list[str]:
70
71
@pytest.mark.asyncio
72
@pytest.mark.parametrize("model_name", [MODEL_NAME])
75
-async def test_multi_chunk_streaming(
76
- model_name, mary_had_lamb_audio_chunks, rocm_aiter_fa_attention
77
-):
73
+async def test_multi_chunk_streaming(model_name, mary_had_lamb_audio_chunks):
74
"""Test streaming multiple audio chunks before committing."""
75
server_args = ["--enforce-eager", "--max-model-len", "2048"]
76
77
if model_name.startswith("mistralai"):
78
server_args += MISTRAL_FORMAT_ARGS
79
84
- add_attention_backend(server_args, rocm_aiter_fa_attention)
85
-
80
with RemoteOpenAIServer(
81
model_name, server_args, env_dict=REALTIME_ENV_OVERRIDES
82
) as remote_server:
@@ -174,7 +168,7 @@ async def test_multi_chunk_streaming(
168
@pytest.mark.asyncio
169
@pytest.mark.parametrize("model_name", [MODEL_NAME])
170
async def test_empty_commit_does_not_crash_engine(
177
- model_name, mary_had_lamb_audio_chunks, rocm_aiter_fa_attention
171
+ model_name, mary_had_lamb_audio_chunks
172
):
173
"""Test that committing without audio does not crash the engine.
174
@@ -189,8 +183,6 @@ async def test_empty_commit_does_not_crash_engine(
183
if model_name.startswith("mistralai"):
184
server_args += MISTRAL_FORMAT_ARGS
185
192
- add_attention_backend(server_args, rocm_aiter_fa_attention)
193
-
186
with RemoteOpenAIServer(
187
model_name, server_args, env_dict=REALTIME_ENV_OVERRIDES
188
) as remote_server:
@@ -273,17 +265,13 @@ async def test_empty_commit_does_not_crash_engine(
265
266
@pytest.mark.asyncio
267
@pytest.mark.parametrize("model_name", [MODEL_NAME])
276
-async def test_session_update_invalid_model_returns_error(
277
- model_name, rocm_aiter_fa_attention
278
-):
268
+async def test_session_update_invalid_model_returns_error(model_name):
269
"""Test that session.update with an invalid model returns an error."""
270
server_args = ["--enforce-eager", "--max-model-len", "2048"]
271
272
if model_name.startswith("mistralai"):
273
server_args += MISTRAL_FORMAT_ARGS
274
285
- add_attention_backend(server_args, rocm_aiter_fa_attention)
286
-
275
with RemoteOpenAIServer(
276
model_name, server_args, env_dict=REALTIME_ENV_OVERRIDES
277
) as remote_server:
@@ -305,9 +293,7 @@ async def test_session_update_invalid_model_returns_error(
293
294
@pytest.mark.asyncio
295
@pytest.mark.parametrize("model_name", [MODEL_NAME])
308
-async def test_commit_without_session_update_returns_error(
309
- model_name, rocm_aiter_fa_attention
310
-):
296
+async def test_commit_without_session_update_returns_error(model_name):
297
"""Test that committing before validating the model returns an error
298
and does not fall through to processing."""
299
server_args = ["--enforce-eager", "--max-model-len", "2048"]
@@ -315,8 +301,6 @@ async def test_commit_without_session_update_returns_error(
301
if model_name.startswith("mistralai"):
302
server_args += MISTRAL_FORMAT_ARGS
303
318
- add_attention_backend(server_args, rocm_aiter_fa_attention)
319
-
304
with RemoteOpenAIServer(
305
model_name, server_args, env_dict=REALTIME_ENV_OVERRIDES
306
) as remote_server:
tests/entrypoints/speech_to_text/transcription/test_transcription_validation.py
+6
-18
@@ -6,8 +6,7 @@ import json
6
7
import pytest
8
9
-from tests.entrypoints.speech_to_text.conftest import add_attention_backend
10
-from tests.utils import ROCM_ENV_OVERRIDES, ROCM_EXTRA_ARGS, RemoteOpenAIServer
9
+from tests.utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
10
11
MISTRAL_FORMAT_ARGS = [
12
"--tokenizer_mode",
@@ -66,18 +65,14 @@ async def transcribe_and_check(
65
@pytest.mark.parametrize(
66
"model_name", ["mistralai/Voxtral-Mini-3B-2507", "Qwen/Qwen3-ASR-0.6B"]
67
)
69
-async def test_basic_audio(mary_had_lamb, model_name, rocm_aiter_fa_attention):
68
+async def test_basic_audio(mary_had_lamb, model_name):
69
server_args = ["--enforce-eager", *ROCM_EXTRA_ARGS]
70
71
if model_name.startswith("mistralai"):
72
server_args += MISTRAL_FORMAT_ARGS
73
75
- add_attention_backend(server_args, rocm_aiter_fa_attention)
76
-
74
# Based on https://github.com/openai/openai-cookbook/blob/main/examples/Whisper_prompting_guide.ipynb.
78
- with RemoteOpenAIServer(
79
- model_name, server_args, env_dict=ROCM_ENV_OVERRIDES
80
- ) as remote_server:
75
+ with RemoteOpenAIServer(model_name, server_args) as remote_server:
76
client = remote_server.get_async_client()
77
await transcribe_and_check(
78
client,
@@ -90,7 +85,7 @@ async def test_basic_audio(mary_had_lamb, model_name, rocm_aiter_fa_attention):
85
86
87
@pytest.mark.asyncio
93
-async def test_basic_audio_with_lora(mary_had_lamb, rocm_aiter_fa_attention):
88
+async def test_basic_audio_with_lora(mary_had_lamb):
89
"""Ensure STT (transcribe) requests can pass LoRA through to generate."""
90
# ROCm SPECIFIC CONFIGURATION:
91
# To ensure the test passes on ROCm, we modify the max model length to 512.
@@ -112,12 +107,8 @@ async def test_basic_audio_with_lora(mary_had_lamb, rocm_aiter_fa_attention):
107
"1",
108
]
109
115
- add_attention_backend(server_args, rocm_aiter_fa_attention)
116
-
110
# Based on https://github.com/openai/openai-cookbook/blob/main/examples/Whisper_prompting_guide.ipynb.
118
- with RemoteOpenAIServer(
119
- model_name, server_args, env_dict=ROCM_ENV_OVERRIDES
120
- ) as remote_server:
111
+ with RemoteOpenAIServer(model_name, server_args) as remote_server:
112
client = remote_server.get_async_client()
113
await transcribe_and_check(
114
client,
@@ -133,18 +124,15 @@ async def test_basic_audio_with_lora(mary_had_lamb, rocm_aiter_fa_attention):
124
@pytest.mark.parametrize(
125
"model_name", ["google/gemma-3n-E2B-it", "Qwen/Qwen3-ASR-0.6B"]
126
)
136
-async def test_basic_audio_foscolo(foscolo, rocm_aiter_fa_attention, model_name):
127
+async def test_basic_audio_foscolo(foscolo, model_name):
128
# Gemma accuracy on some of the audio samples we use is particularly bad,
129
# hence we use a different one here. WER is evaluated separately.
130
server_args = ["--enforce-eager", *ROCM_EXTRA_ARGS]
131
141
- add_attention_backend(server_args, rocm_aiter_fa_attention)
142
-
132
with RemoteOpenAIServer(
133
model_name,
134
server_args,
135
max_wait_seconds=480,
147
- env_dict=ROCM_ENV_OVERRIDES,
136
) as remote_server:
137
client = remote_server.get_async_client()
138
await transcribe_and_check(
tests/entrypoints/speech_to_text/translation/test_translation_validation.py
+18
-12
@@ -28,27 +28,33 @@ def _get_rocm_attention_config(model_name):
28
29
Whisper uses cross-attention (ENCODER_DECODER) which ROCM_AITER_FA does
30
not support. For Whisper we use ROCM_AITER_UNIFIED_ATTN (or TRITON_ATTN
31
- as fallback); other models can use ROCM_AITER_FA.
31
+ as fallback). Other models use ROCM_AITER_FA only on supported CDNA3+
32
+ hardware and otherwise use the platform default.
33
"""
34
from vllm.platforms import current_platform
35
36
if not current_platform.is_rocm():
37
return None
38
39
+ try:
40
+ from vllm.platforms.rocm import get_cdna_version
41
+
42
+ cdna_version = get_cdna_version()
43
+ except ImportError:
44
+ logger.warning(
45
+ "Could not check cdna version from rocm platform; "
46
+ "using a compatible fallback attention backend."
47
+ )
48
+ cdna_version = -1
49
+
50
if "whisper" in model_name.lower():
39
- try:
40
- from vllm.platforms.rocm import get_cdna_version
41
-
42
- if get_cdna_version() > 2:
43
- return {"backend": "ROCM_AITER_UNIFIED_ATTN"}
44
- except ImportError:
45
- logger.warning(
46
- "Could not check cdna version from rocm platform, "
47
- "falling back to TRITON_ATTN for Whisper."
48
- )
51
+ if cdna_version > 2:
52
+ return {"backend": "ROCM_AITER_UNIFIED_ATTN"}
53
return {"backend": "TRITON_ATTN"}
54
51
- return {"backend": "ROCM_AITER_FA"}
55
+ if cdna_version > 2:
56
+ return {"backend": "ROCM_AITER_FA"}
57
+ return None
58
59
60
def _get_server_args(attention_config):
tests/kernels/attention/test_prefix_prefill.py
+9
-17
@@ -5,12 +5,10 @@ import math
5
import random
6
import time
7
from collections.abc import Callable
8
-from contextlib import nullcontext
8
9
import pytest
10
import torch
11
import torch.nn.functional as F
13
-from torch.nn.attention import SDPBackend, sdpa_kernel
12
13
from vllm.platforms import current_platform
14
from vllm.utils.torch_utils import STR_DTYPE_TO_TORCH_DTYPE, set_random_seed
@@ -895,21 +893,15 @@ def test_contexted_kv_attention_alibi(
893
query_len, seq_len, alibi_slopes, device, dtype
894
)
895
898
- # Compute attention. On ROCm we force use of the Math SDPA backend rather than
899
- # the Flash or Mem-Efficient backends for increased numerical accuracy
900
- if current_platform.is_rocm():
901
- sdpa_context = sdpa_kernel(SDPBackend.MATH)
902
- else:
903
- sdpa_context = nullcontext()
904
- with sdpa_context:
905
- out = F.scaled_dot_product_attention(
906
- q_sdpa,
907
- k_sdpa,
908
- v_sdpa,
909
- attn_mask=alibi_mask,
910
- dropout_p=0.0,
911
- scale=scale,
912
- )
896
+ # Compute attention
897
+ out = F.scaled_dot_product_attention(
898
+ q_sdpa,
899
+ k_sdpa,
900
+ v_sdpa,
901
+ attn_mask=alibi_mask,
902
+ dropout_p=0.0,
903
+ scale=scale,
904
+ )
905
906
# Reshape output back to [query_len, num_heads, head_size]
907
out = out.view(num_heads, query_len, head_size).permute(1, 0, 2)
tests/kernels/quantization/test_rocm_skinny_gemms.py
+1
-1
@@ -140,7 +140,7 @@ def test_rocm_wvsplitkrc_kernel(xnorm, n, k, m, dtype, seed, padded_a, bias_mode
140
GrpsShrB = min(N_p2 // 16, 4)
141
# Given the above, how many CUs would we need?
142
CuNeeded = rndup_cus * GrpsShrB
143
- # candidate for atomic reduce count splitk?
143
+ # Deterministic reduction stores one float workspace value per K shard.
144
fits_wvsplitkrc = (N_p2 * m * ((k + 512 - 1) // 512)) <= 128 * 1024 * 12
145
fits_wvsplitkrc &= CuNeeded <= cu_count
146
tests/lora/test_gptoss_tp.py
+20
@@ -50,6 +50,20 @@ def reformat(text: str) -> str:
50
return text
51
52
53
+def _enable_deterministic_lora_shrink(monkeypatch: pytest.MonkeyPatch) -> None:
54
+ if not current_platform.is_rocm():
55
+ return
56
+
57
+ # These tests assert exact greedy outputs. Force the Triton LoRA shrink
58
+ # kernel to use SPLIT_K=1 so it stores the complete reduction directly
59
+ # instead of accumulating split-K partial results with atomic_add.
60
+ monkeypatch.setenv("VLLM_BATCH_INVARIANT", "1")
61
+ # The kernel configuration reads VLLM_BATCH_INVARIANT at import time.
62
+ # Spawn the engine process so it observes this setting even if the LoRA
63
+ # Triton utilities were already imported during test collection.
64
+ monkeypatch.setenv("VLLM_WORKER_MULTIPROC_METHOD", "spawn")
65
+
66
+
67
def generate_and_test(llm: vllm.LLM, lora_path: str, lora_id: int) -> None:
68
prompts = [
69
PROMPT_TEMPLATE.format(
@@ -106,7 +120,10 @@ def test_gpt_oss_lora(
120
gptoss20b_lora_files,
121
mxfp4_use_marlin,
122
specialize_active_lora,
123
+ monkeypatch: pytest.MonkeyPatch,
124
):
125
+ _enable_deterministic_lora_shrink(monkeypatch)
126
+
127
llm = vllm.LLM(
128
MODEL_PATH,
129
max_model_len=1024,
@@ -146,7 +163,10 @@ def test_gpt_oss_lora_tp2(
163
gptoss20b_lora_files,
164
fully_sharded_loras,
165
mxfp4_use_marlin,
166
+ monkeypatch: pytest.MonkeyPatch,
167
):
168
+ _enable_deterministic_lora_shrink(monkeypatch)
169
+
170
llm = vllm.LLM(
171
MODEL_PATH,
172
max_model_len=1024,
tests/lora/test_moe_lora_align_sum.py
+21
@@ -40,6 +40,18 @@ def sample_data(num_experts, max_loras, num_tokens, topk_num):
40
@pytest.mark.parametrize("block_size", [16])
41
def test_moe_lora_align_block_size(
42
num_tokens, topk_num, num_experts, max_loras, block_size
43
+):
44
+ _run_moe_lora_align_block_size_case(
45
+ num_tokens, topk_num, num_experts, max_loras, block_size
46
+ )
47
+
48
+
49
+def test_moe_lora_align_block_size_large_path_counts():
50
+ _run_moe_lora_align_block_size_case(100, 12, 64, 4, 16)
51
+
52
+
53
+def _run_moe_lora_align_block_size_case(
54
+ num_tokens, topk_num, num_experts, max_loras, block_size
55
):
56
# sample data
57
random.seed(1)
@@ -94,8 +106,17 @@ def test_moe_lora_align_block_size(
106
# verify values
107
expert_ids = expert_ids.view(max_loras, -1)
108
sorted_token_ids = sorted_token_ids.view(max_loras, -1, block_size)
109
+ topk_ids_cpu = topk_ids.cpu()
110
+ token_lora_mapping_cpu = token_lora_mapping.cpu()
111
112
for lora_idx in range(max_loras):
113
+ expert_counts = torch.bincount(
114
+ topk_ids_cpu[token_lora_mapping_cpu == lora_idx].flatten(),
115
+ minlength=num_experts,
116
+ )
117
+ expected_post_pad = round_up(expert_counts, block_size).sum().item()
118
+ assert num_tokens_post_pad[lora_idx].item() == expected_post_pad
119
+
120
for token_idx in range(sorted_token_ids.size(1)):
121
block = sorted_token_ids[lora_idx][token_idx]
122
indices = block[block != topk_ids.numel()]
tests/model_executor/layers/test_rocm_unquantized_gemm.py
+111
-1
@@ -42,6 +42,113 @@ def test_rocm_unquantized_gemm_gfx1x_wvsplitk_path(monkeypatch):
42
assert torch.allclose(out, ref, atol=1e-3, rtol=1e-3)
43
44
45
+def test_rocm_unquantized_gemm_makes_skinny_activation_contiguous(monkeypatch):
46
+ x = torch.randn(64, 4, dtype=torch.float16).t()
47
+ weight = torch.randn(128, 64, dtype=torch.float16)
48
+ assert x.shape == (4, 64)
49
+ assert x.stride() == (1, 4)
50
+
51
+ monkeypatch.setattr(utils, "use_aiter_triton_gemm", lambda *args: False)
52
+ monkeypatch.setattr(utils.envs, "VLLM_ROCM_USE_SKINNY_GEMM", True)
53
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1x", lambda: True)
54
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx9", lambda: False)
55
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx950", lambda: False)
56
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1250", lambda: False)
57
+ monkeypatch.setattr(utils, "num_compute_units", lambda: 120)
58
+
59
+ wvsplitk_mock = MagicMock(side_effect=lambda w, x_view, _, __: x_view @ w.t())
60
+ monkeypatch.setattr(utils.ops, "wvSplitK", wvsplitk_mock)
61
+
62
+ out = utils.rocm_unquantized_gemm_impl(x, weight, None)
63
+ ref = torch.nn.functional.linear(x, weight, None)
64
+
65
+ wvsplitk_mock.assert_called_once()
66
+ x_view = wvsplitk_mock.call_args.args[1]
67
+ assert x_view.is_contiguous()
68
+ assert torch.allclose(out, ref, atol=1e-3, rtol=1e-3)
69
+
70
+
71
+def test_rocm_unquantized_gemm_makes_llmm1_activation_contiguous(monkeypatch):
72
+ x = torch.randn(1, 128, dtype=torch.float16)[:, ::2]
73
+ weight = torch.randn(4, 64, dtype=torch.float16)
74
+ assert x.shape == (1, 64)
75
+ assert x.stride() == (128, 2)
76
+
77
+ monkeypatch.setattr(utils, "use_aiter_triton_gemm", lambda *args: False)
78
+ monkeypatch.setattr(utils.envs, "VLLM_ROCM_USE_SKINNY_GEMM", True)
79
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1x", lambda: True)
80
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx9", lambda: False)
81
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx950", lambda: False)
82
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1250", lambda: False)
83
+ monkeypatch.setattr(utils, "num_compute_units", lambda: 120)
84
+
85
+ llmm1_mock = MagicMock(side_effect=lambda w, x_view, _: x_view @ w.t())
86
+ monkeypatch.setattr(utils.ops, "LLMM1", llmm1_mock)
87
+
88
+ out = utils.rocm_unquantized_gemm_impl(x, weight, None)
89
+ ref = torch.nn.functional.linear(x, weight, None)
90
+
91
+ llmm1_mock.assert_called_once()
92
+ x_view = llmm1_mock.call_args.args[1]
93
+ assert x_view.is_contiguous()
94
+ assert torch.allclose(out, ref, atol=1e-3, rtol=1e-3)
95
+
96
+
97
+@pytest.mark.parametrize("noncontiguous_operand", ["weight", "bias"])
98
+def test_rocm_unquantized_gemm_rejects_unsupported_skinny_layouts(
99
+ monkeypatch, noncontiguous_operand
100
+):
101
+ x = torch.randn(4, 64, dtype=torch.float16)
102
+ weight = torch.randn(128, 64, dtype=torch.float16)
103
+ bias = torch.randn(128, dtype=torch.float16)
104
+ if noncontiguous_operand == "weight":
105
+ weight = torch.randn(64, 128, dtype=torch.float16).t()
106
+ assert not weight.is_contiguous()
107
+ else:
108
+ bias = torch.randn(256, dtype=torch.float16)[::2]
109
+ assert not bias.is_contiguous()
110
+
111
+ monkeypatch.setattr(utils, "use_aiter_triton_gemm", lambda *args: False)
112
+ monkeypatch.setattr(utils.rocm_aiter_ops, "is_tgemm_enabled", lambda: False)
113
+ monkeypatch.setattr(utils.envs, "VLLM_ROCM_USE_SKINNY_GEMM", True)
114
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1x", lambda: True)
115
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx9", lambda: False)
116
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx950", lambda: False)
117
+ monkeypatch.setattr("vllm.platforms.rocm.on_gfx1250", lambda: False)
118
+ monkeypatch.setattr(utils, "num_compute_units", lambda: 120)
119
+
120
+ wvsplitk_mock = MagicMock()
121
+ monkeypatch.setattr(utils.ops, "wvSplitK", wvsplitk_mock)
122
+ llmm1_mock = MagicMock()
123
+ monkeypatch.setattr(utils.ops, "LLMM1", llmm1_mock)
124
+
125
+ out = utils.rocm_unquantized_gemm_impl(x, weight, bias)
126
+ ref = torch.nn.functional.linear(x, weight, bias)
127
+
128
+ wvsplitk_mock.assert_not_called()
129
+ llmm1_mock.assert_not_called()
130
+ assert torch.allclose(out, ref, atol=1e-3, rtol=1e-3)
131
+
132
+
133
+@pytest.mark.skipif(not current_platform.is_rocm(), reason="ROCm-only kernel test")
134
+@pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16])
135
+def test_rocm_unquantized_gemm_noncontiguous_activation_real_kernel(monkeypatch, dtype):
136
+ x = torch.randn(64, 4, device="cuda", dtype=dtype).t()
137
+ weight = torch.randn(128, 64, device="cuda", dtype=dtype)
138
+ assert x.stride() == (1, 4)
139
+
140
+ monkeypatch.setattr(utils.envs, "VLLM_ROCM_USE_SKINNY_GEMM", True)
141
+ original_wvsplitk = utils.ops.wvSplitK
142
+ wvsplitk_mock = MagicMock(side_effect=original_wvsplitk)
143
+ monkeypatch.setattr(utils.ops, "wvSplitK", wvsplitk_mock)
144
+
145
+ out = utils.rocm_unquantized_gemm_impl(x, weight, None)
146
+ ref = torch.nn.functional.linear(x, weight, None)
147
+
148
+ wvsplitk_mock.assert_called_once()
149
+ torch.testing.assert_close(out, ref, atol=1e-2, rtol=1e-2)
150
+
151
+
152
def test_rocm_unquantized_gemm_gfx1x_n_gt_5_falls_back(monkeypatch):
153
# wvSplitK skinny GEMM handles n in [1, 5] (see PR #40687); n > 5 must
154
# fall back to torch.nn.functional.linear.
@@ -70,8 +177,9 @@ def test_rocm_unquantized_gemm_gfx1x_n_gt_5_falls_back(monkeypatch):
177
178
179
def test_rocm_unquantized_gemm_gfx950_wvsplitkrc_path(monkeypatch):
73
- x = torch.randn(16, 1024, dtype=torch.float16)
180
+ x = torch.randn(1024, 16, dtype=torch.float16).t()
181
weight = torch.randn(256, 1024, dtype=torch.float16)
182
+ assert x.stride() == (1, 16)
183
184
monkeypatch.setattr(utils, "use_aiter_triton_gemm", lambda *args: False)
185
monkeypatch.setattr(utils.envs, "VLLM_ROCM_USE_SKINNY_GEMM", True)
@@ -91,4 +199,6 @@ def test_rocm_unquantized_gemm_gfx950_wvsplitkrc_path(monkeypatch):
199
200
wvsplitkrc_mock.assert_called_once()
201
wvsplitk_mock.assert_not_called()
202
+ x_view = wvsplitkrc_mock.call_args.args[0]
203
+ assert x_view.is_contiguous()
204
assert torch.allclose(out, ref, atol=1e-3, rtol=1e-3)
tests/models/language/generation/conftest.py
deleted
-46
@@ -1,46 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Pytest configuration for vLLM language generation tests."""
4
-
5
-import os
6
-import warnings
7
-
8
-import torch
9
-
10
-from vllm.platforms import current_platform
11
-
12
-
13
-def pytest_configure(config):
14
- """Early ROCm configuration that must happen before test collection."""
15
- if not current_platform.is_rocm():
16
- return
17
-
18
- # Disable skinny GEMM on ROCm to avoid non-deterministic results
19
- # from atomic reductions in wvSplitKrc kernel.
20
- # See: https://github.com/vllm-project/vllm/pull/33493#issuecomment-3906083975
21
- os.environ["VLLM_ROCM_USE_SKINNY_GEMM"] = "0"
22
- warnings.warn(
23
- "ROCm: Set VLLM_ROCM_USE_SKINNY_GEMM=0 to avoid non-deterministic "
24
- "results from skinny GEMM atomic reductions",
25
- UserWarning,
26
- stacklevel=1,
27
- )
28
-
29
-
30
-def pytest_sessionstart(session):
31
- """Configure ROCm-specific settings before test session starts."""
32
- if not current_platform.is_rocm():
33
- return
34
-
35
- # Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
36
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
37
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
38
- torch.backends.cuda.enable_flash_sdp(False)
39
- torch.backends.cuda.enable_mem_efficient_sdp(False)
40
- torch.backends.cuda.enable_math_sdp(True)
41
- warnings.warn(
42
- "ROCm: Disabled flash_sdp and mem_efficient_sdp, enabled math_sdp "
43
- "to avoid HuggingFace Transformers accuracy issues",
44
- UserWarning,
45
- stacklevel=1,
46
- )
tests/models/language/generation/test_common.py
+6
@@ -126,6 +126,12 @@ def test_models(
126
model_info.check_available_online(on_fail="skip")
127
model_info.check_transformers_version(on_fail="skip")
128
129
+ if current_platform.is_rocm() and model == "TitanML/tiny-mixtral":
130
+ # Its single-token router selects LLMM1, whose low-precision
131
+ # accumulation can change the top-2 experts. Keep the optimized kernel
132
+ # enabled generally, but use the reference GEMM for this accuracy test.
133
+ monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
134
+
135
if use_rocm_aiter and (model in AITER_MODEL_LIST):
136
monkeypatch.setenv("VLLM_ROCM_USE_AITER", "1")
137
elif use_rocm_aiter and model not in AITER_MODEL_LIST:
tests/models/language/pooling/conftest.py
+2
-18
@@ -2,8 +2,6 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
"""Pytest configuration for vLLM language generation tests."""
4
5
-import warnings
6
-
5
import torch
6
7
from vllm.platforms import current_platform
@@ -11,19 +9,5 @@ from vllm.platforms import current_platform
9
10
def pytest_sessionstart(session):
11
"""Configure ROCm-specific settings before test session starts."""
14
- if not current_platform.is_rocm():
15
- return
16
-
17
- # Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
18
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
19
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
20
- torch.backends.cuda.enable_flash_sdp(False)
21
- torch.backends.cuda.enable_mem_efficient_sdp(False)
22
- torch.backends.cuda.enable_math_sdp(True)
23
- torch.set_float32_matmul_precision("high")
24
- warnings.warn(
25
- "ROCm: Disabled flash_sdp and mem_efficient_sdp, enabled math_sdp "
26
- "to avoid HuggingFace Transformers accuracy issues",
27
- UserWarning,
28
- stacklevel=1,
29
- )
12
+ if current_platform.is_rocm():
13
+ torch.set_float32_matmul_precision("high")
tests/models/language/pooling/test_gritlm.py
+2
-2
@@ -7,7 +7,7 @@ from scipy.spatial.distance import cosine
7
from vllm import LLM, SamplingParams
8
from vllm.config import ModelConfig
9
10
-from ....utils import ROCM_ENV_OVERRIDES, ROCM_EXTRA_ARGS, RemoteOpenAIServer
10
+from ....utils import ROCM_EXTRA_ARGS, RemoteOpenAIServer
11
from .embed_utils import run_client_embeddings
12
13
MODEL_NAME = "parasail-ai/GritLM-7B-vllm"
@@ -134,7 +134,7 @@ async def test_gritlm_api_server_embedding():
134
*ROCM_EXTRA_ARGS,
135
]
136
137
- with RemoteOpenAIServer(MODEL_NAME, args, env_dict=ROCM_ENV_OVERRIDES) as server:
137
+ with RemoteOpenAIServer(MODEL_NAME, args) as server:
138
client_embedding = server.get_async_client()
139
140
d_rep = await run_client_embeddings(
tests/models/language/pooling/test_token_classification.py
-33
@@ -48,17 +48,10 @@ def test_bert_model_runner_v2(
48
vllm_model.token_classify(prompts) for prompts in prompt_batches
49
]
50
51
- # Use eager attention on ROCm to avoid HF Transformers flash attention
52
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
53
- hf_model_kwargs = {}
54
- if current_platform.is_rocm():
55
- hf_model_kwargs["attn_implementation"] = "eager"
56
-
51
with hf_runner(
52
model,
53
dtype=dtype,
54
auto_cls=AutoModelForTokenClassification,
61
- model_kwargs=hf_model_kwargs,
55
) as hf_model:
56
tokenizer = hf_model.tokenizer
57
hf_outputs = []
@@ -100,17 +93,10 @@ def test_modernbert_models(
93
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
94
vllm_outputs = vllm_model.token_classify(example_prompts)
95
103
- # Use eager attention on ROCm to avoid HF Transformers flash attention
104
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
105
- hf_model_kwargs = {}
106
- if current_platform.is_rocm():
107
- hf_model_kwargs["attn_implementation"] = "eager"
108
-
96
with hf_runner(
97
model,
98
dtype=dtype,
99
auto_cls=AutoModelForTokenClassification,
113
- model_kwargs=hf_model_kwargs,
100
) as hf_model:
101
tokenizer = hf_model.tokenizer
102
hf_outputs = []
@@ -140,17 +126,10 @@ def test_xlm_roberta_models(
126
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
127
vllm_outputs = vllm_model.token_classify(example_prompts)
128
143
- # Use eager attention on ROCm to avoid HF Transformers flash attention
144
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
145
- hf_model_kwargs = {}
146
- if current_platform.is_rocm():
147
- hf_model_kwargs["attn_implementation"] = "eager"
148
-
129
with hf_runner(
130
model,
131
dtype=dtype,
132
auto_cls=AutoModelForTokenClassification,
153
- model_kwargs=hf_model_kwargs,
133
) as hf_model:
134
tokenizer = hf_model.tokenizer
135
hf_outputs = []
@@ -197,15 +176,10 @@ def test_openai_privacy_filter(
176
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
177
vllm_outputs = vllm_model.token_classify(PRIVACY_FILTER_PROMPTS)
178
200
- hf_model_kwargs = {}
201
- if current_platform.is_rocm():
202
- hf_model_kwargs["attn_implementation"] = "eager"
203
-
179
with hf_runner(
180
model,
181
dtype=dtype,
182
auto_cls=AutoModelForTokenClassification,
208
- model_kwargs=hf_model_kwargs,
183
) as hf_model:
184
tokenizer = hf_model.tokenizer
185
hf_outputs = []
@@ -276,12 +250,6 @@ def test_bert_for_masked_lm(
250
with vllm_runner(model, max_model_len=None, dtype=dtype) as vllm_model:
251
vllm_outputs = vllm_model.token_classify(example_prompts)
252
279
- # Use eager attention on ROCm to avoid HF Transformers flash attention
280
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
281
- hf_model_kwargs = {}
282
- if current_platform.is_rocm():
283
- hf_model_kwargs["attn_implementation"] = "eager"
284
-
253
# Run hf_runner reference with "highest" fp32 precision to match
254
# default behvior of vLLM. This is needed on ROCm since the
255
# pooling tests set matmul precision to "high" in conftest.py
@@ -291,7 +259,6 @@ def test_bert_for_masked_lm(
259
model,
260
dtype=dtype,
261
auto_cls=AutoModelForMaskedLM,
294
- model_kwargs=hf_model_kwargs,
262
) as hf_model:
263
tokenizer = hf_model.tokenizer
264
hf_outputs = []
tests/models/multimodal/conftest.py
-65
@@ -2,14 +2,8 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
"""Pytest configuration for vLLM multimodal tests."""
4
5
-import os
6
-import warnings
7
-
8
-import torch
5
import torch.nn.functional as F
6
11
-from vllm.platforms import current_platform
12
-
7
# openbmb/MiniCPM-Llama3-V-2_5's remote ``resampler.py`` annotates with ``List``
8
# without importing it, relying on the alias leaking from
9
# ``from torch.nn.functional import *``. Recent torch uses builtin generics and no
@@ -17,62 +11,3 @@ from vllm.platforms import current_platform
11
# TODO: Remove once the checkpoint fixes its imports.
12
if not hasattr(F, "List"):
13
F.List = list
20
-
21
-
22
-def pytest_configure(config):
23
- """Early ROCm configuration that must happen before test collection."""
24
- if not current_platform.is_rocm():
25
- return
26
-
27
- # Disable skinny GEMM on ROCm to avoid non-deterministic results
28
- # from atomic reductions in wvSplitKrc kernel.
29
- # See: https://github.com/vllm-project/vllm/pull/33493#issuecomment-3906083975
30
- os.environ["VLLM_ROCM_USE_SKINNY_GEMM"] = "0"
31
- warnings.warn(
32
- "ROCm: Set VLLM_ROCM_USE_SKINNY_GEMM=0 to avoid non-deterministic "
33
- "results from skinny GEMM atomic reductions",
34
- UserWarning,
35
- stacklevel=1,
36
- )
37
-
38
-
39
-def pytest_collection_modifyitems(config, items):
40
- """Configure ROCm-specific settings based on collected tests."""
41
- if not current_platform.is_rocm():
42
- return
43
-
44
- skip_patterns = ["test_granite_speech.py"]
45
- if any(pattern in str(arg) for arg in config.args for pattern in skip_patterns):
46
- return
47
-
48
- # Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
49
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
50
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
51
- torch.backends.cuda.enable_flash_sdp(False)
52
- torch.backends.cuda.enable_mem_efficient_sdp(False)
53
- torch.backends.cuda.enable_math_sdp(True)
54
- warnings.warn(
55
- "ROCm: Disabled flash_sdp and mem_efficient_sdp, enabled math_sdp "
56
- "to avoid HuggingFace Transformers accuracy issues",
57
- UserWarning,
58
- stacklevel=1,
59
- )
60
-
61
-
62
-def patch_hf_vision_attn_for_rocm(model):
63
- """Force SDPA for HF vision encoders on ROCm.
64
-
65
- HF's flash_attention_2 has accuracy issues on ROCm that bypass
66
- torch.backends.cuda settings. This forces SDPA which then uses
67
- math_sdp via the pytest_collection_modifyitems settings.
68
- """
69
- if not current_platform.is_rocm():
70
- return
71
-
72
- inner = getattr(model, "model", model)
73
-
74
- if hasattr(inner, "vision_embedding"):
75
- vit = inner.vision_embedding[0]
76
- for layer in vit.encoder.layers:
77
- if hasattr(layer, "self_attn"):
78
- layer.self_attn.vision_config._attn_implementation = "sdpa"
tests/models/multimodal/generation/test_common.py
+2
-16
@@ -249,10 +249,7 @@ VLM_TEST_SETTINGS = {
249
vllm_runner_kwargs={
250
"model_impl": "transformers",
251
},
252
- marks=[
253
- pytest.mark.core_model,
254
- *([large_gpu_mark(min_gb=80)] if current_platform.is_rocm() else []),
255
- ],
252
+ marks=[pytest.mark.core_model],
253
),
254
"idefics3-transformers": VLMTestInfo(
255
models=["HuggingFaceTB/SmolVLM-256M-Instruct"],
@@ -282,19 +279,8 @@ VLM_TEST_SETTINGS = {
279
image_size_factors=[(0.25, 0.2, 0.15)],
280
vllm_runner_kwargs={
281
"model_impl": "transformers",
285
- # TODO: [ROCm] Revert this once issue #30167 is resolved
286
- **(
287
- {
288
- "mm_processor_kwargs": {
289
- "min_pixels": 256 * 28 * 28,
290
- "max_pixels": 1280 * 28 * 28,
291
- },
292
- }
293
- if current_platform.is_rocm()
294
- else {}
295
- ),
282
},
297
- marks=[large_gpu_mark(min_gb=80 if current_platform.is_rocm() else 32)],
283
+ marks=[large_gpu_mark(min_gb=32)],
284
),
285
#### Extended model tests
286
"aria": VLMTestInfo(
tests/models/multimodal/generation/test_whisper.py
-4
@@ -129,7 +129,6 @@ def check_model_available(model: str) -> None:
129
@pytest.mark.parametrize("max_tokens", [64])
130
@pytest.mark.parametrize("beam_width", [1, 2])
131
def test_beam_search_encoder_decoder(
132
- monkeypatch,
132
hf_runner,
133
vllm_runner,
134
dtype: str,
@@ -138,9 +137,6 @@ def test_beam_search_encoder_decoder(
137
resampled_assets,
138
) -> None:
139
"""Test beam search with encoder-decoder models (Whisper)."""
141
- if current_platform.is_rocm():
142
- monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
143
-
140
model = "openai/whisper-large-v3-turbo"
141
check_model_available(model)
142
tests/models/multimodal/generation/vlm_utils/model_utils.py
-30
@@ -5,9 +5,7 @@ for manipulating the input / output of HF & vLLM test runners, which are
5
typically specific to a small subset of models.
6
"""
7
8
-import logging
8
import types
10
-import warnings
9
from pathlib import PosixPath
10
11
import numpy as np
@@ -34,8 +32,6 @@ from vllm.utils.collection_utils import is_list_of
32
from .....conftest import HfRunner, ImageAsset, ImageTestAssets
33
from .types import RunnerOutput
34
37
-logger = logging.getLogger(__name__)
38
-
35
36
####### vLLM output processors functions
37
def blip2_vllm_to_hf_output(vllm_output: RunnerOutput, model: str) -> RunnerOutput:
@@ -559,32 +555,6 @@ def isaac_patch_hf_runner(hf_model: HfRunner) -> HfRunner:
555
# ----------------------------
556
isaac_model = hf_model.model.model
557
562
- # [ROCm] Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
563
- # accuracy issues: https://github.com/vllm-project/vllm/issues/30167
564
- # TODO: Remove once ROCm SDP accuracy issues are resolved on HuggingFace
565
- # ----------------------------
566
- from ...conftest import patch_hf_vision_attn_for_rocm
567
-
568
- try:
569
- patch_hf_vision_attn_for_rocm(hf_model.model)
570
- except AttributeError as e:
571
- if "vision_config" in str(e):
572
- warnings.warn(
573
- f"Skipping ROCm vision attention patch for Isaac model: {e}. "
574
- "This is expected for models without vision_config in "
575
- "attention layers (e.g., Siglip2VariableLengthAttention).",
576
- stacklevel=2,
577
- )
578
- else:
579
- logger.error(
580
- "Unexpected AttributeError during ROCm vision attention patch: %s. "
581
- "Model type: %s. Inner model type: %s.",
582
- e,
583
- type(hf_model.model).__name__,
584
- type(getattr(hf_model.model, "model", None)).__name__,
585
- )
586
- raise
587
-
558
def patched_forward(
559
self,
560
input_ids=None,
tests/models/multimodal/pooling/conftest.py
deleted
-18
@@ -1,18 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Pytest configuration for vLLM pooling tests."""
4
-
5
-import pytest
6
-
7
-from vllm.platforms import current_platform
8
-
9
-
10
-@pytest.fixture
11
-def siglip_attention_config():
12
- """Return attention config for SigLIP tests on ROCm.
13
-
14
- On ROCm, SigLIP tests require FLEX_ATTENTION backend.
15
- """
16
- if current_platform.is_rocm():
17
- return {"backend": "FLEX_ATTENTION"}
18
- return None
tests/models/multimodal/pooling/test_siglip.py
-8
@@ -39,7 +39,6 @@ def _run_test(
39
*,
40
dtype: str,
41
tokenization_kwargs: dict[str, Any] | None = None,
42
- attention_config: dict[str, Any] | None = None,
42
) -> None:
43
if tokenization_kwargs is None:
44
tokenization_kwargs = {}
@@ -51,7 +50,6 @@ def _run_test(
50
enforce_eager=True,
51
max_model_len=64,
52
gpu_memory_utilization=0.7,
54
- attention_config=attention_config,
53
) as vllm_model:
54
vllm_outputs = vllm_model.embed(
55
input_texts, images=input_images, tokenization_kwargs=tokenization_kwargs
@@ -96,7 +94,6 @@ def test_models_text(
94
hf_runner,
95
vllm_runner,
96
image_assets,
99
- siglip_attention_config,
97
model: str,
98
dtype: str,
99
) -> None:
@@ -115,7 +112,6 @@ def test_models_text(
112
"padding": "max_length",
113
"max_length": 64,
114
}, # siglip2 was trained with this padding setting.
118
- attention_config=siglip_attention_config,
115
)
116
117
@@ -125,7 +121,6 @@ def test_models_image(
121
hf_runner,
122
vllm_runner,
123
image_assets,
128
- siglip_attention_config,
124
model: str,
125
dtype: str,
126
) -> None:
@@ -142,7 +137,6 @@ def test_models_image(
137
input_images,
138
model,
139
dtype=dtype,
145
- attention_config=siglip_attention_config,
140
)
141
142
@@ -151,7 +145,6 @@ def test_models_image(
145
def test_models_text_image_no_crash(
146
vllm_runner,
147
image_assets,
154
- siglip_attention_config,
148
model: str,
149
dtype: str,
150
) -> None:
@@ -165,7 +158,6 @@ def test_models_text_image_no_crash(
158
enforce_eager=True,
159
max_model_len=64,
160
gpu_memory_utilization=0.7,
168
- attention_config=siglip_attention_config,
161
) as vllm_model:
162
with pytest.raises(ValueError, match="not both"):
163
vllm_model.embed(texts, images=images)
tests/samplers/test_beam_search.py
-12
@@ -50,7 +50,6 @@ MODELS = ["TinyLlama/TinyLlama-1.1B-Chat-v1.0"]
50
@pytest.mark.parametrize("max_tokens", MAX_TOKENS)
51
@pytest.mark.parametrize("beam_width", BEAM_WIDTHS)
52
def test_beam_search_single_input(
53
- monkeypatch,
53
hf_runner,
54
vllm_runner,
55
example_prompts,
@@ -59,9 +58,6 @@ def test_beam_search_single_input(
58
max_tokens: int,
59
beam_width: int,
60
) -> None:
62
- if current_platform.is_rocm():
63
- monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
64
-
61
example_prompts = example_prompts[:1]
62
with hf_runner(model, dtype=dtype) as hf_model:
63
hf_outputs = hf_model.generate_beam_search(
@@ -95,7 +91,6 @@ def test_beam_search_single_input(
91
@pytest.mark.parametrize("max_tokens", MAX_TOKENS)
92
@pytest.mark.parametrize("beam_width", BEAM_WIDTHS)
93
def test_beam_search_with_concurrency_limit(
98
- monkeypatch,
94
hf_runner,
95
vllm_runner,
96
example_prompts,
@@ -104,9 +99,6 @@ def test_beam_search_with_concurrency_limit(
99
max_tokens: int,
100
beam_width: int,
101
) -> None:
107
- if current_platform.is_rocm():
108
- monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
109
-
102
# example_prompts[1]&[3]&[7] fails due to unknown reason even without
103
# concurrency limit. skip them for now.
104
example_prompts = example_prompts[:8]
@@ -156,7 +148,6 @@ def test_beam_search_with_concurrency_limit(
148
@pytest.mark.parametrize("max_tokens", MAX_TOKENS)
149
@pytest.mark.parametrize("beam_width", MM_BEAM_WIDTHS)
150
def test_beam_search_passes_multimodal_data(
159
- monkeypatch,
151
hf_runner,
152
vllm_runner,
153
dtype: str,
@@ -164,9 +155,6 @@ def test_beam_search_passes_multimodal_data(
155
beam_width: int,
156
) -> None:
157
"""Ensure that beam search passes multimodal data through correctly."""
167
- if current_platform.is_rocm():
168
- monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
169
-
158
# NOTE - this test is primarily to check that mm data is passed to beams
159
# correctly. As such, we just need to check one extra modality to make
160
# sure things pass through properly.
tests/utils.py
-6
@@ -131,12 +131,6 @@ else:
131
VLLM_PATH = Path(__file__).parent.parent
132
"""Path to root of the vLLM repository."""
133
134
-# ROCm: disable skinny GEMM to avoid non-deterministic results from
135
-# atomic reductions in wvSplitKrc kernel.
136
-# See: https://github.com/vllm-project/vllm/pull/33493#issuecomment-3906083975
137
-ROCM_ENV_OVERRIDES = (
138
- {"VLLM_ROCM_USE_SKINNY_GEMM": "0"} if current_platform.is_rocm() else {}
139
-)
134
# ROCm: disable prefix caching and eliminate batch variance to reduce
135
# test flakiness.
136
ROCM_EXTRA_ARGS = (
tests/v1/distributed/test_internal_lb_dp.py
+1
-4
@@ -12,7 +12,7 @@ import pytest
12
import pytest_asyncio
13
import requests
14
15
-from tests.utils import ROCM_ENV_OVERRIDES, RemoteOpenAIServer
15
+from tests.utils import RemoteOpenAIServer
16
from tests.v1.utils import check_request_balancing
17
from vllm.platforms import current_platform
18
@@ -186,7 +186,6 @@ class MultinodeInternalLBServerManager:
186
auto_port=False,
187
env_dict={
188
"VLLM_SERVER_DEV_MODE": "1",
189
- **ROCM_ENV_OVERRIDES,
189
current_platform.device_control_env_var: ",".join(
190
str(current_platform.device_id_to_physical_device_id(i))
191
for i in range(r, r + gpus_per_node)
@@ -308,7 +307,6 @@ class APIOnlyServerManager:
307
auto_port=False,
308
env_dict={
309
"VLLM_SERVER_DEV_MODE": "1",
311
- **ROCM_ENV_OVERRIDES,
310
# No GPUs needed for API-only server
311
},
312
)
@@ -329,7 +327,6 @@ class APIOnlyServerManager:
327
engines_server_args,
328
auto_port=False,
329
env_dict={
332
- **ROCM_ENV_OVERRIDES,
330
current_platform.device_control_env_var: ",".join(
331
str(current_platform.device_id_to_physical_device_id(i))
332
for i in range(self.dp_size * self.tp_size)
tests/v1/kv_connector/nixl_integration/test_accuracy.py
+17
-4
@@ -38,6 +38,19 @@ SIMPLE_PROMPT = (
38
MODEL_NAME = os.environ.get("TEST_MODEL", "Qwen/Qwen3-0.6B")
39
40
41
+def _meets_accuracy_threshold(measured_value: float, expected_value: float) -> bool:
42
+ return measured_value >= expected_value - RTOL
43
+
44
+
45
+def test_accuracy_threshold_is_one_sided():
46
+ expected_value = 0.77
47
+ minimum_value = expected_value - RTOL
48
+
49
+ assert _meets_accuracy_threshold(minimum_value, expected_value)
50
+ assert _meets_accuracy_threshold(expected_value + RTOL + 0.01, expected_value)
51
+ assert not _meets_accuracy_threshold(minimum_value - 0.01, expected_value)
52
+
53
+
54
def run_simple_prompt():
55
client = openai.OpenAI(api_key="EMPTY", base_url=BASE_URL)
56
completion = client.completions.create(model=MODEL_NAME, prompt=SIMPLE_PROMPT)
@@ -93,7 +106,7 @@ def test_accuracy():
106
)
107
return
108
96
- assert (
97
- measured_value - RTOL < expected_value
98
- and measured_value + RTOL > expected_value
99
- ), f"Expected: {expected_value} | Measured: {measured_value}"
109
+ minimum_value = expected_value - RTOL
110
+ assert _meets_accuracy_threshold(measured_value, expected_value), (
111
+ f"Expected at least: {minimum_value} | Measured: {measured_value}"
112
+ )
tests/v1/kv_offload/cpu/test_gpu_worker.py
+70
@@ -18,6 +18,7 @@ from vllm.v1.kv_offload.base import (
18
CanonicalKVCaches,
19
CanonicalKVCacheTensor,
20
GPULoadStoreSpec,
21
+ TransferResult,
22
)
23
from vllm.v1.kv_offload.cpu import gpu_worker
24
from vllm.v1.kv_offload.cpu.common import CPULoadStoreSpec
@@ -612,3 +613,72 @@ def test_transfer_multi_group(
613
)
614
615
worker.shutdown()
616
+
617
+
618
+@pytest.mark.skipif(
619
+ not current_platform.is_cuda_alike(),
620
+ reason="stream ordering test requires a CUDA-like platform",
621
+)
622
+@torch.inference_mode()
623
+def test_load_waits_for_pending_compute_stream_writes(default_vllm_config) -> None:
624
+ """A CPU load must land after pending writes to its GPU destination."""
625
+ device = DEVICES[0]
626
+ page_size_bytes = 128 * 1024
627
+ num_blocks = 64
628
+ loaded_blocks = list(range(32))
629
+ sentinel = 0x5A
630
+
631
+ gpu_tensor = torch.zeros(
632
+ (num_blocks, page_size_bytes), dtype=torch.int8, device=device
633
+ )
634
+ loaded_block_ids = torch.tensor(loaded_blocks, dtype=torch.long, device=device)
635
+ worker = CPUOffloadingWorker(
636
+ kv_caches=CanonicalKVCaches(
637
+ tensors=[
638
+ CanonicalKVCacheTensor(
639
+ tensor=gpu_tensor, page_size_bytes=page_size_bytes
640
+ )
641
+ ],
642
+ group_data_refs=[
643
+ [CanonicalKVCacheRef(tensor_idx=0, page_size_bytes=page_size_bytes)]
644
+ ],
645
+ ),
646
+ blocks_per_chunk=1,
647
+ num_cpu_blocks=num_blocks,
648
+ )
649
+ worker._load_handler.src_tensors[0].fill_(sentinel)
650
+ expected = torch.full((page_size_bytes,), sentinel, dtype=torch.int8)
651
+
652
+ try:
653
+ for trial in range(3):
654
+ gpu_tensor.fill_(0x11)
655
+ torch.accelerator.synchronize()
656
+
657
+ # Model a delayed zero of a freshly allocated KV block. Without a
658
+ # compute-stream dependency, the DMA can finish during the sleep
659
+ # and this later fill wipes out the loaded cache contents.
660
+ torch.cuda._sleep(50_000_000)
661
+ gpu_tensor.index_fill_(0, loaded_block_ids, 0)
662
+
663
+ assert worker.submit_load(
664
+ trial + 1,
665
+ CPULoadStoreSpec(loaded_blocks),
666
+ GPULoadStoreSpec(
667
+ loaded_blocks,
668
+ group_sizes=(len(loaded_blocks),),
669
+ block_indices=(0,),
670
+ ),
671
+ )
672
+ deadline = time.time() + 10
673
+ finished: list[TransferResult] = []
674
+ while time.time() < deadline and not finished:
675
+ finished = worker.get_finished()
676
+ if not finished:
677
+ time.sleep(0.001)
678
+ assert finished and finished[0].success, f"load {trial} did not finish"
679
+
680
+ torch.accelerator.synchronize()
681
+ for block_id in loaded_blocks:
682
+ torch.testing.assert_close(gpu_tensor[block_id].cpu(), expected)
683
+ finally:
684
+ worker.shutdown()
tests/v1/sample/test_logprobs.py
-12
@@ -1114,7 +1114,6 @@ def test_correct_decoded_token_preserves_valid_tokens():
1114
def test_spec_decode_logprobs(
1115
logprobs_mode: LogprobsMode,
1116
model_setup: tuple[str, str, dict, int],
1117
- monkeypatch,
1117
):
1118
"""Spec decode logprobs should match those of the base model.
1119
@@ -1127,20 +1126,9 @@ def test_spec_decode_logprobs(
1126
logprobs_mode: logprobs mode.
1127
model_setup: Tuple of (method, base model name,
1128
speculative_config dict, top_logprobs).
1130
- monkeypatch: pytest fixture for setting env vars.
1129
"""
1130
from vllm import LLM
1131
1134
- # The ROCm skinny GEMM kernels (gemm_kernels.cu) are
1135
- # non-deterministic across LLM instantiations due to persistent
1136
- # workgroup scheduling and wave-level shuffle reductions, which
1137
- # causes logprob differences that get misattributed to spec decode.
1138
- # Disable them so this test isolates spec decode correctness only.
1139
- # TODO(akaratza): Remove this workaround once the follow-up to
1140
- # https://github.com/vllm-project/vllm/pull/33493#issuecomment-3906083975
1141
- # lands with a determinism fix for wvSplitK kernels.
1142
- monkeypatch.setenv("VLLM_ROCM_USE_SKINNY_GEMM", "0")
1143
-
1132
method, model_name, spec_config, top_logprobs = model_setup
1133
1134
prompt = "Hello world " * 50
tests/v1/worker/test_gpu_model_runner.py
+60
@@ -1,6 +1,7 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
+import gc
5
from types import SimpleNamespace
6
from unittest.mock import Mock
7
@@ -126,6 +127,34 @@ def get_vllm_config():
127
return vllm_config
128
129
130
+@pytest.mark.parametrize("gc_initially_enabled", [True, False])
131
+def test_freeze_gc_disables_and_restores_automatic_gc(
132
+ monkeypatch: pytest.MonkeyPatch,
133
+ gc_initially_enabled: bool,
134
+):
135
+ monkeypatch.setenv("VLLM_ENABLE_CUDAGRAPH_GC", "0")
136
+ original_gc_state = gc.isenabled()
137
+ try:
138
+ if gc_initially_enabled:
139
+ gc.enable()
140
+ else:
141
+ gc.disable()
142
+
143
+ with (
144
+ pytest.raises(RuntimeError, match="capture failed"),
145
+ GPUModelRunner._freeze_gc(),
146
+ ):
147
+ assert not gc.isenabled()
148
+ raise RuntimeError("capture failed")
149
+
150
+ assert gc.isenabled() is gc_initially_enabled
151
+ finally:
152
+ if original_gc_state:
153
+ gc.enable()
154
+ else:
155
+ gc.disable()
156
+
157
+
158
@pytest.fixture
159
def model_runner():
160
vllm_config = get_vllm_config()
@@ -896,6 +925,37 @@ def test_sample_passes_reordered_draft_probs_to_rejection_sampler():
925
assert torch.equal(passed_draft_probs, expected_draft_probs)
926
927
928
+def test_dummy_sampler_run_warms_all_greedy_rejection_sampler(monkeypatch):
929
+ runner = object.__new__(GPUModelRunner)
930
+ runner.device = torch.device("cpu")
931
+ runner.vllm_config = SimpleNamespace(
932
+ model_config=SimpleNamespace(multimodal_config=None)
933
+ )
934
+ runner.model = SimpleNamespace(compute_logits=Mock(return_value=torch.randn(3, 8)))
935
+ runner.sampler = Mock(return_value="sampler_output")
936
+ runner.sampler.logprobs_mode = "processed_logprobs"
937
+ runner.speculative_config = SimpleNamespace(
938
+ rejection_sample_method="standard",
939
+ draft_sample_method="greedy",
940
+ )
941
+ runner.rejection_sampler = Mock()
942
+ synchronize = Mock()
943
+ monkeypatch.setattr(torch.accelerator, "synchronize", synchronize)
944
+
945
+ output = GPUModelRunner._dummy_sampler_run(runner, torch.randn(3, 4))
946
+
947
+ assert output == "sampler_output"
948
+ assert runner.rejection_sampler.call_count == 2
949
+ mixed_metadata = runner.rejection_sampler.call_args_list[0].args[3]
950
+ all_greedy_metadata = runner.rejection_sampler.call_args_list[1].args[3]
951
+ assert not mixed_metadata.all_greedy
952
+ assert mixed_metadata.temperature is not None
953
+ assert all_greedy_metadata.all_greedy
954
+ assert not all_greedy_metadata.all_random
955
+ assert all_greedy_metadata.temperature is None
956
+ synchronize.assert_called_once_with()
957
+
958
+
959
def test_invalid_draft_suffixes_remain_rejected_in_metadata():
960
runner = object.__new__(GPUModelRunner)
961
runner.device = torch.device("cpu")
vllm/_aiter_ops.py
+82
@@ -1,12 +1,15 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+import ctypes
4
import functools
5
+import os
6
from collections.abc import Callable
7
8
import torch
9
from torch._ops import OpOverload
10
11
import vllm.envs as envs
12
+from vllm.logger import init_logger
13
from vllm.platforms import current_platform
14
from vllm.utils.import_utils import PlaceholderModule
15
from vllm.utils.torch_utils import direct_register_custom_op
@@ -15,6 +18,8 @@ from vllm.v1.attention.ops.rocm_aiter_mla_sparse import (
18
rocm_aiter_sparse_attn_indexer_fake,
19
)
20
21
+logger = init_logger(__name__)
22
+
23
try:
24
import pandas as pd
25
except ImportError:
@@ -49,6 +54,83 @@ def is_aiter_found() -> bool:
54
IS_AITER_FOUND = is_aiter_found()
55
56
57
+class _DlInfo(ctypes.Structure):
58
+ _fields_ = [
59
+ ("dli_fname", ctypes.c_char_p),
60
+ ("dli_fbase", ctypes.c_void_p),
61
+ ("dli_sname", ctypes.c_char_p),
62
+ ("dli_saddr", ctypes.c_void_p),
63
+ ]
64
+
65
+
66
+_HIP_RUNTIME_HANDLE: ctypes.CDLL | None = None
67
+
68
+
69
+def _find_torch_hip_runtime_path() -> str | None:
70
+ """Find the HIP runtime already selected by PyTorch's extension graph."""
71
+ try:
72
+ torch_extension = ctypes.CDLL(torch._C.__file__)
73
+ hip_symbol = torch_extension.hipGetDeviceCount
74
+ dladdr = ctypes.CDLL(None).dladdr
75
+ dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(_DlInfo)]
76
+ dladdr.restype = ctypes.c_int
77
+ info = _DlInfo()
78
+ if not dladdr(ctypes.cast(hip_symbol, ctypes.c_void_p), ctypes.byref(info)):
79
+ return None
80
+ except (AttributeError, OSError, TypeError, ctypes.ArgumentError):
81
+ return None
82
+ if info.dli_fname is None:
83
+ return None
84
+
85
+ runtime_path = os.fsdecode(info.dli_fname)
86
+ if "libamdhip64.so" not in os.path.basename(runtime_path):
87
+ return None
88
+ return runtime_path
89
+
90
+
91
+def _promote_torch_hip_runtime() -> None:
92
+ """Make PyTorch's HIP runtime symbols visible to AITER JIT extensions.
93
+
94
+ PyTorch loads its native extension with ``RTLD_LOCAL``. Some AITER JIT
95
+ extensions rely on HIP registration and launch symbols being available in
96
+ the process-global lookup scope. Reopening the exact runtime that provides
97
+ PyTorch's ``hipGetDeviceCount`` symbol promotes the existing DSO instead of
98
+ selecting or initializing a second HIP runtime.
99
+ """
100
+ global _HIP_RUNTIME_HANDLE
101
+ if _HIP_RUNTIME_HANDLE is not None:
102
+ return
103
+
104
+ runtime_path = _find_torch_hip_runtime_path()
105
+ if runtime_path is None:
106
+ logger.warning_once(
107
+ "Could not locate PyTorch's HIP runtime; AITER JIT extensions may "
108
+ "fail to resolve HIP symbols."
109
+ )
110
+ return
111
+
112
+ try:
113
+ # Retain the handle for the process lifetime. Besides preventing a
114
+ # future dlclose, this documents that the RTLD_GLOBAL promotion is
115
+ # intentional and must outlive every lazily imported AITER extension.
116
+ _HIP_RUNTIME_HANDLE = ctypes.CDLL(runtime_path, mode=ctypes.RTLD_GLOBAL)
117
+ except OSError as err:
118
+ logger.warning_once(
119
+ "Could not promote PyTorch's HIP runtime at %s; AITER JIT "
120
+ "extensions may fail to resolve HIP symbols: %s",
121
+ runtime_path,
122
+ err,
123
+ )
124
+
125
+
126
+def _maybe_promote_torch_hip_runtime() -> None:
127
+ if current_platform.is_rocm() and IS_AITER_FOUND:
128
+ _promote_torch_hip_runtime()
129
+
130
+
131
+_maybe_promote_torch_hip_runtime()
132
+
133
+
134
def is_aiter_found_and_supported() -> bool:
135
"""Check if AITER library is available and platform supports it.
136
vllm/model_executor/layers/utils.py
+12
-4
@@ -134,12 +134,16 @@ def rocm_unquantized_gemm_impl(
134
GrpsShrB = min(N_p2 // 16, 4)
135
# Given the above, how many CUs would we need?
136
CuNeeded = rndup_cus * GrpsShrB
137
- # candidate for atomic reduce count splitk?
137
+ # Deterministic reduction stores one float workspace value per K shard.
138
fits_wvsplitkrc = (
139
N_p2 * m * ((k + 512 - 1) // 512)
140
) <= 128 * 1024 * 12 # deterministic
141
fits_wvsplitkrc &= CuNeeded <= cu_count
142
143
+ skinny_operands_compatible = weight.is_contiguous() and (
144
+ bias is None or bias.is_contiguous()
145
+ )
146
+
147
use_skinny_reduce_counting = (
148
envs.VLLM_ROCM_USE_SKINNY_GEMM
149
and on_gfx950()
@@ -151,12 +155,13 @@ def rocm_unquantized_gemm_impl(
155
and k > 512
156
and m % 16 == 0
157
and fits_wvsplitkrc
154
- and weight.is_contiguous()
158
+ and skinny_operands_compatible
159
)
160
)
161
162
if use_skinny_reduce_counting:
159
- return ops.wvSplitKrc(x, weight, cu_count, bias)
163
+ x_view = x.reshape(-1, x.size(-1)).contiguous()
164
+ return ops.wvSplitKrc(x_view, weight, cu_count, bias)
165
166
# gfx1250's aiter gemm_a16w16 uses the gluon backend, which requires
167
# K % 256 == 0 (it walks K with fixed-size descriptors and won't pad a
@@ -174,10 +179,13 @@ def rocm_unquantized_gemm_impl(
179
# TODO GFX1250: Include once skinny GEMM is supported on gfx1250
180
and x.dtype in [torch.float16, torch.bfloat16]
181
and k % 8 == 0
182
+ and skinny_operands_compatible
183
)
184
185
if use_skinny:
180
- x_view = x.reshape(-1, x.size(-1))
186
+ # The skinny kernels assume contiguous K elements. A shape-preserving
187
+ # reshape can retain a transposed activation's non-contiguous strides.
188
+ x_view = x.reshape(-1, x.size(-1)).contiguous()
189
if m > 8 and 0 < n <= 5:
190
cu_count = num_compute_units()
191
out = ops.wvSplitK(weight, x_view, cu_count, bias)
vllm/model_executor/models/transformers/multimodal.py
+5
-28
@@ -18,7 +18,7 @@
18
19
from collections import defaultdict
20
from collections.abc import Mapping, Sequence
21
-from contextlib import ExitStack, contextmanager, nullcontext
21
+from contextlib import ExitStack, contextmanager
22
from typing import TYPE_CHECKING, Any
23
24
import torch
@@ -53,7 +53,6 @@ from vllm.multimodal.processing import (
53
PromptUpdate,
54
TimingContext,
55
)
56
-from vllm.platforms import current_platform
56
from vllm.sequence import IntermediateTensors
57
58
if TYPE_CHECKING:
@@ -727,15 +726,9 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE):
726
kwargs.pop("token_type_ids", None)
727
kwargs.pop("mm_token_type_ids", None)
728
730
- context = nullcontext()
731
- if current_platform.is_rocm():
732
- context = torch.nn.attention.sdpa_kernel(
733
- backends=[torch.nn.attention.SDPBackend.MATH]
734
- )
735
- with context:
736
- audio_output = self.model.get_audio_features(
737
- input_features, return_dict=True, **kwargs
738
- )
729
+ audio_output = self.model.get_audio_features(
730
+ input_features, return_dict=True, **kwargs
731
+ )
732
audio_embeddings = audio_output.pooler_output
733
734
split_sizes = num_audio_tokens.flatten().tolist()
@@ -756,23 +749,7 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE):
749
750
num_image_patches = kwargs.pop("num_image_patches")
751
759
- context = nullcontext()
760
- if current_platform.is_rocm():
761
- # ROCm: Force math SDP backend for vision encoder to avoid accuracy issues
762
- # with flash_sdp and mem_efficient_sdp
763
- # TODO: [ROCm] Fix accuracy issues with flash backend
764
- logger.debug(
765
- "ROCm platform detected. Forcing math SDP backend "
766
- "for vision encoder. Currently ROCm platform has "
767
- "accuracy issues with `flash_sdp` and"
768
- "`mem_efficient_sdp` backends. See issue: "
769
- "https://github.com/vllm-project/vllm/issues/30167"
770
- )
771
- context = torch.nn.attention.sdpa_kernel(
772
- backends=[torch.nn.attention.SDPBackend.MATH]
773
- )
774
- with context:
775
- vision_embeddings = self.model.get_image_features(pixel_values, **kwargs)
752
+ vision_embeddings = self.model.get_image_features(pixel_values, **kwargs)
753
754
# Transformers `v5`, `self.get_image_features` returns a tuple
755
# containing the features and optionally attentions/hidden_states
vllm/v1/core/kv_cache_utils.py
+1
-2
@@ -619,8 +619,7 @@ def resolve_kv_cache_block_sizes(
619
``cache_config.prefix_match_unit`` override if set, else the GCD of
620
group block sizes; every group's block size must be divisible by it.
621
Returns the scheduler block size (i.e. disables finer hashing) if block
622
- hashing is inactive or a mamba group's block size diverges from the
623
- cache block size (mamba_cache_mode != "align").
622
+ hashing is inactive or a mamba group is not using cache mode "align".
623
"""
624
cache_config = vllm_config.cache_config
625
dcp = vllm_config.parallel_config.decode_context_parallel_size
vllm/v1/kv_offload/cpu/gpu_worker.py
+5
-3
@@ -634,9 +634,11 @@ class SingleDirectionOffloadingHandler:
634
else torch.Event(enable_timing=True)
635
)
636
637
- if self.gpu_to_cpu:
638
- # wait for model computation to finish before offloading
639
- stream.wait_stream(current_platform.current_stream())
637
+ # Stores must wait for the model to finish writing the KV they read.
638
+ # Loads must wait for pending writes (including zeroing) to their
639
+ # destination blocks; otherwise an earlier transfer can be overwritten
640
+ # by compute-stream work that was already queued when the load began.
641
+ stream.wait_stream(current_platform.current_stream())
642
if self._transfers:
643
last_transfer: Transfer = self._transfers[-1]
644
last_event = last_transfer.end_event
vllm/v1/worker/gpu_model_runner.py
+27
-2
@@ -6420,6 +6420,21 @@ class GPUModelRunner(
6420
logits,
6421
dummy_metadata,
6422
)
6423
+ # All-greedy is a separate Triton specialization from the
6424
+ # mixed-sampling path above. Compile and exercise it before serving.
6425
+ all_greedy_metadata = replace(
6426
+ dummy_metadata,
6427
+ temperature=None,
6428
+ all_greedy=True,
6429
+ all_random=False,
6430
+ )
6431
+ self.rejection_sampler(
6432
+ dummy_spec_decode_metadata,
6433
+ draft_probs,
6434
+ logits,
6435
+ all_greedy_metadata,
6436
+ )
6437
+ torch.accelerator.synchronize()
6438
return sampler_output
6439
6440
def _dummy_pooler_run_task(
@@ -6615,16 +6630,26 @@ class GPUModelRunner(
6630
@staticmethod
6631
@contextmanager
6632
def _freeze_gc():
6633
+ gc_was_enabled = gc.isenabled()
6634
gc.collect()
6635
should_freeze = not envs.VLLM_ENABLE_CUDAGRAPH_GC
6636
if should_freeze:
6637
gc.freeze()
6638
+ # A Triton kernel finalized during stream capture unloads its
6639
+ # module and invalidates the captured graph.
6640
+ gc.disable()
6641
try:
6642
yield
6643
finally:
6644
if should_freeze:
6626
- gc.unfreeze()
6627
- gc.collect()
6645
+ try:
6646
+ gc.unfreeze()
6647
+ gc.collect()
6648
+ finally:
6649
+ if gc_was_enabled:
6650
+ gc.enable()
6651
+ else:
6652
+ gc.disable()
6653
6654
def shutdown(self) -> None:
6655
"""Release GPU tensors (model weights, KV caches, workspace) so that