main
py 135 lines 4.76 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import os
5 import types
6 from importlib.metadata import version
7 from importlib.util import find_spec
8
9 from vllm.logger import init_logger
10 from vllm.platforms import current_platform
11 from vllm.utils.math_utils import cdiv
12
13 logger = init_logger(__name__)
14
15 HAS_TRITON = (
16 find_spec("triton") is not None
17 or find_spec("pytorch-triton-xpu") is not None # Not compatible
18 )
19 if HAS_TRITON:
20 try:
21 from triton.backends import backends
22
23 # It's generally expected that x.driver exists and has
24 # an is_active method.
25 # The `x.driver and` check adds a small layer of safety.
26 # The "cpu" backend's driver reports itself active unconditionally, so
27 # it must be excluded here or every GPU host looks like it has 2 active
28 # drivers. Triton's own driver selection skips it for the same reason
29 # (see triton.runtime.driver._create_driver): CPU is only ever used
30 # when explicitly selected.
31 active_drivers = [
32 x.driver
33 for name, x in backends.items()
34 if name != "cpu" and x.driver and x.driver.is_active()
35 ]
36
37 # Check Triton CPU
38 if "cpu" in version("vllm"):
39 if "cpu" in backends:
40 HAS_TRITON = True
41 # Suppress following warnings on CPU-only platforms
42 if len(active_drivers) == 0:
43 active_drivers.append(backends["cpu"].driver)
44 else:
45 logger.warning(
46 "Triton is installed, but doesn't include CPU backend. "
47 "Disabling Triton."
48 )
49 HAS_TRITON = False
50
51 # Check if we're in a distributed environment where CUDA_VISIBLE_DEVICES
52 # or HIP_VISIBLE_DEVICES might be temporarily empty (e.g., Ray sets it to ""
53 # during actor init)
54 visible_devices_env = (
55 "HIP_VISIBLE_DEVICES"
56 if current_platform.is_rocm()
57 else "CUDA_VISIBLE_DEVICES"
58 )
59 visible_devices = os.environ.get(visible_devices_env)
60 is_distributed_env = (
61 visible_devices is not None and len(visible_devices.strip()) == 0
62 )
63
64 # Apply lenient driver check for distributed environments
65 if is_distributed_env and len(active_drivers) == 0:
66 # Allow 0 drivers in distributed environments - they may become
67 # active later when CUDA context is properly initialized
68 logger.debug(
69 "Triton found 0 active drivers in distributed environment. "
70 "This is expected during initialization."
71 )
72 elif not is_distributed_env and len(active_drivers) != 1:
73 # Strict check for non-distributed environments
74 logger.info(
75 "Triton is installed but %d active driver(s) found "
76 "(expected 1). Disabling Triton to prevent runtime errors.",
77 len(active_drivers),
78 )
79 HAS_TRITON = False
80 except ImportError:
81 # This can occur if Triton is partially installed or triton.backends
82 # is missing.
83 logger.warning(
84 "Triton is installed, but `triton.backends` could not be imported. "
85 "Disabling Triton."
86 )
87 HAS_TRITON = False
88 except Exception as e:
89 # Catch any other unexpected errors during the check.
90 logger.warning(
91 "An unexpected error occurred while checking Triton active drivers:"
92 " %s. Disabling Triton.",
93 e,
94 )
95 HAS_TRITON = False
96
97 if not HAS_TRITON:
98 logger.info(
99 "Triton not installed or not compatible; certain GPU-related"
100 " functions will not be available."
101 )
102
103
104 class TritonPlaceholder(types.ModuleType):
105 def __init__(self):
106 super().__init__("triton")
107 self.__version__ = "3.4.0"
108 self.jit = self._dummy_decorator("jit")
109 self.autotune = self._dummy_decorator("autotune")
110 self.heuristics = self._dummy_decorator("heuristics")
111 self.Config = self._dummy_decorator("Config")
112 self.cdiv = cdiv
113 self.language = TritonLanguagePlaceholder()
114
115 def _dummy_decorator(self, name):
116 def decorator(*args, **kwargs):
117 if args and callable(args[0]):
118 return args[0]
119 return lambda f: f
120
121 return decorator
122
123
124 class TritonLanguagePlaceholder(types.ModuleType):
125 def __init__(self):
126 super().__init__("triton.language")
127 self.constexpr = lambda value: value
128 self.dtype = None
129 self.int64 = None
130 self.int32 = None
131 self.tensor = None
132 self.exp = None
133 self.exp2 = None
134 self.log = None
135 self.log2 = None