main
py 115 lines 3.99 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import contextlib
5 import time
6 from collections.abc import Generator
7
8 from vllm.config import CompilationMode, VllmConfig
9 from vllm.logger import init_logger
10
11 logger = init_logger(__name__)
12
13 # Shared global so backends.py can read the start time for Dynamo timing.
14 torch_compile_start_time: float = 0.0
15
16
17 @contextlib.contextmanager
18 def monitor_torch_compile(
19 vllm_config: VllmConfig,
20 message: str = "%storch.compile took %.2f s in total",
21 is_encoder: bool = False,
22 tag: str = "",
23 announce_start: bool = True,
24 ) -> Generator[None, None, None]:
25 """Context manager that times torch.compile and manages depyf debugging.
26
27 On normal exit: logs the compile time and exits depyf.
28 On exception: cleans up depyf without logging (compilation failed).
29
30 ``announce_start=False`` suppresses the "Starting torch.compile" line;
31 used by the AOT-load probe so a failed load attempt doesn't announce a
32 compile it didn't perform.
33 """
34 global torch_compile_start_time
35 torch_compile_start_time = time.perf_counter()
36
37 compilation_config = vllm_config.compilation_config
38 log_prefix = f"[{tag}] " if tag else ""
39 if announce_start and compilation_config.mode == CompilationMode.VLLM_COMPILE:
40 logger.info("%sStarting torch.compile", log_prefix)
41 depyf_cm = None
42 path = vllm_config.compile_debug_dump_path()
43 if compilation_config.mode == CompilationMode.VLLM_COMPILE and path:
44 import depyf
45
46 path.mkdir(parents=True, exist_ok=True)
47 logger.debug("Dumping depyf output to %s", path)
48 depyf_cm = depyf.prepare_debug(path.as_posix())
49 depyf_cm.__enter__()
50
51 try:
52 yield
53 except Exception:
54 raise
55 else:
56 total_compile_time = time.perf_counter() - torch_compile_start_time
57 if compilation_config.mode == CompilationMode.VLLM_COMPILE:
58 if is_encoder:
59 compilation_config.encoder_compilation_time += total_compile_time
60 else:
61 compilation_config.compilation_time += total_compile_time
62 logger.info(message, log_prefix, total_compile_time)
63 finally:
64 if depyf_cm is not None:
65 try:
66 depyf_cm.__exit__(None, None, None)
67 except Exception:
68 logger.warning("Exception during depyf cleanup.", exc_info=True)
69
70
71 @contextlib.contextmanager
72 def monitor_profiling_run(tag: str = "") -> Generator[None, None, None]:
73 """Context manager that times the initial profiling run.
74
75 Asserts that no backend compilation occurs during the profiling run
76 (all compilation should have completed before this point).
77 """
78 from vllm.compilation.counter import compilation_counter
79
80 backend_compilations_before = compilation_counter.num_backend_compilations
81 start = time.perf_counter()
82 yield
83 elapsed = time.perf_counter() - start
84 assert (
85 compilation_counter.num_backend_compilations == backend_compilations_before
86 ), (
87 "backend compilation occurred during the initial profiling run; "
88 "all compilation should be complete before the profiling run starts."
89 )
90 log_prefix = f"[{tag}] " if tag else ""
91 logger.info(
92 "%sInitial profiling/warmup run took %.2f s",
93 log_prefix,
94 elapsed,
95 )
96
97
98 cudagraph_capturing_enabled: bool = True
99
100
101 def validate_cudagraph_capturing_enabled() -> None:
102 # used to monitor whether a cudagraph capturing is legal at runtime.
103 # should be called before any cudagraph capturing.
104 # if an illegal cudagraph capturing happens, raise an error.
105 global cudagraph_capturing_enabled
106 if not cudagraph_capturing_enabled:
107 raise RuntimeError(
108 "CUDA graph capturing detected at an inappropriate "
109 "time. This operation is currently disabled."
110 )
111
112
113 def set_cudagraph_capturing_enabled(enabled: bool) -> None:
114 global cudagraph_capturing_enabled
115 cudagraph_capturing_enabled = enabled