@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / ba81163997
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 22:15 UTC

[core] add sleep and wake up endpoint and v1 support (#12987)

Signed-off-by: youkaichao <youkaichao@gmail.com> Signed-off-by: cennn <2523403608@qq.com> Co-authored-by: cennn <2523403608@qq.com>

youkaichao committed Feb 20, 2025 at 12:41 UTC ba81163997b1b8eb38529371a7243de3b50564fb
13 files changed +160 -9
tests/basic_correctness/test_cumem.py
+8 -4
@@ -118,14 +118,16 @@ def test_cumem_with_cudagraph():
118
119 @fork_new_process_for_each_test
120 @pytest.mark.parametrize(
121 - "model",
121 + "model, use_v1",
122 [
123 # sleep mode with safetensors
124 - f"{MODEL_WEIGHTS_S3_BUCKET}/Llama-3.2-1B",
124 + (f"{MODEL_WEIGHTS_S3_BUCKET}/Llama-3.2-1B", True),
125 # sleep mode with pytorch checkpoint
126 - "facebook/opt-125m"
126 + ("facebook/opt-125m", False),
127 ])
128 -def test_end_to_end(model):
128 +def test_end_to_end(model: str, use_v1: bool):
129 + import os
130 + os.environ["VLLM_USE_V1"] = "1" if use_v1 else "0"
131 free, total = torch.cuda.mem_get_info()
132 used_bytes_baseline = total - free # in case other process is running
133 load_format = LoadFormat.AUTO
@@ -152,3 +154,5 @@ def test_end_to_end(model):
154
155 # cmp output
156 assert output[0].outputs[0].text == output2[0].outputs[0].text
157 +
158 + del os.environ["VLLM_USE_V1"]
tests/entrypoints/openai/test_sleep.py new
+32
@@ -0,0 +1,32 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +
3 +import requests
4 +
5 +from ...utils import RemoteOpenAIServer
6 +
7 +MODEL_NAME = "meta-llama/Llama-3.2-1B"
8 +
9 +
10 +def test_sleep_mode():
11 + # dtype, max-len etc set so that this can run in CI
12 + args = [
13 + "--dtype",
14 + "bfloat16",
15 + "--max-model-len",
16 + "8192",
17 + "--max-num-seqs",
18 + "128",
19 + "--enable-sleep-mode",
20 + ]
21 +
22 + with RemoteOpenAIServer(MODEL_NAME,
23 + args,
24 + env_dict={
25 + "VLLM_SERVER_DEV_MODE": "1",
26 + "CUDA_VISIBLE_DEVICES": "0"
27 + }) as remote_server:
28 + response = requests.post(remote_server.url_for("/sleep"),
29 + data={"level": "1"})
30 + assert response.status_code == 200
31 + response = requests.post(remote_server.url_for("/wake_up"))
32 + assert response.status_code == 200
vllm/engine/async_llm_engine.py
+6
@@ -1187,6 +1187,12 @@ class AsyncLLMEngine(EngineClient):
1187 async def reset_prefix_cache(self) -> None:
1188 self.engine.reset_prefix_cache()
1189
1190 + async def sleep(self, level: int = 1) -> None:
1191 + self.engine.sleep(level)
1192 +
1193 + async def wake_up(self) -> None:
1194 + self.engine.wake_up()
1195 +
1196 async def add_lora(self, lora_request: LoRARequest) -> None:
1197 self.engine.add_lora(lora_request)
1198
vllm/engine/multiprocessing/__init__.py
+11 -1
@@ -127,6 +127,15 @@ class RPCResetPrefixCacheRequest(Enum):
127 RESET_PREFIX_CACHE = 1
128
129
130 +class RPCSleepRequest(Enum):
131 + SLEEP_LEVEL_1 = 1
132 + SLEEP_LEVEL_2 = 2
133 +
134 +
135 +class RPCWakeUpRequest(Enum):
136 + WAKE_UP = 1
137 +
138 +
139 @dataclass
140 class RPCLoadAdapterRequest:
141 lora_request: LoRARequest
@@ -141,7 +150,8 @@ class RPCAdapterLoadedResponse:
150
151 RPC_REQUEST_T = Union[RPCProcessRequest, RPCAbortRequest, RPCStartupRequest,
152 RPCUProfileRequest, RPCLoadAdapterRequest,
144 - RPCResetPrefixCacheRequest]
153 + RPCResetPrefixCacheRequest, RPCSleepRequest,
154 + RPCWakeUpRequest]
155
156 REQUEST_OUTPUTS_T = Union[List[RequestOutput], RPCAdapterLoadedResponse,
157 RPCError]
vllm/engine/multiprocessing/client.py
+13 -2
@@ -31,8 +31,9 @@ from vllm.engine.multiprocessing import (ENGINE_DEAD_ERROR, IPC_DATA_EXT,
31 RPCLoadAdapterRequest,
32 RPCProcessRequest,
33 RPCResetPrefixCacheRequest,
34 - RPCStartupRequest, RPCStartupResponse,
35 - RPCUProfileRequest)
34 + RPCSleepRequest, RPCStartupRequest,
35 + RPCStartupResponse,
36 + RPCUProfileRequest, RPCWakeUpRequest)
37 from vllm.engine.protocol import EngineClient
38 # yapf: enable
39 from vllm.envs import VLLM_RPC_TIMEOUT
@@ -685,6 +686,16 @@ class MQLLMEngineClient(EngineClient):
686 request=RPCResetPrefixCacheRequest.RESET_PREFIX_CACHE,
687 socket=self.input_socket)
688
689 + async def sleep(self, level: int = 1) -> None:
690 + """Sleep the engine for a given level"""
691 + return await self._send_one_way_rpc_request(
692 + request=RPCSleepRequest(level), socket=self.input_socket)
693 +
694 + async def wake_up(self) -> None:
695 + """Wake up the engine"""
696 + return await self._send_one_way_rpc_request(
697 + request=RPCWakeUpRequest.WAKE_UP, socket=self.input_socket)
698 +
699 async def add_lora(self, lora_request: LoRARequest) -> None:
700 """Load a new LoRA adapter into the engine for future requests."""
701 # Uses the same I/O as generate requests
vllm/engine/multiprocessing/engine.py
+13 -2
@@ -20,8 +20,9 @@ from vllm.engine.multiprocessing import (ENGINE_DEAD_ERROR, IPC_DATA_EXT,
20 RPCLoadAdapterRequest,
21 RPCProcessRequest,
22 RPCResetPrefixCacheRequest,
23 - RPCStartupRequest, RPCStartupResponse,
24 - RPCUProfileRequest)
23 + RPCSleepRequest, RPCStartupRequest,
24 + RPCStartupResponse,
25 + RPCUProfileRequest, RPCWakeUpRequest)
26 # yapf: enable
27 from vllm.logger import init_logger
28 from vllm.outputs import RequestOutput
@@ -242,6 +243,10 @@ class MQLLMEngine:
243 self._handle_load_adapter_request(request)
244 elif isinstance(request, RPCResetPrefixCacheRequest):
245 self.reset_prefix_cache()
246 + elif isinstance(request, RPCSleepRequest):
247 + self.sleep(request.value)
248 + elif isinstance(request, RPCWakeUpRequest):
249 + self.wake_up()
250 else:
251 raise ValueError("Unknown RPCRequest Type: "
252 f"{type(request)}")
@@ -369,6 +374,12 @@ class MQLLMEngine:
374 def reset_prefix_cache(self) -> bool:
375 return self.engine.reset_prefix_cache()
376
377 + def sleep(self, level: int = 1) -> None:
378 + self.engine.sleep(level)
379 +
380 + def wake_up(self) -> None:
381 + self.engine.wake_up()
382 +
383
384 def signal_handler(*_) -> None:
385 raise KeyboardInterrupt("MQLLMEngine terminated")
vllm/engine/protocol.py
+10
@@ -278,6 +278,16 @@ class EngineClient(ABC):
278 """Reset the prefix cache"""
279 ...
280
281 + @abstractmethod
282 + async def sleep(self, level: int = 1) -> None:
283 + """Sleep the engine"""
284 + ...
285 +
286 + @abstractmethod
287 + async def wake_up(self) -> None:
288 + """Wake up the engine"""
289 + ...
290 +
291 @abstractmethod
292 async def add_lora(self, lora_request: LoRARequest) -> None:
293 """Load a new LoRA adapter into the engine for future requests."""
vllm/entrypoints/openai/api_server.py
+18
@@ -625,6 +625,24 @@ if envs.VLLM_SERVER_DEV_MODE:
625 await engine_client(raw_request).reset_prefix_cache()
626 return Response(status_code=200)
627
628 + @router.post("/sleep")
629 + async def sleep(raw_request: Request):
630 + # get POST params
631 + level = raw_request.query_params.get("level", "1")
632 + logger.info("sleep the engine with level %s", level)
633 + await engine_client(raw_request).sleep(int(level))
634 + # FIXME: in v0 with frontend multiprocessing, the sleep command
635 + # is sent but does not finish yet when we return a response.
636 + return Response(status_code=200)
637 +
638 + @router.post("/wake_up")
639 + async def wake_up(raw_request: Request):
640 + logger.info("wake up the engine")
641 + await engine_client(raw_request).wake_up()
642 + # FIXME: in v0 with frontend multiprocessing, the wake-up command
643 + # is sent but does not finish yet when we return a response.
644 + return Response(status_code=200)
645 +
646
647 @router.post("/invocations", dependencies=[Depends(validate_json_request)])
648 async def invocations(raw_request: Request):
vllm/entrypoints/openai/serving_transcription.py
+1
@@ -295,6 +295,7 @@ class OpenAIServingTranscription(OpenAIServing):
295 # TODO(rob): figure out a way to pipe streaming in.
296 # Non-streaming response.
297 try:
298 + assert result_generator is not None
299 async for op in result_generator:
300 result = op
301 return TranscriptionResponse(text=result.outputs[0].text)
vllm/v1/engine/async_llm.py
+6
@@ -361,6 +361,12 @@ class AsyncLLM(EngineClient):
361 async def reset_prefix_cache(self) -> None:
362 await self.engine_core.reset_prefix_cache_async()
363
364 + async def sleep(self, level: int = 1) -> None:
365 + await self.engine_core.sleep_async(level)
366 +
367 + async def wake_up(self) -> None:
368 + await self.engine_core.wake_up_async()
369 +
370 async def add_lora(self, lora_request: LoRARequest) -> None:
371 """Load a new LoRA adapter into the engine for future requests."""
372 await self.engine_core.add_lora_async(lora_request)
vllm/v1/engine/core.py
+6
@@ -213,6 +213,12 @@ class EngineCore:
213 def reset_prefix_cache(self):
214 self.scheduler.reset_prefix_cache()
215
216 + def sleep(self, level: int = 1):
217 + self.model_executor.sleep(level)
218 +
219 + def wake_up(self):
220 + self.model_executor.wake_up()
221 +
222 def add_lora(self, lora_request: LoRARequest) -> None:
223 self.model_executor.add_lora(lora_request)
224
vllm/v1/engine/core_client.py
+30
@@ -81,6 +81,12 @@ class EngineCoreClient(ABC):
81 def reset_prefix_cache(self) -> None:
82 raise NotImplementedError
83
84 + def sleep(self, level: int = 1) -> None:
85 + raise NotImplementedError
86 +
87 + def wake_up(self) -> None:
88 + raise NotImplementedError
89 +
90 def abort_requests(self, request_ids: List[str]) -> None:
91 raise NotImplementedError
92
@@ -99,6 +105,12 @@ class EngineCoreClient(ABC):
105 async def reset_prefix_cache_async(self) -> None:
106 raise NotImplementedError
107
108 + async def sleep_async(self, level: int = 1) -> None:
109 + raise NotImplementedError
110 +
111 + async def wake_up_async(self) -> None:
112 + raise NotImplementedError
113 +
114 async def abort_requests_async(self, request_ids: List[str]) -> None:
115 raise NotImplementedError
116
@@ -138,6 +150,12 @@ class InprocClient(EngineCoreClient):
150 def reset_prefix_cache(self) -> None:
151 self.engine_core.reset_prefix_cache()
152
153 + def sleep(self, level: int = 1) -> None:
154 + self.engine_core.sleep(level)
155 +
156 + def wake_up(self) -> None:
157 + self.engine_core.wake_up()
158 +
159 def add_lora(self, lora_request: LoRARequest) -> None:
160 self.engine_core.add_lora(lora_request)
161
@@ -307,6 +325,12 @@ class SyncMPClient(MPClient):
325 def add_lora(self, lora_request: LoRARequest) -> None:
326 self._call_utility("add_lora", lora_request)
327
328 + def sleep(self, level: int = 1) -> None:
329 + self._call_utility("sleep", level)
330 +
331 + def wake_up(self) -> None:
332 + self._call_utility("wake_up")
333 +
334
335 class AsyncMPClient(MPClient):
336 """Asyncio-compatible client for multi-proc EngineCore."""
@@ -384,5 +408,11 @@ class AsyncMPClient(MPClient):
408 async def reset_prefix_cache_async(self) -> None:
409 await self._call_utility_async("reset_prefix_cache")
410
411 + async def sleep_async(self, level: int = 1) -> None:
412 + await self._call_utility_async("sleep", level)
413 +
414 + async def wake_up_async(self) -> None:
415 + await self._call_utility_async("wake_up")
416 +
417 async def add_lora_async(self, lora_request: LoRARequest) -> None:
418 await self._call_utility_async("add_lora", lora_request)
vllm/v1/engine/llm_engine.py
+6
@@ -169,6 +169,12 @@ class LLMEngine:
169 def reset_prefix_cache(self):
170 self.engine_core.reset_prefix_cache()
171
172 + def sleep(self, level: int = 1):
173 + self.engine_core.sleep(level)
174 +
175 + def wake_up(self):
176 + self.engine_core.wake_up()
177 +
178 def get_tokenizer_group(
179 self,
180 group_type: Type[_G] = BaseTokenizerGroup,