From 67f47ddd3f2d7c5975ea192958f3852aadc5229f Mon Sep 17 00:00:00 2001 From: Amir Balwel Date: Thu, 2 Oct 2025 02:09:33 +0000 Subject: [PATCH 1/3] Init Signed-off-by: Amir Balwel --- _posts/2025-10-02-sleep-mode.md | 321 ++++++++++++++++++ .../sleep-mode/First-prompt-latency.png | Bin 0 -> 47555 bytes .../figures/sleep-mode/total-time-ratio.png | Bin 0 -> 48341 bytes 3 files changed, 321 insertions(+) create mode 100644 _posts/2025-10-02-sleep-mode.md create mode 100644 assets/figures/sleep-mode/First-prompt-latency.png create mode 100644 assets/figures/sleep-mode/total-time-ratio.png diff --git a/_posts/2025-10-02-sleep-mode.md b/_posts/2025-10-02-sleep-mode.md new file mode 100644 index 0000000..b41838a --- /dev/null +++ b/_posts/2025-10-02-sleep-mode.md @@ -0,0 +1,321 @@ +--- +layout: post +title: "Zero‑Reload Model Switching with vLLM Sleep Mode" +author: "Embedded LLM" +--- + +Serve multiple LLMs on a single GPU **without increasing VRAM,** and finish faster, by combining **vLLM Sleep Mode** with a **1‑token warm‑up**. + +## TL;DR + +- **Problem:** Stage‑based pipelines often need to swap between different models. Reloading models each round burns time and VRAM. +- **Solution:** vLLM **Sleep Mode** offloads weights (and optionally frees them) so you can **wake** a model in ~0.1–0.4 s, run a **1‑token warm‑up**, and then hit steady‑state latency on the first user request. +- **Result:** Across six alternating prompts (two models, three rounds), **Sleep Mode + warm‑up** is **~2.7×** faster than reloading models each time, **69.2 s vs 188.9 s,** with prefix caching **disabled**. + +First prompt latency + +Total time ratio + +Figures 1 & 2 — End-to-end time & first-prompt latency (lower is better). +Two models, 6 alternating prompts; Sleep L1 + 1-token warm-up. Total time: 69.2 s vs 188.9 s (~2.7× faster). First-prompt (after wake): 4.12 s → 0.96 s (–77%). + +## Why Sleep Mode + +**The problem.** In multi‑stage pipelines (e.g., classify → caption → rerank), different steps call different models. On a single GPU, naïve orchestration reloads models from disk each time, repeatedly incurring initialization, allocator priming, and other cold‑start costs. VRAM also prevents keeping multiple models resident. + +**Sleep Mode (CUDA‑only).** vLLM’s Sleep Mode keeps the server up while reducing GPU footprint: + +- **Level 1** — Offload model **weights to CPU RAM** and discard **KV cache**. + - Use when you plan to switch **back to the same model**. + - Wake is fast because weights are already in host memory. + - **API:** `POST /sleep?sleep_level=1` then `POST /wake_up` +- **Level 2** — Discard **both** weights and KV cache (free on CPU + GPU). + - Use when switching to **a different model** or **updating weights**; the next wake will reload from disk. + - **API:** `POST /sleep?sleep_level=2` then `POST /wake_up` + +> Works on multi‑GPU too. If you serve large models with tensor parallelism (TP) or pipeline parallelism (PP), Sleep Mode offloads/frees each partition across devices in the same way. The control endpoints are identical; the speed‑up dynamics remain (wake is cheap, reload is expensive), only the absolute times change. + +## Setup + +**Hardware** + +- CPU: Ryzen 7 7900x +- GPU: **RTX A4000** (PCIe 4.0 x16) +- RAM: **64 GB** DDR5 + +**Software** + +- vLLM **0.10.0** (older versions may work similarly) +- CUDA (required; Sleep Mode is CUDA‑only) + +**Models** + +- `Qwen/Qwen3-0.6B` (text, compact reasoning) +- `HuggingFaceTB/SmolVLM2-2.2B-Instruct` (lightweight VLM) + +**Common flags** + +- `-enable-sleep-mode` +- `-no-enable-prefix-caching` _(prefix caching disabled for fairness)_ +- `-compilation-config '{"full_cuda_graph": true}'` _(baseline runs)_ +- `-dtype auto` _(bf16 if supported; otherwise fp16)_ +- `-trust-remote-code` _(needed by many VLMs, including SmolVLM2)_ + +> Quantization: none for these runs. If you quantize, the absolute latencies change but the patterns (cold‑start vs steady‑state) remain. + +## Method + +**Scenario.** Two models, three alternating rounds (A→B→A→B→A→B). One prompt per model per round. + +**Policy.** + +- **Sleep Mode runs:** + - Load both models once (steady state), then for each turn: + - **wake → warm‑up (1 token) → prompt → sleep (L1)** + - We use **Sleep Level 1** because we switch back to the same models later. +- **No‑sleep baseline:** + - **Reload the needed model from disk** each time. + - No explicit warm‑up call: the cold‑start cost is **embedded** into the **first prompt** latency on every round. + +**Controls.** + +- Prefix caching **disabled** (`-no-enable-prefix-caching`). +- Same prompts across runs. +- Measured total wall time; TTFT observed but not used to drive control flow. +- CUDA Graph **enabled** in baseline; other ablations (eager mode, CG off) did not remove the cold‑start spike. +- Concurrency: single request at a time, to isolate first‑prompt effects. + +## Results + +### Canonical end‑to‑end comparison + +**Condition:** _Sleep Mode (L1), warm‑up ON, CUDA Graph ON, eager OFF, prefix caching OFF._ + +**Workload:** _Two models, three rounds, one prompt per turn, single‑threaded._ + +- **Sleep + warm‑up:** **69.2 s** total +- **No‑sleep:** **188.9 s** total +- **Speed‑up:** **~2.7×** + +### Warm‑up removes the first‑prompt spike + +**Condition:** _Second model’s first inference after wake; Sleep Mode (L1); prefix caching OFF._ + +A single **1‑token warm‑up** right after `wake_up` reduces the first‑prompt latency from **4.12 s → 0.96 s** (**77%**). Subsequent prompts stay at steady state; you pay the warm‑up once per wake. + +> Why the big gap vs no‑sleep? In no‑sleep, you reload from disk every round, and the cold‑start cost is repaid repeatedly because there’s no persistent server state. In Sleep Mode, you pay a small wake + warm‑up and keep the process hot. + +## What causes the first‑prompt spike? + +It’s not (just) token length; it’s general **cold‑start work** concentrated in the first request: + +- CUDA runtime/driver initialization paths +- TorchInductor graph specialization and/or JIT compilation +- CUDA Graph capture (if enabled) +- Memory allocator priming and graphable pool setup +- Prefill‑path specialization (e.g., attention mask/layout) + +Flipping **CUDA Graph off** or **enforce‑eager on** didn’t eliminate the spike in our tests; both still need allocator setup and prefill specialization. A **1‑token warm‑up** absorbs these costs so user‑visible requests start in steady state. + +## Quickstart + +**The fastest way to use Sleep Mode today—just what you need, nothing else.** + +```bash +# 1) Install +pip install vllm==0.10.0 + +# 2) Start a server (CUDA only) +export HF_TOKEN=... +export VLLM_SERVER_DEV_MODE=1 # dev endpoints; run behind your proxy +vllm serve Qwen/Qwen3-0.6B \ + --enable-sleep-mode \ + --no-enable-prefix-caching \ + --port 8000 +``` + +**Sleep / Wake** + +```bash +# Sleep Level 1 (weights → CPU, KV cache cleared) +curl -X POST localhost:8000/sleep?sleep_level=1 + +# Wake +curl -X POST localhost:8000/wake_up + +``` + +**Warm‑up (1 token) + prompt** + +```bash +# Warm-up: absorbs cold-start; keeps first user request fast +curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ + "model": "Qwen/Qwen3-0.6B", + "messages": [{"role":"user","content":"warm-up"}], + "max_tokens": 1, "temperature": 0, "top_p": 1, "seed": 0 +}' + +# Real prompt +curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ + "model": "Qwen/Qwen3-0.6B", + "messages": [{"role":"user","content":"Give me a fun fact about the Moon."}], + "max_tokens": 32, "temperature": 0, "top_p": 1, "seed": 0 +}' + +``` + +> Multi‑GPU note: Works with TP/PP as well; Sleep Mode offloads/frees each partition the same way. The endpoints and workflow don’t change.A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: + +--- + +A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: + +- **wake → warm‑up (1 token) → prompt → sleep** + +## Notes + +- Endpoints for sleeping/waking are **outside** `/v1`: use `POST /sleep?sleep_level=...` and `POST /wake_up`. +- This example uses **Sleep Level 1**. Change to `sleep_level=2` when you won’t switch back soon or want to reclaim CPU RAM. +- Logging prints timings for **wake / warm‑up / prompt / sleep** so you can see the first‑prompt drop. + +```python +# two_model_sleep_quickstart.py +# Minimal quickstart for Sleep Mode + Warm‑up in vLLM (two models) + +import os, time, signal, subprocess, requests +from contextlib import contextmanager +from openai import OpenAI + +A_MODEL = "Qwen/Qwen3-0.6B" +B_MODEL = "HuggingFaceTB/SmolVLM2-2.2B-Instruct" +A_PORT, B_PORT = 8001, 8002 +A_URL, B_URL = f"http://localhost:{A_PORT}", f"http://localhost:{B_PORT}" + +COMMON = [ + "--enable-sleep-mode", + "--no-enable-prefix-caching", + "--dtype", "auto", + "--compilation-config", '{"full_cuda_graph": true}', +] + +def run_vllm(model, port, extra_flags=None): + flags = extra_flags or [] + cmd = [ + "python3", "-m", "vllm.entrypoints.openai.api_server", + "--model", model, "--port", str(port), + *COMMON, *flags, + ] + return subprocess.Popen(cmd, env=os.environ.copy()) + +def wait_ready(url, timeout=120): + t0 = time.time() + while time.time() - t0 < timeout: + try: + if requests.get(url + "/health", timeout=2).status_code == 200: + return True + except requests.RequestException: + pass + time.sleep(1) + raise RuntimeError(f"Server at {url} not ready in {timeout}s") + +def client(base_url): + # vLLM OpenAI-compatible endpoint is served under /v1 + return OpenAI(api_key="EMPTY", base_url=base_url + "/v1") + +def post(url, path): + r = requests.post(url + path, timeout=10) + r.raise_for_status() + +@contextmanager +def timed(label): + t0 = time.time() + yield + dt = time.time() - t0 + print(f"{label:<18} {dt:.2f}s") + +def warmup_call(url, model): + # 1-token warm‑up to absorb cold-start + client(url).chat.completions.create( + model=model, + messages=[{"role": "user", "content": "warm-up"}], + max_tokens=1, + temperature=0.0, + top_p=1.0, + extra_body={"seed": 0}, + ) + +def user_prompt(url, model, text, max_tokens=32): + resp = client(url).chat.completions.create( + model=model, + messages=[{"role": "user", "content": text}], + max_tokens=max_tokens, + temperature=0.0, + top_p=1.0, + extra_body={"seed": 0}, + ) + return resp.choices[0].message.content + +def cycle(url, model, text, sleep_level=1): + with timed("wake"): + post(url, "/wake_up") + + with timed("warm-up"): + warmup_call(url, model) + + with timed("prompt"): + out = user_prompt(url, model, text) + print("→", out.strip()) + + with timed(f"sleep(L{sleep_level})"): + post(url, f"/sleep?sleep_level={sleep_level}") + +if __name__ == "__main__": + # SmolVLM2 needs trust-remote-code + a = run_vllm(A_MODEL, A_PORT) + b = run_vllm(B_MODEL, B_PORT, extra_flags=["--trust-remote-code"]) + + try: + wait_ready(A_URL); wait_ready(B_URL) + print("\n[A cycle]") + cycle(A_URL, A_MODEL, "Give me a fun fact about the Moon.", sleep_level=1) + + print("\n[B cycle]") + cycle(B_URL, B_MODEL, "Describe an image pipeline in one line.", sleep_level=1) + + finally: + a.terminate(); b.terminate() + try: + a.wait(timeout=5) + except Exception: + a.kill() + try: + b.wait(timeout=5) + except Exception: + b.kill() +``` + +Run + +```python +python two_model_sleep_quickstart.py +``` + +You’ll see logs like: + +```markdown +[A cycle] +wake 0.12s +warm-up 0.96s +prompt 2.55s +→ The Moon’s day is about 29.5 Earth days. +sleep(L1) 0.33s +... +``` + +## Limits & when _not_ to use it + +- **CPU RAM bound.** Level‑1 offloads **weights to CPU**. Reserve roughly `param_count × bytes_per_param` (bf16≈2 bytes, fp16≈2 bytes) **plus overhead**. + - Example: 2.2B params × 2 bytes ≈ **4.4 GB** baseline, expect ~5–6 GB with overheads. +- **Level‑2 reload penalty.** L2 frees CPU+GPU memory; the next **wake** reloads from disk and pays the full cold‑start again. Use L2 only when you won’t switch back soon. +- **CUDA‑only.** Sleep Mode isn’t available on ROCm or CPU‑only backends (as of v0.10.0). +- **Heavy concurrency.** Warm‑up is cheap but still a request—run it once per wake, not per thread. Many concurrent first‑requests can stampede into cold‑start work; serialize the warm‑up or gate the first request. diff --git a/assets/figures/sleep-mode/First-prompt-latency.png b/assets/figures/sleep-mode/First-prompt-latency.png new file mode 100644 index 0000000000000000000000000000000000000000..c239e12b35a94a25351cc2b64c5eb6bcabaaae9e GIT binary patch literal 47555 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 literal 0 HcmV?d00001 diff --git a/assets/figures/sleep-mode/total-time-ratio.png b/assets/figures/sleep-mode/total-time-ratio.png new file mode 100644 index 0000000000000000000000000000000000000000..461ea2e06dfc1f4baf6d235ff7e33e34c6cf115b GIT binary patch literal 48341 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 literal 0 HcmV?d00001 From f8178b2f101260d8a59e5e8e6d931a4724d9006e Mon Sep 17 00:00:00 2001 From: Amir Balwel Date: Fri, 3 Oct 2025 06:17:13 +0000 Subject: [PATCH 2/3] rename Signed-off-by: Amir Balwel --- _posts/2025-10-02-sleep-mode.md | 321 -------------------------------- 1 file changed, 321 deletions(-) delete mode 100644 _posts/2025-10-02-sleep-mode.md diff --git a/_posts/2025-10-02-sleep-mode.md b/_posts/2025-10-02-sleep-mode.md deleted file mode 100644 index b41838a..0000000 --- a/_posts/2025-10-02-sleep-mode.md +++ /dev/null @@ -1,321 +0,0 @@ ---- -layout: post -title: "Zero‑Reload Model Switching with vLLM Sleep Mode" -author: "Embedded LLM" ---- - -Serve multiple LLMs on a single GPU **without increasing VRAM,** and finish faster, by combining **vLLM Sleep Mode** with a **1‑token warm‑up**. - -## TL;DR - -- **Problem:** Stage‑based pipelines often need to swap between different models. Reloading models each round burns time and VRAM. -- **Solution:** vLLM **Sleep Mode** offloads weights (and optionally frees them) so you can **wake** a model in ~0.1–0.4 s, run a **1‑token warm‑up**, and then hit steady‑state latency on the first user request. -- **Result:** Across six alternating prompts (two models, three rounds), **Sleep Mode + warm‑up** is **~2.7×** faster than reloading models each time, **69.2 s vs 188.9 s,** with prefix caching **disabled**. - -First prompt latency - -Total time ratio - -Figures 1 & 2 — End-to-end time & first-prompt latency (lower is better). -Two models, 6 alternating prompts; Sleep L1 + 1-token warm-up. Total time: 69.2 s vs 188.9 s (~2.7× faster). First-prompt (after wake): 4.12 s → 0.96 s (–77%). - -## Why Sleep Mode - -**The problem.** In multi‑stage pipelines (e.g., classify → caption → rerank), different steps call different models. On a single GPU, naïve orchestration reloads models from disk each time, repeatedly incurring initialization, allocator priming, and other cold‑start costs. VRAM also prevents keeping multiple models resident. - -**Sleep Mode (CUDA‑only).** vLLM’s Sleep Mode keeps the server up while reducing GPU footprint: - -- **Level 1** — Offload model **weights to CPU RAM** and discard **KV cache**. - - Use when you plan to switch **back to the same model**. - - Wake is fast because weights are already in host memory. - - **API:** `POST /sleep?sleep_level=1` then `POST /wake_up` -- **Level 2** — Discard **both** weights and KV cache (free on CPU + GPU). - - Use when switching to **a different model** or **updating weights**; the next wake will reload from disk. - - **API:** `POST /sleep?sleep_level=2` then `POST /wake_up` - -> Works on multi‑GPU too. If you serve large models with tensor parallelism (TP) or pipeline parallelism (PP), Sleep Mode offloads/frees each partition across devices in the same way. The control endpoints are identical; the speed‑up dynamics remain (wake is cheap, reload is expensive), only the absolute times change. - -## Setup - -**Hardware** - -- CPU: Ryzen 7 7900x -- GPU: **RTX A4000** (PCIe 4.0 x16) -- RAM: **64 GB** DDR5 - -**Software** - -- vLLM **0.10.0** (older versions may work similarly) -- CUDA (required; Sleep Mode is CUDA‑only) - -**Models** - -- `Qwen/Qwen3-0.6B` (text, compact reasoning) -- `HuggingFaceTB/SmolVLM2-2.2B-Instruct` (lightweight VLM) - -**Common flags** - -- `-enable-sleep-mode` -- `-no-enable-prefix-caching` _(prefix caching disabled for fairness)_ -- `-compilation-config '{"full_cuda_graph": true}'` _(baseline runs)_ -- `-dtype auto` _(bf16 if supported; otherwise fp16)_ -- `-trust-remote-code` _(needed by many VLMs, including SmolVLM2)_ - -> Quantization: none for these runs. If you quantize, the absolute latencies change but the patterns (cold‑start vs steady‑state) remain. - -## Method - -**Scenario.** Two models, three alternating rounds (A→B→A→B→A→B). One prompt per model per round. - -**Policy.** - -- **Sleep Mode runs:** - - Load both models once (steady state), then for each turn: - - **wake → warm‑up (1 token) → prompt → sleep (L1)** - - We use **Sleep Level 1** because we switch back to the same models later. -- **No‑sleep baseline:** - - **Reload the needed model from disk** each time. - - No explicit warm‑up call: the cold‑start cost is **embedded** into the **first prompt** latency on every round. - -**Controls.** - -- Prefix caching **disabled** (`-no-enable-prefix-caching`). -- Same prompts across runs. -- Measured total wall time; TTFT observed but not used to drive control flow. -- CUDA Graph **enabled** in baseline; other ablations (eager mode, CG off) did not remove the cold‑start spike. -- Concurrency: single request at a time, to isolate first‑prompt effects. - -## Results - -### Canonical end‑to‑end comparison - -**Condition:** _Sleep Mode (L1), warm‑up ON, CUDA Graph ON, eager OFF, prefix caching OFF._ - -**Workload:** _Two models, three rounds, one prompt per turn, single‑threaded._ - -- **Sleep + warm‑up:** **69.2 s** total -- **No‑sleep:** **188.9 s** total -- **Speed‑up:** **~2.7×** - -### Warm‑up removes the first‑prompt spike - -**Condition:** _Second model’s first inference after wake; Sleep Mode (L1); prefix caching OFF._ - -A single **1‑token warm‑up** right after `wake_up` reduces the first‑prompt latency from **4.12 s → 0.96 s** (**77%**). Subsequent prompts stay at steady state; you pay the warm‑up once per wake. - -> Why the big gap vs no‑sleep? In no‑sleep, you reload from disk every round, and the cold‑start cost is repaid repeatedly because there’s no persistent server state. In Sleep Mode, you pay a small wake + warm‑up and keep the process hot. - -## What causes the first‑prompt spike? - -It’s not (just) token length; it’s general **cold‑start work** concentrated in the first request: - -- CUDA runtime/driver initialization paths -- TorchInductor graph specialization and/or JIT compilation -- CUDA Graph capture (if enabled) -- Memory allocator priming and graphable pool setup -- Prefill‑path specialization (e.g., attention mask/layout) - -Flipping **CUDA Graph off** or **enforce‑eager on** didn’t eliminate the spike in our tests; both still need allocator setup and prefill specialization. A **1‑token warm‑up** absorbs these costs so user‑visible requests start in steady state. - -## Quickstart - -**The fastest way to use Sleep Mode today—just what you need, nothing else.** - -```bash -# 1) Install -pip install vllm==0.10.0 - -# 2) Start a server (CUDA only) -export HF_TOKEN=... -export VLLM_SERVER_DEV_MODE=1 # dev endpoints; run behind your proxy -vllm serve Qwen/Qwen3-0.6B \ - --enable-sleep-mode \ - --no-enable-prefix-caching \ - --port 8000 -``` - -**Sleep / Wake** - -```bash -# Sleep Level 1 (weights → CPU, KV cache cleared) -curl -X POST localhost:8000/sleep?sleep_level=1 - -# Wake -curl -X POST localhost:8000/wake_up - -``` - -**Warm‑up (1 token) + prompt** - -```bash -# Warm-up: absorbs cold-start; keeps first user request fast -curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ - "model": "Qwen/Qwen3-0.6B", - "messages": [{"role":"user","content":"warm-up"}], - "max_tokens": 1, "temperature": 0, "top_p": 1, "seed": 0 -}' - -# Real prompt -curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ - "model": "Qwen/Qwen3-0.6B", - "messages": [{"role":"user","content":"Give me a fun fact about the Moon."}], - "max_tokens": 32, "temperature": 0, "top_p": 1, "seed": 0 -}' - -``` - -> Multi‑GPU note: Works with TP/PP as well; Sleep Mode offloads/frees each partition the same way. The endpoints and workflow don’t change.A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: - ---- - -A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: - -- **wake → warm‑up (1 token) → prompt → sleep** - -## Notes - -- Endpoints for sleeping/waking are **outside** `/v1`: use `POST /sleep?sleep_level=...` and `POST /wake_up`. -- This example uses **Sleep Level 1**. Change to `sleep_level=2` when you won’t switch back soon or want to reclaim CPU RAM. -- Logging prints timings for **wake / warm‑up / prompt / sleep** so you can see the first‑prompt drop. - -```python -# two_model_sleep_quickstart.py -# Minimal quickstart for Sleep Mode + Warm‑up in vLLM (two models) - -import os, time, signal, subprocess, requests -from contextlib import contextmanager -from openai import OpenAI - -A_MODEL = "Qwen/Qwen3-0.6B" -B_MODEL = "HuggingFaceTB/SmolVLM2-2.2B-Instruct" -A_PORT, B_PORT = 8001, 8002 -A_URL, B_URL = f"http://localhost:{A_PORT}", f"http://localhost:{B_PORT}" - -COMMON = [ - "--enable-sleep-mode", - "--no-enable-prefix-caching", - "--dtype", "auto", - "--compilation-config", '{"full_cuda_graph": true}', -] - -def run_vllm(model, port, extra_flags=None): - flags = extra_flags or [] - cmd = [ - "python3", "-m", "vllm.entrypoints.openai.api_server", - "--model", model, "--port", str(port), - *COMMON, *flags, - ] - return subprocess.Popen(cmd, env=os.environ.copy()) - -def wait_ready(url, timeout=120): - t0 = time.time() - while time.time() - t0 < timeout: - try: - if requests.get(url + "/health", timeout=2).status_code == 200: - return True - except requests.RequestException: - pass - time.sleep(1) - raise RuntimeError(f"Server at {url} not ready in {timeout}s") - -def client(base_url): - # vLLM OpenAI-compatible endpoint is served under /v1 - return OpenAI(api_key="EMPTY", base_url=base_url + "/v1") - -def post(url, path): - r = requests.post(url + path, timeout=10) - r.raise_for_status() - -@contextmanager -def timed(label): - t0 = time.time() - yield - dt = time.time() - t0 - print(f"{label:<18} {dt:.2f}s") - -def warmup_call(url, model): - # 1-token warm‑up to absorb cold-start - client(url).chat.completions.create( - model=model, - messages=[{"role": "user", "content": "warm-up"}], - max_tokens=1, - temperature=0.0, - top_p=1.0, - extra_body={"seed": 0}, - ) - -def user_prompt(url, model, text, max_tokens=32): - resp = client(url).chat.completions.create( - model=model, - messages=[{"role": "user", "content": text}], - max_tokens=max_tokens, - temperature=0.0, - top_p=1.0, - extra_body={"seed": 0}, - ) - return resp.choices[0].message.content - -def cycle(url, model, text, sleep_level=1): - with timed("wake"): - post(url, "/wake_up") - - with timed("warm-up"): - warmup_call(url, model) - - with timed("prompt"): - out = user_prompt(url, model, text) - print("→", out.strip()) - - with timed(f"sleep(L{sleep_level})"): - post(url, f"/sleep?sleep_level={sleep_level}") - -if __name__ == "__main__": - # SmolVLM2 needs trust-remote-code - a = run_vllm(A_MODEL, A_PORT) - b = run_vllm(B_MODEL, B_PORT, extra_flags=["--trust-remote-code"]) - - try: - wait_ready(A_URL); wait_ready(B_URL) - print("\n[A cycle]") - cycle(A_URL, A_MODEL, "Give me a fun fact about the Moon.", sleep_level=1) - - print("\n[B cycle]") - cycle(B_URL, B_MODEL, "Describe an image pipeline in one line.", sleep_level=1) - - finally: - a.terminate(); b.terminate() - try: - a.wait(timeout=5) - except Exception: - a.kill() - try: - b.wait(timeout=5) - except Exception: - b.kill() -``` - -Run - -```python -python two_model_sleep_quickstart.py -``` - -You’ll see logs like: - -```markdown -[A cycle] -wake 0.12s -warm-up 0.96s -prompt 2.55s -→ The Moon’s day is about 29.5 Earth days. -sleep(L1) 0.33s -... -``` - -## Limits & when _not_ to use it - -- **CPU RAM bound.** Level‑1 offloads **weights to CPU**. Reserve roughly `param_count × bytes_per_param` (bf16≈2 bytes, fp16≈2 bytes) **plus overhead**. - - Example: 2.2B params × 2 bytes ≈ **4.4 GB** baseline, expect ~5–6 GB with overheads. -- **Level‑2 reload penalty.** L2 frees CPU+GPU memory; the next **wake** reloads from disk and pays the full cold‑start again. Use L2 only when you won’t switch back soon. -- **CUDA‑only.** Sleep Mode isn’t available on ROCm or CPU‑only backends (as of v0.10.0). -- **Heavy concurrency.** Warm‑up is cheap but still a request—run it once per wake, not per thread. Many concurrent first‑requests can stampede into cold‑start work; serialize the warm‑up or gate the first request. From 1122eb65f7f6feaba074255dd5ef59d9b2ddd364 Mon Sep 17 00:00:00 2001 From: Amir Balwel Date: Fri, 3 Oct 2025 06:19:17 +0000 Subject: [PATCH 3/3] add markdown Signed-off-by: Amir Balwel --- _posts/2025-10-03-sleep-mode.md | 321 ++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 _posts/2025-10-03-sleep-mode.md diff --git a/_posts/2025-10-03-sleep-mode.md b/_posts/2025-10-03-sleep-mode.md new file mode 100644 index 0000000..b41838a --- /dev/null +++ b/_posts/2025-10-03-sleep-mode.md @@ -0,0 +1,321 @@ +--- +layout: post +title: "Zero‑Reload Model Switching with vLLM Sleep Mode" +author: "Embedded LLM" +--- + +Serve multiple LLMs on a single GPU **without increasing VRAM,** and finish faster, by combining **vLLM Sleep Mode** with a **1‑token warm‑up**. + +## TL;DR + +- **Problem:** Stage‑based pipelines often need to swap between different models. Reloading models each round burns time and VRAM. +- **Solution:** vLLM **Sleep Mode** offloads weights (and optionally frees them) so you can **wake** a model in ~0.1–0.4 s, run a **1‑token warm‑up**, and then hit steady‑state latency on the first user request. +- **Result:** Across six alternating prompts (two models, three rounds), **Sleep Mode + warm‑up** is **~2.7×** faster than reloading models each time, **69.2 s vs 188.9 s,** with prefix caching **disabled**. + +First prompt latency + +Total time ratio + +Figures 1 & 2 — End-to-end time & first-prompt latency (lower is better). +Two models, 6 alternating prompts; Sleep L1 + 1-token warm-up. Total time: 69.2 s vs 188.9 s (~2.7× faster). First-prompt (after wake): 4.12 s → 0.96 s (–77%). + +## Why Sleep Mode + +**The problem.** In multi‑stage pipelines (e.g., classify → caption → rerank), different steps call different models. On a single GPU, naïve orchestration reloads models from disk each time, repeatedly incurring initialization, allocator priming, and other cold‑start costs. VRAM also prevents keeping multiple models resident. + +**Sleep Mode (CUDA‑only).** vLLM’s Sleep Mode keeps the server up while reducing GPU footprint: + +- **Level 1** — Offload model **weights to CPU RAM** and discard **KV cache**. + - Use when you plan to switch **back to the same model**. + - Wake is fast because weights are already in host memory. + - **API:** `POST /sleep?sleep_level=1` then `POST /wake_up` +- **Level 2** — Discard **both** weights and KV cache (free on CPU + GPU). + - Use when switching to **a different model** or **updating weights**; the next wake will reload from disk. + - **API:** `POST /sleep?sleep_level=2` then `POST /wake_up` + +> Works on multi‑GPU too. If you serve large models with tensor parallelism (TP) or pipeline parallelism (PP), Sleep Mode offloads/frees each partition across devices in the same way. The control endpoints are identical; the speed‑up dynamics remain (wake is cheap, reload is expensive), only the absolute times change. + +## Setup + +**Hardware** + +- CPU: Ryzen 7 7900x +- GPU: **RTX A4000** (PCIe 4.0 x16) +- RAM: **64 GB** DDR5 + +**Software** + +- vLLM **0.10.0** (older versions may work similarly) +- CUDA (required; Sleep Mode is CUDA‑only) + +**Models** + +- `Qwen/Qwen3-0.6B` (text, compact reasoning) +- `HuggingFaceTB/SmolVLM2-2.2B-Instruct` (lightweight VLM) + +**Common flags** + +- `-enable-sleep-mode` +- `-no-enable-prefix-caching` _(prefix caching disabled for fairness)_ +- `-compilation-config '{"full_cuda_graph": true}'` _(baseline runs)_ +- `-dtype auto` _(bf16 if supported; otherwise fp16)_ +- `-trust-remote-code` _(needed by many VLMs, including SmolVLM2)_ + +> Quantization: none for these runs. If you quantize, the absolute latencies change but the patterns (cold‑start vs steady‑state) remain. + +## Method + +**Scenario.** Two models, three alternating rounds (A→B→A→B→A→B). One prompt per model per round. + +**Policy.** + +- **Sleep Mode runs:** + - Load both models once (steady state), then for each turn: + - **wake → warm‑up (1 token) → prompt → sleep (L1)** + - We use **Sleep Level 1** because we switch back to the same models later. +- **No‑sleep baseline:** + - **Reload the needed model from disk** each time. + - No explicit warm‑up call: the cold‑start cost is **embedded** into the **first prompt** latency on every round. + +**Controls.** + +- Prefix caching **disabled** (`-no-enable-prefix-caching`). +- Same prompts across runs. +- Measured total wall time; TTFT observed but not used to drive control flow. +- CUDA Graph **enabled** in baseline; other ablations (eager mode, CG off) did not remove the cold‑start spike. +- Concurrency: single request at a time, to isolate first‑prompt effects. + +## Results + +### Canonical end‑to‑end comparison + +**Condition:** _Sleep Mode (L1), warm‑up ON, CUDA Graph ON, eager OFF, prefix caching OFF._ + +**Workload:** _Two models, three rounds, one prompt per turn, single‑threaded._ + +- **Sleep + warm‑up:** **69.2 s** total +- **No‑sleep:** **188.9 s** total +- **Speed‑up:** **~2.7×** + +### Warm‑up removes the first‑prompt spike + +**Condition:** _Second model’s first inference after wake; Sleep Mode (L1); prefix caching OFF._ + +A single **1‑token warm‑up** right after `wake_up` reduces the first‑prompt latency from **4.12 s → 0.96 s** (**77%**). Subsequent prompts stay at steady state; you pay the warm‑up once per wake. + +> Why the big gap vs no‑sleep? In no‑sleep, you reload from disk every round, and the cold‑start cost is repaid repeatedly because there’s no persistent server state. In Sleep Mode, you pay a small wake + warm‑up and keep the process hot. + +## What causes the first‑prompt spike? + +It’s not (just) token length; it’s general **cold‑start work** concentrated in the first request: + +- CUDA runtime/driver initialization paths +- TorchInductor graph specialization and/or JIT compilation +- CUDA Graph capture (if enabled) +- Memory allocator priming and graphable pool setup +- Prefill‑path specialization (e.g., attention mask/layout) + +Flipping **CUDA Graph off** or **enforce‑eager on** didn’t eliminate the spike in our tests; both still need allocator setup and prefill specialization. A **1‑token warm‑up** absorbs these costs so user‑visible requests start in steady state. + +## Quickstart + +**The fastest way to use Sleep Mode today—just what you need, nothing else.** + +```bash +# 1) Install +pip install vllm==0.10.0 + +# 2) Start a server (CUDA only) +export HF_TOKEN=... +export VLLM_SERVER_DEV_MODE=1 # dev endpoints; run behind your proxy +vllm serve Qwen/Qwen3-0.6B \ + --enable-sleep-mode \ + --no-enable-prefix-caching \ + --port 8000 +``` + +**Sleep / Wake** + +```bash +# Sleep Level 1 (weights → CPU, KV cache cleared) +curl -X POST localhost:8000/sleep?sleep_level=1 + +# Wake +curl -X POST localhost:8000/wake_up + +``` + +**Warm‑up (1 token) + prompt** + +```bash +# Warm-up: absorbs cold-start; keeps first user request fast +curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ + "model": "Qwen/Qwen3-0.6B", + "messages": [{"role":"user","content":"warm-up"}], + "max_tokens": 1, "temperature": 0, "top_p": 1, "seed": 0 +}' + +# Real prompt +curl localhost:8000/v1/chat/completions -H 'content-type: application/json' -d '{ + "model": "Qwen/Qwen3-0.6B", + "messages": [{"role":"user","content":"Give me a fun fact about the Moon."}], + "max_tokens": 32, "temperature": 0, "top_p": 1, "seed": 0 +}' + +``` + +> Multi‑GPU note: Works with TP/PP as well; Sleep Mode offloads/frees each partition the same way. The endpoints and workflow don’t change.A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: + +--- + +A minimal script that launches **two** vLLM servers (Sleep Mode enabled), then runs one full cycle on each model: + +- **wake → warm‑up (1 token) → prompt → sleep** + +## Notes + +- Endpoints for sleeping/waking are **outside** `/v1`: use `POST /sleep?sleep_level=...` and `POST /wake_up`. +- This example uses **Sleep Level 1**. Change to `sleep_level=2` when you won’t switch back soon or want to reclaim CPU RAM. +- Logging prints timings for **wake / warm‑up / prompt / sleep** so you can see the first‑prompt drop. + +```python +# two_model_sleep_quickstart.py +# Minimal quickstart for Sleep Mode + Warm‑up in vLLM (two models) + +import os, time, signal, subprocess, requests +from contextlib import contextmanager +from openai import OpenAI + +A_MODEL = "Qwen/Qwen3-0.6B" +B_MODEL = "HuggingFaceTB/SmolVLM2-2.2B-Instruct" +A_PORT, B_PORT = 8001, 8002 +A_URL, B_URL = f"http://localhost:{A_PORT}", f"http://localhost:{B_PORT}" + +COMMON = [ + "--enable-sleep-mode", + "--no-enable-prefix-caching", + "--dtype", "auto", + "--compilation-config", '{"full_cuda_graph": true}', +] + +def run_vllm(model, port, extra_flags=None): + flags = extra_flags or [] + cmd = [ + "python3", "-m", "vllm.entrypoints.openai.api_server", + "--model", model, "--port", str(port), + *COMMON, *flags, + ] + return subprocess.Popen(cmd, env=os.environ.copy()) + +def wait_ready(url, timeout=120): + t0 = time.time() + while time.time() - t0 < timeout: + try: + if requests.get(url + "/health", timeout=2).status_code == 200: + return True + except requests.RequestException: + pass + time.sleep(1) + raise RuntimeError(f"Server at {url} not ready in {timeout}s") + +def client(base_url): + # vLLM OpenAI-compatible endpoint is served under /v1 + return OpenAI(api_key="EMPTY", base_url=base_url + "/v1") + +def post(url, path): + r = requests.post(url + path, timeout=10) + r.raise_for_status() + +@contextmanager +def timed(label): + t0 = time.time() + yield + dt = time.time() - t0 + print(f"{label:<18} {dt:.2f}s") + +def warmup_call(url, model): + # 1-token warm‑up to absorb cold-start + client(url).chat.completions.create( + model=model, + messages=[{"role": "user", "content": "warm-up"}], + max_tokens=1, + temperature=0.0, + top_p=1.0, + extra_body={"seed": 0}, + ) + +def user_prompt(url, model, text, max_tokens=32): + resp = client(url).chat.completions.create( + model=model, + messages=[{"role": "user", "content": text}], + max_tokens=max_tokens, + temperature=0.0, + top_p=1.0, + extra_body={"seed": 0}, + ) + return resp.choices[0].message.content + +def cycle(url, model, text, sleep_level=1): + with timed("wake"): + post(url, "/wake_up") + + with timed("warm-up"): + warmup_call(url, model) + + with timed("prompt"): + out = user_prompt(url, model, text) + print("→", out.strip()) + + with timed(f"sleep(L{sleep_level})"): + post(url, f"/sleep?sleep_level={sleep_level}") + +if __name__ == "__main__": + # SmolVLM2 needs trust-remote-code + a = run_vllm(A_MODEL, A_PORT) + b = run_vllm(B_MODEL, B_PORT, extra_flags=["--trust-remote-code"]) + + try: + wait_ready(A_URL); wait_ready(B_URL) + print("\n[A cycle]") + cycle(A_URL, A_MODEL, "Give me a fun fact about the Moon.", sleep_level=1) + + print("\n[B cycle]") + cycle(B_URL, B_MODEL, "Describe an image pipeline in one line.", sleep_level=1) + + finally: + a.terminate(); b.terminate() + try: + a.wait(timeout=5) + except Exception: + a.kill() + try: + b.wait(timeout=5) + except Exception: + b.kill() +``` + +Run + +```python +python two_model_sleep_quickstart.py +``` + +You’ll see logs like: + +```markdown +[A cycle] +wake 0.12s +warm-up 0.96s +prompt 2.55s +→ The Moon’s day is about 29.5 Earth days. +sleep(L1) 0.33s +... +``` + +## Limits & when _not_ to use it + +- **CPU RAM bound.** Level‑1 offloads **weights to CPU**. Reserve roughly `param_count × bytes_per_param` (bf16≈2 bytes, fp16≈2 bytes) **plus overhead**. + - Example: 2.2B params × 2 bytes ≈ **4.4 GB** baseline, expect ~5–6 GB with overheads. +- **Level‑2 reload penalty.** L2 frees CPU+GPU memory; the next **wake** reloads from disk and pays the full cold‑start again. Use L2 only when you won’t switch back soon. +- **CUDA‑only.** Sleep Mode isn’t available on ROCm or CPU‑only backends (as of v0.10.0). +- **Heavy concurrency.** Warm‑up is cheap but still a request—run it once per wake, not per thread. Many concurrent first‑requests can stampede into cold‑start work; serialize the warm‑up or gate the first request.