main
py 1,082 lines 34.2 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # ruff: noqa
5 # code borrowed from https://github.com/pytorch/pytorch/blob/main/torch/utils/collect_env.py
6
7 import datetime
8 import locale
9 import os
10 import subprocess
11 import sys
12
13 # Unlike the rest of the PyTorch this file must be python2 compliant.
14 # This script outputs relevant system environment info
15 # Run it with `python collect_env.py` or `python -m torch.utils.collect_env`
16 from collections import namedtuple
17
18 import regex as re
19
20 from vllm.envs import environment_variables
21
22 try:
23 import torch
24
25 TORCH_AVAILABLE = True
26 except (ImportError, NameError, AttributeError, OSError):
27 TORCH_AVAILABLE = False
28
29 # System Environment Information
30 SystemEnv = namedtuple(
31 "SystemEnv",
32 [
33 "torch_version",
34 "is_debug_build",
35 "cuda_compiled_version",
36 "gcc_version",
37 "clang_version",
38 "cmake_version",
39 "os",
40 "libc_version",
41 "python_version",
42 "python_platform",
43 "is_cuda_available",
44 "cuda_runtime_version",
45 "cuda_module_loading",
46 "nvidia_driver_version",
47 "nvidia_gpu_models",
48 "cudnn_version",
49 "xpu_available",
50 "xpu_runtime_version",
51 "intel_graphics_compiler_version",
52 "intel_gpu_models",
53 "oneapi_compiler_version",
54 "level_zero_loader_version",
55 "level_zero_driver_version",
56 "oneccl_version",
57 "libigdgmm_version",
58 "vllm_xpu_kernels_version",
59 "sycl_version",
60 "pip_version", # 'pip' or 'pip3'
61 "pip_packages",
62 "conda_packages",
63 "hip_compiled_version",
64 "hip_runtime_version",
65 "miopen_runtime_version",
66 "caching_allocator_config",
67 "is_xnnpack_available",
68 "cpu_info",
69 "rocm_version", # vllm specific field
70 "vllm_version", # vllm specific field
71 "vllm_build_flags", # vllm specific field
72 "gpu_topo", # vllm specific field
73 "env_vars",
74 ],
75 )
76
77 DEFAULT_CONDA_PATTERNS = {
78 "torch",
79 "numpy",
80 "cudatoolkit",
81 "soumith",
82 "mkl",
83 "magma",
84 "triton",
85 "optree",
86 "nccl",
87 "transformers",
88 "zmq",
89 "nvidia",
90 "pynvml",
91 "flashinfer-python",
92 "helion",
93 }
94
95 DEFAULT_PIP_PATTERNS = {
96 "torch",
97 "numpy",
98 "mypy",
99 "flake8",
100 "triton",
101 "optree",
102 "onnx",
103 "nccl",
104 "transformers",
105 "zmq",
106 "nvidia",
107 "pynvml",
108 "flashinfer-python",
109 "helion",
110 }
111
112
113 def run(command):
114 """Return (return-code, stdout, stderr)."""
115 shell = True if type(command) is str else False
116 try:
117 p = subprocess.Popen(
118 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell
119 )
120 raw_output, raw_err = p.communicate()
121 rc = p.returncode
122 if get_platform() == "win32":
123 enc = "oem"
124 else:
125 enc = locale.getpreferredencoding()
126 output = raw_output.decode(enc)
127 if command == "nvidia-smi topo -m":
128 # don't remove the leading whitespace of `nvidia-smi topo -m`
129 # because they are meaningful
130 output = output.rstrip()
131 else:
132 output = output.strip()
133 err = raw_err.decode(enc)
134 return rc, output, err.strip()
135
136 except FileNotFoundError:
137 cmd_str = command if isinstance(command, str) else command[0]
138 return 127, "", f"Command not found: {cmd_str}"
139
140
141 def run_and_read_all(run_lambda, command):
142 """Run command using run_lambda; reads and returns entire output if rc is 0."""
143 rc, out, _ = run_lambda(command)
144 if rc != 0:
145 return None
146 return out
147
148
149 def run_and_parse_first_match(run_lambda, command, regex):
150 """Run command using run_lambda, returns the first regex match if it exists."""
151 rc, out, _ = run_lambda(command)
152 if rc != 0:
153 return None
154 match = re.search(regex, out)
155 if match is None:
156 return None
157 return match.group(1)
158
159
160 def get_conda_packages(run_lambda, patterns=None):
161 if patterns is None:
162 patterns = DEFAULT_CONDA_PATTERNS
163 conda = os.environ.get("CONDA_EXE", "conda")
164 out = run_and_read_all(run_lambda, [conda, "list"])
165 if out is None:
166 return out
167
168 return "\n".join(
169 line
170 for line in out.splitlines()
171 if not line.startswith("#") and any(name in line for name in patterns)
172 )
173
174
175 def get_gcc_version(run_lambda):
176 return run_and_parse_first_match(run_lambda, "gcc --version", r"gcc (.*)")
177
178
179 def get_clang_version(run_lambda):
180 return run_and_parse_first_match(
181 run_lambda, "clang --version", r"clang version (.*)"
182 )
183
184
185 def get_cmake_version(run_lambda):
186 return run_and_parse_first_match(run_lambda, "cmake --version", r"cmake (.*)")
187
188
189 def get_nvidia_driver_version(run_lambda):
190 if get_platform() == "darwin":
191 cmd = "kextstat | grep -i cuda"
192 return run_and_parse_first_match(
193 run_lambda, cmd, r"com[.]nvidia[.]CUDA [(](.*?)[)]"
194 )
195 smi = get_nvidia_smi()
196 return run_and_parse_first_match(run_lambda, smi, r"Driver Version: (.*?) ")
197
198
199 def get_gpu_info(run_lambda):
200 if get_platform() == "darwin" or (
201 TORCH_AVAILABLE
202 and hasattr(torch.version, "hip")
203 and torch.version.hip is not None
204 ):
205 if TORCH_AVAILABLE and torch.cuda.is_available():
206 if torch.version.hip is not None:
207 prop = torch.cuda.get_device_properties(0)
208 if hasattr(prop, "gcnArchName"):
209 gcnArch = " ({})".format(prop.gcnArchName)
210 else:
211 gcnArch = "NoGCNArchNameOnOldPyTorch"
212 else:
213 gcnArch = ""
214 return torch.cuda.get_device_name(None) + gcnArch
215 return None
216 smi = get_nvidia_smi()
217 uuid_regex = re.compile(r" \(UUID: .+?\)")
218 rc, out, _ = run_lambda(smi + " -L")
219 if rc != 0:
220 return None
221 # Anonymize GPUs by removing their UUID
222 return re.sub(uuid_regex, "", out)
223
224
225 def get_running_cuda_version(run_lambda):
226 return run_and_parse_first_match(run_lambda, "nvcc --version", r"release .+ V(.*)")
227
228
229 def get_cudnn_version(run_lambda):
230 """Return a list of libcudnn.so; it's hard to tell which one is being used."""
231 if get_platform() == "win32":
232 system_root = os.environ.get("SYSTEMROOT", "C:\\Windows")
233 cuda_path = os.environ.get("CUDA_PATH", "%CUDA_PATH%")
234 where_cmd = os.path.join(system_root, "System32", "where")
235 cudnn_cmd = '{} /R "{}\\bin" cudnn*.dll'.format(where_cmd, cuda_path)
236 elif get_platform() == "darwin":
237 # CUDA libraries and drivers can be found in /usr/local/cuda/. See
238 # https://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html#install
239 # https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html#installmac
240 # Use CUDNN_LIBRARY when cudnn library is installed elsewhere.
241 cudnn_cmd = "ls /usr/local/cuda/lib/libcudnn*"
242 else:
243 cudnn_cmd = 'ldconfig -p | grep libcudnn | rev | cut -d" " -f1 | rev'
244 rc, out, _ = run_lambda(cudnn_cmd)
245 # find will return 1 if there are permission errors or if not found
246 if len(out) == 0 or (rc != 1 and rc != 0):
247 l = os.environ.get("CUDNN_LIBRARY")
248 if l is not None and os.path.isfile(l):
249 return os.path.realpath(l)
250 return None
251 files_set = set()
252 for fn in out.split("\n"):
253 fn = os.path.realpath(fn) # eliminate symbolic links
254 if os.path.isfile(fn):
255 files_set.add(fn)
256 if not files_set:
257 return None
258 # Alphabetize the result because the order is non-deterministic otherwise
259 files = sorted(files_set)
260 if len(files) == 1:
261 return files[0]
262 result = "\n".join(files)
263 return "Probably one of the following:\n{}".format(result)
264
265
266 def get_nvidia_smi():
267 # Note: nvidia-smi is currently available only on Windows and Linux
268 smi = "nvidia-smi"
269 if get_platform() == "win32":
270 system_root = os.environ.get("SYSTEMROOT", "C:\\Windows")
271 program_files_root = os.environ.get("PROGRAMFILES", "C:\\Program Files")
272 legacy_path = os.path.join(
273 program_files_root, "NVIDIA Corporation", "NVSMI", smi
274 )
275 new_path = os.path.join(system_root, "System32", smi)
276 smis = [new_path, legacy_path]
277 for candidate_smi in smis:
278 if os.path.exists(candidate_smi):
279 smi = '"{}"'.format(candidate_smi)
280 break
281 return smi
282
283
284 def get_rocm_version(run_lambda):
285 """Returns the ROCm version if available, otherwise 'N/A'."""
286 return run_and_parse_first_match(
287 run_lambda, "hipcc --version", r"HIP version: (\S+)"
288 )
289
290
291 def get_xpu_available():
292 if TORCH_AVAILABLE and hasattr(torch, "xpu") and torch.xpu.is_available():
293 return True
294 return False
295
296
297 def get_xpu_runtime_version():
298 if TORCH_AVAILABLE and hasattr(torch.version, "xpu"):
299 return torch.version.xpu
300 return None
301
302
303 def get_pkg_version(run_lambda, pkg):
304 assert get_platform() == "linux"
305
306 if pkg in ["vllm_xpu_kernels", "oneccl"]:
307 rc, out, _ = run_lambda(f"pip show {pkg}")
308 if rc == 0:
309 match = re.search(r"Version: (.*)", out)
310 return match.group(1).strip() if match else None
311 return None
312
313 pkg_map = {
314 "igc": ["intel-igc-core", "libigc2", "libigc1"],
315 "level_zero_loader": ["level-zero", "libze1"],
316 "level_zero_driver": ["libze-intel-gpu1", "intel-level-zero-gpu"],
317 "libigdgmm": ["libigdgmm12", "libigdgmm"],
318 }
319
320 pkg_candidates = pkg_map.get(pkg, [])
321 if not pkg_candidates:
322 return None
323
324 mgr_name = None
325 for mgr in ["dpkg", "dnf", "yum", "zypper"]:
326 rc, _, _ = run_lambda(f"which {mgr}")
327 if rc == 0:
328 mgr_name = mgr
329 break
330
331 if not mgr_name:
332 return None
333
334 ret = ""
335 index = -1
336
337 for pkg_name in pkg_candidates:
338 if not pkg_name:
339 continue
340
341 cmd = ""
342 if mgr_name in ["dnf", "yum"]:
343 index = 1
344 cmd = f"{mgr_name} list | grep -w {pkg_name}"
345 elif mgr_name == "zypper":
346 index = 2
347 cmd = f"{mgr_name} info {pkg_name} | grep Version"
348 elif mgr_name == "dpkg":
349 index = 2
350 cmd = f"{mgr_name} -l | grep -w {pkg_name}"
351
352 if cmd:
353 out = run_and_read_all(run_lambda, cmd)
354 if out:
355 ret = out.splitlines()[0]
356 break
357
358 if not ret or index == -1:
359 return None
360
361 lst = re.sub(" +", " ", ret).strip().split(" ")
362 if len(lst) > index:
363 return lst[index]
364
365 return None
366
367
368 def get_intel_graphics_compiler_version(run_lambda):
369 """Return Intel Graphics Compiler (IGC) version."""
370 return get_pkg_version(run_lambda, "igc")
371
372
373 def get_level_zero_loader_version(run_lambda):
374 """Return Level Zero loader runtime version."""
375 return get_pkg_version(run_lambda, "level_zero_loader")
376
377
378 def get_level_zero_driver_version(run_lambda):
379 """Return Level Zero driver version."""
380 return get_pkg_version(run_lambda, "level_zero_driver")
381
382
383 def get_oneapi_ccl_version(run_lambda):
384 """Return oneAPI Collective Communications Library (oneCCL) version."""
385 return get_pkg_version(run_lambda, "oneccl")
386
387
388 def get_libigdgmm_version(run_lambda):
389 return get_pkg_version(run_lambda, "libigdgmm")
390
391
392 def get_vllm_xpu_kernels_version(run_lambda):
393 return get_pkg_version(run_lambda, "vllm_xpu_kernels")
394
395
396 def get_intel_gpu_models():
397 if TORCH_AVAILABLE and hasattr(torch, "xpu") and torch.xpu.is_available():
398 device_count = torch.xpu.device_count()
399 return "\n".join(
400 "GPU {}: {}".format(i, torch.xpu.get_device_name(i))
401 for i in range(device_count)
402 )
403 return None
404
405
406 def get_oneapi_compiler_version(run_lambda):
407 """Return Intel oneAPI DPC++/C++ Compiler version via icpx."""
408 return run_and_parse_first_match(
409 run_lambda, "icpx --version", r"oneAPI DPC\+\+/C\+\+ Compiler (\S+)"
410 )
411
412
413 def get_sycl_version(run_lambda):
414 """Return SYCL/DPC++ compiler build version."""
415 return run_and_parse_first_match(run_lambda, "icpx --version", r"\((\d[\d.]+)\)")
416
417
418 def get_vllm_version():
419 from vllm import __version__, __version_tuple__
420
421 if __version__ == "dev":
422 return "N/A (dev)"
423 version_str = __version_tuple__[-1]
424 if isinstance(version_str, str) and version_str.startswith("g"):
425 # it's a dev build
426 if "." in version_str:
427 # it's a dev build containing local changes
428 git_sha = version_str.split(".")[0][1:]
429 date = version_str.split(".")[-1][1:]
430 return f"{__version__} (git sha: {git_sha}, date: {date})"
431 else:
432 # it's a dev build without local changes
433 git_sha = version_str[1:] # type: ignore
434 return f"{__version__} (git sha: {git_sha})"
435 return __version__
436
437
438 def summarize_vllm_build_flags():
439 flags = "CUDA Archs: {}; ROCm: {}; XPU: {}".format(
440 os.environ.get("TORCH_CUDA_ARCH_LIST", "Not Set"),
441 "Enabled" if os.environ.get("ROCM_HOME") else "Disabled",
442 "Enabled" if get_xpu_available() else "Disabled",
443 )
444 return flags
445
446
447 def get_gpu_topo(run_lambda):
448 output = None
449
450 if get_platform() == "linux":
451 output = run_and_read_all(run_lambda, "nvidia-smi topo -m")
452 if output is None:
453 output = run_and_read_all(run_lambda, "rocm-smi --showtopo")
454
455 return output
456
457
458 # example outputs of CPU infos
459 # * linux
460 # Architecture: x86_64
461 # CPU op-mode(s): 32-bit, 64-bit
462 # Address sizes: 46 bits physical, 48 bits virtual
463 # Byte Order: Little Endian
464 # CPU(s): 128
465 # On-line CPU(s) list: 0-127
466 # Vendor ID: GenuineIntel
467 # Model name: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
468 # CPU family: 6
469 # Model: 106
470 # Thread(s) per core: 2
471 # Core(s) per socket: 32
472 # Socket(s): 2
473 # Stepping: 6
474 # BogoMIPS: 5799.78
475 # Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr
476 # sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl
477 # xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16
478 # pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand
479 # hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced
480 # fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap
481 # avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1
482 # xsaves wbnoinvd ida arat avx512vbmi pku ospke avx512_vbmi2 gfni vaes vpclmulqdq
483 # avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid md_clear flush_l1d arch_capabilities
484 # Virtualization features:
485 # Hypervisor vendor: KVM
486 # Virtualization type: full
487 # Caches (sum of all):
488 # L1d: 3 MiB (64 instances)
489 # L1i: 2 MiB (64 instances)
490 # L2: 80 MiB (64 instances)
491 # L3: 108 MiB (2 instances)
492 # NUMA:
493 # NUMA node(s): 2
494 # NUMA node0 CPU(s): 0-31,64-95
495 # NUMA node1 CPU(s): 32-63,96-127
496 # Vulnerabilities:
497 # Itlb multihit: Not affected
498 # L1tf: Not affected
499 # Mds: Not affected
500 # Meltdown: Not affected
501 # Mmio stale data: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown
502 # Retbleed: Not affected
503 # Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
504 # Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
505 # Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS SW sequence
506 # Srbds: Not affected
507 # Tsx async abort: Not affected
508 # * win32
509 # Architecture=9
510 # CurrentClockSpeed=2900
511 # DeviceID=CPU0
512 # Family=179
513 # L2CacheSize=40960
514 # L2CacheSpeed=
515 # Manufacturer=GenuineIntel
516 # MaxClockSpeed=2900
517 # Name=Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
518 # ProcessorType=3
519 # Revision=27142
520 #
521 # Architecture=9
522 # CurrentClockSpeed=2900
523 # DeviceID=CPU1
524 # Family=179
525 # L2CacheSize=40960
526 # L2CacheSpeed=
527 # Manufacturer=GenuineIntel
528 # MaxClockSpeed=2900
529 # Name=Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
530 # ProcessorType=3
531 # Revision=27142
532
533
534 def get_cpu_info(run_lambda):
535 rc, out, err = 0, "", ""
536 if get_platform() == "linux":
537 rc, out, err = run_lambda("lscpu")
538 elif get_platform() == "win32":
539 rc, out, err = run_lambda(
540 "wmic cpu get Name,Manufacturer,Family,Architecture,ProcessorType,DeviceID, \
541 CurrentClockSpeed,MaxClockSpeed,L2CacheSize,L2CacheSpeed,Revision /VALUE"
542 )
543 elif get_platform() == "darwin":
544 rc, out, err = run_lambda("sysctl -n machdep.cpu.brand_string")
545 cpu_info = "None"
546 if rc == 0:
547 cpu_info = out
548 else:
549 cpu_info = err
550 return cpu_info
551
552
553 def get_platform():
554 if sys.platform.startswith("linux"):
555 return "linux"
556 elif sys.platform.startswith("win32"):
557 return "win32"
558 elif sys.platform.startswith("cygwin"):
559 return "cygwin"
560 elif sys.platform.startswith("darwin"):
561 return "darwin"
562 else:
563 return sys.platform
564
565
566 def get_mac_version(run_lambda):
567 return run_and_parse_first_match(run_lambda, "sw_vers -productVersion", r"(.*)")
568
569
570 def get_windows_version(run_lambda):
571 system_root = os.environ.get("SYSTEMROOT", "C:\\Windows")
572 wmic_cmd = os.path.join(system_root, "System32", "Wbem", "wmic")
573 findstr_cmd = os.path.join(system_root, "System32", "findstr")
574 return run_and_read_all(
575 run_lambda, "{} os get Caption | {} /v Caption".format(wmic_cmd, findstr_cmd)
576 )
577
578
579 def get_lsb_version(run_lambda):
580 return run_and_parse_first_match(
581 run_lambda, "lsb_release -a", r"Description:\t(.*)"
582 )
583
584
585 def check_release_file(run_lambda):
586 return run_and_parse_first_match(
587 run_lambda, "cat /etc/*-release", r'PRETTY_NAME="(.*)"'
588 )
589
590
591 def get_os(run_lambda):
592 from platform import machine
593
594 platform = get_platform()
595
596 if platform == "win32" or platform == "cygwin":
597 return get_windows_version(run_lambda)
598
599 if platform == "darwin":
600 version = get_mac_version(run_lambda)
601 if version is None:
602 return None
603 return "macOS {} ({})".format(version, machine())
604
605 if platform == "linux":
606 # Ubuntu/Debian based
607 desc = get_lsb_version(run_lambda)
608 if desc is not None:
609 return "{} ({})".format(desc, machine())
610
611 # Try reading /etc/*-release
612 desc = check_release_file(run_lambda)
613 if desc is not None:
614 return "{} ({})".format(desc, machine())
615
616 return "{} ({})".format(platform, machine())
617
618 # Unknown platform
619 return platform
620
621
622 def get_python_platform():
623 import platform
624
625 return platform.platform()
626
627
628 def get_libc_version():
629 import platform
630
631 if get_platform() != "linux":
632 return "N/A"
633 return "-".join(platform.libc_ver())
634
635
636 def is_uv_venv():
637 if os.environ.get("UV"):
638 return True
639 pyvenv_cfg_path = os.path.join(sys.prefix, "pyvenv.cfg")
640 if os.path.exists(pyvenv_cfg_path):
641 with open(pyvenv_cfg_path, "r") as f:
642 return any(line.startswith("uv = ") for line in f)
643 return False
644
645
646 def get_pip_packages(run_lambda, patterns=None):
647 """Return `pip list` output. Note: will also find conda-installed pytorch and numpy packages."""
648 if patterns is None:
649 patterns = DEFAULT_PIP_PATTERNS
650
651 def run_with_pip():
652 try:
653 import importlib.util
654
655 pip_spec = importlib.util.find_spec("pip")
656 pip_available = pip_spec is not None
657 except ImportError:
658 pip_available = False
659
660 if pip_available:
661 cmd = [sys.executable, "-mpip", "list", "--format=freeze"]
662 elif is_uv_venv():
663 print("uv is set")
664 cmd = ["uv", "pip", "list", "--format=freeze"]
665 else:
666 raise RuntimeError(
667 "Could not collect pip list output (pip or uv module not available)"
668 )
669
670 out = run_and_read_all(run_lambda, cmd)
671 return "\n".join(
672 line for line in out.splitlines() if any(name in line for name in patterns)
673 )
674
675 pip_version = "pip3" if sys.version[0] == "3" else "pip"
676 out = run_with_pip()
677 return pip_version, out
678
679
680 def get_cachingallocator_config():
681 ca_config = os.environ.get("PYTORCH_CUDA_ALLOC_CONF", "")
682 return ca_config
683
684
685 def get_cuda_module_loading_config():
686 if TORCH_AVAILABLE and torch.cuda.is_available():
687 torch.cuda.init()
688 config = os.environ.get("CUDA_MODULE_LOADING", "")
689 return config
690 else:
691 return "N/A"
692
693
694 def is_xnnpack_available():
695 if TORCH_AVAILABLE:
696 import torch.backends.xnnpack
697
698 return str(torch.backends.xnnpack.enabled) # type: ignore[attr-defined]
699 else:
700 return "N/A"
701
702
703 def get_env_vars():
704 env_vars = ""
705 secret_terms = ("secret", "token", "api", "access", "password")
706 report_prefix = (
707 "TORCH",
708 "NCCL",
709 "PYTORCH",
710 "CUDA",
711 "CUBLAS",
712 "CUDNN",
713 "OMP_",
714 "MKL_",
715 "NVIDIA",
716 "ZE_",
717 "ONEAPI_",
718 "SYCL_",
719 "NEOReadDebugKeys",
720 "IGC_",
721 "CCL_",
722 "I_MPI_",
723 )
724 for k, v in os.environ.items():
725 if any(term in k.lower() for term in secret_terms):
726 continue
727 if k in environment_variables:
728 env_vars = env_vars + "{}={}".format(k, v) + "\n"
729 if k.startswith(report_prefix):
730 env_vars = env_vars + "{}={}".format(k, v) + "\n"
731
732 return env_vars
733
734
735 def get_env_info():
736 run_lambda = run
737 pip_version, pip_list_output = get_pip_packages(run_lambda)
738
739 if TORCH_AVAILABLE:
740 version_str = torch.__version__
741 debug_mode_str = str(torch.version.debug)
742 cuda_available_str = str(torch.cuda.is_available())
743 cuda_version_str = torch.version.cuda
744 if (
745 not hasattr(torch.version, "hip") or torch.version.hip is None
746 ): # cuda version
747 hip_compiled_version = hip_runtime_version = miopen_runtime_version = "N/A"
748 else: # HIP version
749
750 def get_version_or_na(cfg, prefix):
751 _lst = [s.rsplit(None, 1)[-1] for s in cfg if prefix in s]
752 return _lst[0] if _lst else "N/A"
753
754 cfg = torch._C._show_config().split("\n")
755 hip_runtime_version = get_version_or_na(cfg, "HIP Runtime")
756 miopen_runtime_version = get_version_or_na(cfg, "MIOpen")
757 cuda_version_str = "N/A"
758 hip_compiled_version = torch.version.hip
759 else:
760 version_str = debug_mode_str = cuda_available_str = cuda_version_str = "N/A"
761 hip_compiled_version = hip_runtime_version = miopen_runtime_version = "N/A"
762
763 sys_version = sys.version.replace("\n", " ")
764
765 conda_packages = get_conda_packages(run_lambda)
766
767 rocm_version = get_rocm_version(run_lambda)
768 vllm_version = get_vllm_version()
769 vllm_build_flags = summarize_vllm_build_flags()
770 gpu_topo = get_gpu_topo(run_lambda)
771
772 return SystemEnv(
773 torch_version=version_str,
774 is_debug_build=debug_mode_str,
775 python_version="{} ({}-bit runtime)".format(
776 sys_version, sys.maxsize.bit_length() + 1
777 ),
778 python_platform=get_python_platform(),
779 is_cuda_available=cuda_available_str,
780 cuda_compiled_version=cuda_version_str,
781 cuda_runtime_version=get_running_cuda_version(run_lambda),
782 cuda_module_loading=get_cuda_module_loading_config(),
783 nvidia_gpu_models=get_gpu_info(run_lambda),
784 nvidia_driver_version=get_nvidia_driver_version(run_lambda),
785 cudnn_version=get_cudnn_version(run_lambda),
786 xpu_available=str(get_xpu_available()),
787 xpu_runtime_version=get_xpu_runtime_version(),
788 intel_graphics_compiler_version=get_intel_graphics_compiler_version(run_lambda),
789 intel_gpu_models=get_intel_gpu_models(),
790 oneapi_compiler_version=get_oneapi_compiler_version(run_lambda),
791 level_zero_loader_version=get_level_zero_loader_version(run_lambda),
792 level_zero_driver_version=get_level_zero_driver_version(run_lambda),
793 oneccl_version=get_oneapi_ccl_version(run_lambda),
794 libigdgmm_version=get_libigdgmm_version(run_lambda),
795 vllm_xpu_kernels_version=get_vllm_xpu_kernels_version(run_lambda),
796 sycl_version=get_sycl_version(run_lambda),
797 hip_compiled_version=hip_compiled_version,
798 hip_runtime_version=hip_runtime_version,
799 miopen_runtime_version=miopen_runtime_version,
800 pip_version=pip_version,
801 pip_packages=pip_list_output,
802 conda_packages=conda_packages,
803 os=get_os(run_lambda),
804 libc_version=get_libc_version(),
805 gcc_version=get_gcc_version(run_lambda),
806 clang_version=get_clang_version(run_lambda),
807 cmake_version=get_cmake_version(run_lambda),
808 caching_allocator_config=get_cachingallocator_config(),
809 is_xnnpack_available=is_xnnpack_available(),
810 cpu_info=get_cpu_info(run_lambda),
811 rocm_version=rocm_version,
812 vllm_version=vllm_version,
813 vllm_build_flags=vllm_build_flags,
814 gpu_topo=gpu_topo,
815 env_vars=get_env_vars(),
816 )
817
818
819 env_info_fmt = """
820 ==============================
821 System Info
822 ==============================
823 OS : {os}
824 GCC version : {gcc_version}
825 Clang version : {clang_version}
826 CMake version : {cmake_version}
827 Libc version : {libc_version}
828
829 ==============================
830 PyTorch Info
831 ==============================
832 PyTorch version : {torch_version}
833 Is debug build : {is_debug_build}
834 CUDA used to build PyTorch : {cuda_compiled_version}
835 ROCM used to build PyTorch : {hip_compiled_version}
836 XPU used to build PyTorch : {xpu_runtime_version}
837
838 ==============================
839 Python Environment
840 ==============================
841 Python version : {python_version}
842 Python platform : {python_platform}
843
844 {gpu_info}
845 ==============================
846 CPU Info
847 ==============================
848 {cpu_info}
849
850 ==============================
851 Versions of relevant libraries
852 ==============================
853 {pip_packages}
854 {conda_packages}
855 """.strip()
856
857 # both the above code and the following code use `strip()` to
858 # remove leading/trailing whitespaces, so we need to add a newline
859 # in between to separate the two sections
860 env_info_fmt += "\n\n"
861
862 env_info_fmt += """
863 ==============================
864 vLLM Info
865 ==============================
866 ROCM Version : {rocm_version}
867 vLLM Version : {vllm_version}
868 vLLM Build Flags:
869 {vllm_build_flags}
870 GPU Topology:
871 {gpu_topo}
872
873 ==============================
874 Environment Variables
875 ==============================
876 {env_vars}
877 """.strip()
878
879
880 def pretty_str(envinfo):
881 def replace_nones(dct, replacement="Could not collect"):
882 for key in dct.keys():
883 if dct[key] is not None:
884 continue
885 dct[key] = replacement
886 return dct
887
888 def replace_bools(dct, true="Yes", false="No"):
889 for key in dct.keys():
890 if dct[key] is True:
891 dct[key] = true
892 elif dct[key] is False:
893 dct[key] = false
894 return dct
895
896 def prepend(text, tag="[prepend]"):
897 lines = text.split("\n")
898 updated_lines = [tag + line for line in lines]
899 return "\n".join(updated_lines)
900
901 def replace_if_empty(text, replacement="No relevant packages"):
902 if text is not None and len(text) == 0:
903 return replacement
904 return text
905
906 def maybe_start_on_next_line(string):
907 # If `string` is multiline, prepend a \n to it.
908 if string is not None and len(string.split("\n")) > 1:
909 return "\n{}\n".format(string)
910 return string
911
912 mutable_dict = envinfo._asdict()
913
914 # If nvidia_gpu_models is multiline, start on the next line
915 mutable_dict["nvidia_gpu_models"] = maybe_start_on_next_line(
916 envinfo.nvidia_gpu_models
917 )
918
919 # If the machine doesn't have CUDA, report some fields as 'No CUDA'
920 dynamic_cuda_fields = [
921 "cuda_runtime_version",
922 "nvidia_gpu_models",
923 "nvidia_driver_version",
924 ]
925 all_cuda_fields = dynamic_cuda_fields + ["cudnn_version"]
926 all_dynamic_cuda_fields_missing = all(
927 mutable_dict[field] is None for field in dynamic_cuda_fields
928 )
929 if (
930 TORCH_AVAILABLE
931 and not torch.cuda.is_available()
932 and all_dynamic_cuda_fields_missing
933 ):
934 for field in all_cuda_fields:
935 mutable_dict[field] = "No CUDA"
936 if envinfo.cuda_compiled_version is None:
937 mutable_dict["cuda_compiled_version"] = "None"
938
939 # If the machine doesn't have XPU, report XPU fields as 'No XPU'
940 dynamic_xpu_fields = [
941 "intel_graphics_compiler_version",
942 "intel_gpu_models",
943 "level_zero_loader_version",
944 "level_zero_driver_version",
945 "oneccl_version",
946 "libigdgmm_version",
947 "vllm_xpu_kernels_version",
948 ]
949 all_xpu_fields = dynamic_xpu_fields + [
950 "oneapi_compiler_version",
951 "sycl_version",
952 ]
953 all_dynamic_xpu_fields_missing = all(
954 mutable_dict[field] is None for field in dynamic_xpu_fields
955 )
956 xpu_available = mutable_dict.get("xpu_available") == "True"
957 if not xpu_available and all_dynamic_xpu_fields_missing:
958 for field in all_xpu_fields:
959 mutable_dict[field] = "No XPU"
960 if envinfo.xpu_runtime_version is None or envinfo.xpu_runtime_version == "N/A":
961 mutable_dict["xpu_runtime_version"] = "N/A"
962
963 # If intel_gpu_models is multiline, start on the next line
964 mutable_dict["intel_gpu_models"] = maybe_start_on_next_line(
965 mutable_dict.get("intel_gpu_models")
966 )
967
968 # Replace True with Yes, False with No
969 mutable_dict = replace_bools(mutable_dict)
970
971 # Replace all None objects with 'Could not collect'
972 mutable_dict = replace_nones(mutable_dict)
973
974 # If either of these are '', replace with 'No relevant packages'
975 mutable_dict["pip_packages"] = replace_if_empty(mutable_dict["pip_packages"])
976 mutable_dict["conda_packages"] = replace_if_empty(mutable_dict["conda_packages"])
977
978 # Tag conda and pip packages with a prefix
979 # If they were previously None, they'll show up as ie '[conda] Could not collect'
980 if mutable_dict["pip_packages"]:
981 mutable_dict["pip_packages"] = prepend(
982 mutable_dict["pip_packages"], "[{}] ".format(envinfo.pip_version)
983 )
984 if mutable_dict["conda_packages"]:
985 mutable_dict["conda_packages"] = prepend(
986 mutable_dict["conda_packages"], "[conda] "
987 )
988 mutable_dict["cpu_info"] = envinfo.cpu_info
989
990 CUDA_FMT = """
991 ==============================
992 CUDA / GPU Info
993 ==============================
994 Is CUDA available : {is_cuda_available}
995 CUDA runtime version : {cuda_runtime_version}
996 CUDA_MODULE_LOADING set to : {cuda_module_loading}
997 GPU models and configuration : {nvidia_gpu_models}
998 Nvidia driver version : {nvidia_driver_version}
999 cuDNN version : {cudnn_version}
1000 HIP runtime version : {hip_runtime_version}
1001 MIOpen runtime version : {miopen_runtime_version}
1002 Is XNNPACK available : {is_xnnpack_available}
1003 """.strip()
1004
1005 XPU_FMT = """
1006 ==============================
1007 Intel XPU / GPU Info
1008 ==============================
1009 Is XPU available : {xpu_available}
1010 XPU runtime version : {xpu_runtime_version}
1011 Intel GPU models : {intel_gpu_models}
1012
1013 --Compile time--
1014 oneAPI compiler version : {oneapi_compiler_version}
1015 SYCL compiler build : {sycl_version}
1016 oneCCL version : {oneccl_version}
1017
1018 --Runtime--
1019 Intel Graphics Compiler (IGC): {intel_graphics_compiler_version}
1020 Intel GMM (libigdgmm) : {libigdgmm_version}
1021 Level Zero loader version : {level_zero_loader_version}
1022 Level Zero driver version : {level_zero_driver_version}
1023 vLLM XPU kernels version : {vllm_xpu_kernels_version}
1024 """.strip()
1025
1026 invalid_vers = {"N/A", "Could not collect", "None"}
1027 sections = []
1028
1029 if (
1030 mutable_dict.get("is_cuda_available") in ("True", "Yes")
1031 or mutable_dict.get("cuda_compiled_version") not in invalid_vers
1032 ):
1033 sections.append(CUDA_FMT)
1034
1035 if (
1036 mutable_dict.get("xpu_available") in ("True", "Yes")
1037 or mutable_dict.get("xpu_runtime_version") not in invalid_vers
1038 ):
1039 sections.append(XPU_FMT)
1040
1041 mutable_dict["gpu_info"] = (
1042 ("\n\n".join(sections) + "\n").format(**mutable_dict) if sections else ""
1043 )
1044
1045 return env_info_fmt.format(**mutable_dict)
1046
1047
1048 def get_pretty_env_info():
1049 return pretty_str(get_env_info())
1050
1051
1052 def main():
1053 print("Collecting environment information...")
1054 output = get_pretty_env_info()
1055 print(output)
1056
1057 if (
1058 TORCH_AVAILABLE
1059 and hasattr(torch, "utils")
1060 and hasattr(torch.utils, "_crash_handler")
1061 ):
1062 minidump_dir = torch.utils._crash_handler.DEFAULT_MINIDUMP_DIR
1063 if sys.platform == "linux" and os.path.exists(minidump_dir):
1064 dumps = [
1065 os.path.join(minidump_dir, dump) for dump in os.listdir(minidump_dir)
1066 ]
1067 latest = max(dumps, key=os.path.getctime)
1068 ctime = os.path.getctime(latest)
1069 creation_time = datetime.datetime.fromtimestamp(ctime).strftime(
1070 "%Y-%m-%d %H:%M:%S"
1071 )
1072 msg = (
1073 "\n*** Detected a minidump at {} created on {}, ".format(
1074 latest, creation_time
1075 )
1076 + "if this is related to your bug please include it when you file a report ***"
1077 )
1078 print(msg, file=sys.stderr)
1079
1080
1081 if __name__ == "__main__":
1082 main()