Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions tests/kernels/scripts/check_no_tilelang_hijack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need a separate file for this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The subprocess is the point of the change, and I put the script in a file to
follow what is already in the tree: tests/cuda/test_platform_no_cuda_init.py
keeps its checks in tests/cuda/scripts/check_*.py and runs them the same way,
with subprocess.run([sys.executable, str(script_path)]) and a pytest.fail on
a non-zero exit.

The alternative is to inline the source as a string and pass it with python -c,
as tests/config/test_config_utils.py does, but this check needs a ctypes
structure and the dlsym/dladdr calls, and inside a string none of that is
formatted or linted. I can switch if you prefer no new file in the tree.

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Check that DeepSeek V4 and the JIT monitor leave the HIP symbols alone.

TileLang ships a libhip_stub.so that takes over `hipFree` in the global symbol
table once it is loaded, so neither the model import nor the JIT monitor may
pull TileLang in on ROCm. Both claims are about process-global state, which is
why this runs in an interpreter of its own.
"""

import ctypes
import sys

from vllm.model_executor.layers import mhc # noqa: F401
from vllm.models import deepseek_v4 # noqa: F401
from vllm.utils import jit_monitor


class DlInfo(ctypes.Structure):
_fields_ = [
("dli_fname", ctypes.c_char_p),
("dli_fbase", ctypes.c_void_p),
("dli_sname", ctypes.c_char_p),
("dli_saddr", ctypes.c_void_p),
]


def _must_not_run() -> None:
raise AssertionError("TileLang JIT monitor must not run on ROCm")


jit_monitor._active = False
jit_monitor._setup_triton_autotuning_print = lambda: None
jit_monitor._setup_triton_jit_hook = lambda: None
jit_monitor._setup_cutedsl_jit_hook = lambda: None
jit_monitor._setup_tilelang_jit_hook = _must_not_run
jit_monitor.activate()

imported = [
name for name in sys.modules if name == "tilelang" or name.startswith("tilelang.")
]
assert not imported, f"TileLang was imported: {imported}"

libdl = ctypes.CDLL("libdl.so.2")
dlsym = libdl.dlsym
dlsym.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
dlsym.restype = ctypes.c_void_p
dladdr = libdl.dladdr
dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(DlInfo)]
dladdr.restype = ctypes.c_int

address = dlsym(None, b"hipFree")
assert address is not None, "hipFree is not available in the global symbol table"
info = DlInfo()
assert dladdr(address, ctypes.byref(info))
source = info.dli_fname.decode() if info.dli_fname else "<unknown>"
assert "libhip_stub.so" not in source, source
assert "libamdhip64.so" in source, source
print("OK")
59 changes: 14 additions & 45 deletions tests/kernels/test_mhc_tilelang_jit.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

import ctypes
import importlib
import importlib.util
import subprocess
import sys
from pathlib import Path
from types import ModuleType
from typing import Any

Expand Down Expand Up @@ -78,51 +79,19 @@ def test_tilelang_jit_decorator_is_lazy_only_on_rocm(


@pytest.mark.skipif(not current_platform.is_rocm(), reason="Test requires ROCm")
def test_deepseek_v4_import_and_jit_monitor_do_not_hijack_hip_symbols(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def test_deepseek_v4_import_and_jit_monitor_do_not_hijack_hip_symbols() -> None:
if importlib.util.find_spec("tilelang") is None:
pytest.skip("Test requires TileLang to be installed")

class DlInfo(ctypes.Structure):
_fields_ = [
("dli_fname", ctypes.c_char_p),
("dli_fbase", ctypes.c_void_p),
("dli_sname", ctypes.c_char_p),
("dli_saddr", ctypes.c_void_p),
]

libdl = ctypes.CDLL("libdl.so.2")
dlsym = libdl.dlsym
dlsym.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
dlsym.restype = ctypes.c_void_p
dladdr = libdl.dladdr
dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(DlInfo)]
dladdr.restype = ctypes.c_int

from vllm.model_executor.layers import mhc # noqa: F401
from vllm.models import deepseek_v4 # noqa: F401
from vllm.utils import jit_monitor

monkeypatch.setattr(jit_monitor, "_active", False)
monkeypatch.setattr(jit_monitor, "_setup_triton_autotuning_print", lambda: None)
monkeypatch.setattr(jit_monitor, "_setup_triton_jit_hook", lambda: None)
monkeypatch.setattr(jit_monitor, "_setup_cutedsl_jit_hook", lambda: None)
monkeypatch.setattr(
jit_monitor,
"_setup_tilelang_jit_hook",
lambda: pytest.fail("TileLang JIT monitor must not run on ROCm"),
# Both claims are about process-global state, `sys.modules` and the symbol
# table, and a sibling test legitimately imports TileLang to exercise those
# kernels, so the checks only mean something in an interpreter of their own.
script = Path(__file__).parent / "scripts" / "check_no_tilelang_hijack.py"
result = subprocess.run(
[sys.executable, str(script)],
capture_output=True,
text=True,
timeout=300,
)
jit_monitor.activate()

assert not any(
name == "tilelang" or name.startswith("tilelang.") for name in sys.modules
)

address = dlsym(None, b"hipFree")
assert address is not None, "hipFree is not available in the global symbol table"
info = DlInfo()
assert dladdr(address, ctypes.byref(info))
source = info.dli_fname.decode() if info.dli_fname else "<unknown>"
assert "libhip_stub.so" not in source, source
assert "libamdhip64.so" in source, source
if result.returncode != 0:
pytest.fail(f"HIP symbols were hijacked:\n{result.stdout}\n{result.stderr}")
Loading