[CI/Build][ROCm] Run the TileLang HIP symbol checks in their own interpreter (#53117)

Signed-off-by: Stefan Koncarevic <Stefan.Koncarevic@amd.com>

stefankoncarevic committed Aug 21, 2026 at 23:17 UTC f37d5868b9530497c9474f4850fdd0577f4dad79
2 files changed +74 -45
tests/kernels/scripts/check_no_tilelang_hijack.py new
+60
@@ -0,0 +1,60 @@
1 +#!/usr/bin/env python3
2 +# SPDX-License-Identifier: Apache-2.0
3 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4 +"""Check that DeepSeek V4 and the JIT monitor leave the HIP symbols alone.
5 +
6 +TileLang ships a libhip_stub.so that takes over `hipFree` in the global symbol
7 +table once it is loaded, so neither the model import nor the JIT monitor may
8 +pull TileLang in on ROCm. Both claims are about process-global state, which is
9 +why this runs in an interpreter of its own.
10 +"""
11 +
12 +import ctypes
13 +import sys
14 +
15 +from vllm.model_executor.layers import mhc # noqa: F401
16 +from vllm.models import deepseek_v4 # noqa: F401
17 +from vllm.utils import jit_monitor
18 +
19 +
20 +class DlInfo(ctypes.Structure):
21 + _fields_ = [
22 + ("dli_fname", ctypes.c_char_p),
23 + ("dli_fbase", ctypes.c_void_p),
24 + ("dli_sname", ctypes.c_char_p),
25 + ("dli_saddr", ctypes.c_void_p),
26 + ]
27 +
28 +
29 +def _must_not_run() -> None:
30 + raise AssertionError("TileLang JIT monitor must not run on ROCm")
31 +
32 +
33 +jit_monitor._active = False
34 +jit_monitor._setup_triton_autotuning_print = lambda: None
35 +jit_monitor._setup_triton_jit_hook = lambda: None
36 +jit_monitor._setup_cutedsl_jit_hook = lambda: None
37 +jit_monitor._setup_tilelang_jit_hook = _must_not_run
38 +jit_monitor.activate()
39 +
40 +imported = [
41 + name for name in sys.modules if name == "tilelang" or name.startswith("tilelang.")
42 +]
43 +assert not imported, f"TileLang was imported: {imported}"
44 +
45 +libdl = ctypes.CDLL("libdl.so.2")
46 +dlsym = libdl.dlsym
47 +dlsym.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
48 +dlsym.restype = ctypes.c_void_p
49 +dladdr = libdl.dladdr
50 +dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(DlInfo)]
51 +dladdr.restype = ctypes.c_int
52 +
53 +address = dlsym(None, b"hipFree")
54 +assert address is not None, "hipFree is not available in the global symbol table"
55 +info = DlInfo()
56 +assert dladdr(address, ctypes.byref(info))
57 +source = info.dli_fname.decode() if info.dli_fname else "<unknown>"
58 +assert "libhip_stub.so" not in source, source
59 +assert "libamdhip64.so" in source, source
60 +print("OK")
tests/kernels/test_mhc_tilelang_jit.py
+14 -45
@@ -1,10 +1,11 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -import ctypes
4 import importlib
5 import importlib.util
6 +import subprocess
7 import sys
8 +from pathlib import Path
9 from types import ModuleType
10 from typing import Any
11
@@ -78,51 +79,19 @@ def test_tilelang_jit_decorator_is_lazy_only_on_rocm(
79
80
81 @pytest.mark.skipif(not current_platform.is_rocm(), reason="Test requires ROCm")
81 -def test_deepseek_v4_import_and_jit_monitor_do_not_hijack_hip_symbols(
82 - monkeypatch: pytest.MonkeyPatch,
83 -) -> None:
82 +def test_deepseek_v4_import_and_jit_monitor_do_not_hijack_hip_symbols() -> None:
83 if importlib.util.find_spec("tilelang") is None:
84 pytest.skip("Test requires TileLang to be installed")
85
87 - class DlInfo(ctypes.Structure):
88 - _fields_ = [
89 - ("dli_fname", ctypes.c_char_p),
90 - ("dli_fbase", ctypes.c_void_p),
91 - ("dli_sname", ctypes.c_char_p),
92 - ("dli_saddr", ctypes.c_void_p),
93 - ]
94 -
95 - libdl = ctypes.CDLL("libdl.so.2")
96 - dlsym = libdl.dlsym
97 - dlsym.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
98 - dlsym.restype = ctypes.c_void_p
99 - dladdr = libdl.dladdr
100 - dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(DlInfo)]
101 - dladdr.restype = ctypes.c_int
102 -
103 - from vllm.model_executor.layers import mhc # noqa: F401
104 - from vllm.models import deepseek_v4 # noqa: F401
105 - from vllm.utils import jit_monitor
106 -
107 - monkeypatch.setattr(jit_monitor, "_active", False)
108 - monkeypatch.setattr(jit_monitor, "_setup_triton_autotuning_print", lambda: None)
109 - monkeypatch.setattr(jit_monitor, "_setup_triton_jit_hook", lambda: None)
110 - monkeypatch.setattr(jit_monitor, "_setup_cutedsl_jit_hook", lambda: None)
111 - monkeypatch.setattr(
112 - jit_monitor,
113 - "_setup_tilelang_jit_hook",
114 - lambda: pytest.fail("TileLang JIT monitor must not run on ROCm"),
86 + # Both claims are about process-global state, `sys.modules` and the symbol
87 + # table, and a sibling test legitimately imports TileLang to exercise those
88 + # kernels, so the checks only mean something in an interpreter of their own.
89 + script = Path(__file__).parent / "scripts" / "check_no_tilelang_hijack.py"
90 + result = subprocess.run(
91 + [sys.executable, str(script)],
92 + capture_output=True,
93 + text=True,
94 + timeout=300,
95 )
116 - jit_monitor.activate()
117 -
118 - assert not any(
119 - name == "tilelang" or name.startswith("tilelang.") for name in sys.modules
120 - )
121 -
122 - address = dlsym(None, b"hipFree")
123 - assert address is not None, "hipFree is not available in the global symbol table"
124 - info = DlInfo()
125 - assert dladdr(address, ctypes.byref(info))
126 - source = info.dli_fname.decode() if info.dli_fname else "<unknown>"
127 - assert "libhip_stub.so" not in source, source
128 - assert "libamdhip64.so" in source, source
96 + if result.returncode != 0:
97 + pytest.fail(f"HIP symbols were hijacked:\n{result.stdout}\n{result.stderr}")