2025-12-30 21:55:32 +08:00
# Profiling vLLM-Omni
2025-12-12 01:52:53 -05:00
2026-01-21 09:42:30 +08:00
> **Warning:** Profiling incurs significant overhead. Use only for development and debugging, never in production.
2026-01-06 08:58:00 +08:00
2026-01-28 20:18:02 +08:00
vLLM-Omni uses the PyTorch Profiler to analyze performance across both **multi-stage omni-modality models** and **diffusion models** .
2026-01-06 08:58:00 +08:00
2026-03-24 15:25:52 +08:00
### 1. Configure Profiling in the Stage YAML
2026-01-06 08:58:00 +08:00
2026-03-24 15:25:52 +08:00
Enable profiling by adding `profiler_config` under `engine_args` for the stage(s) you want to profile in your stage config YAML:
```yaml
stage_args :
- stage_id : 0
stage_type : llm
engine_args :
# ... other engine args ...
profiler_config :
profiler : torch
torch_profiler_dir : ./perf
2026-01-06 08:58:00 +08:00
```
2026-03-24 15:25:52 +08:00
| Field | Description |
|---|---|
| `profiler` | Profiler backend to use. Currently supports `torch` . |
| `torch_profiler_dir` | Directory where trace files are saved. Created automatically if it doesn't exist. |
> **Tip:** Only enable `profiler_config` on stages you actually need to profile. Stages without it will not start a profiler, keeping overhead minimal.
2026-01-28 20:18:02 +08:00
### 2. Profiling Omni-Modality Models
2026-01-06 08:58:00 +08:00
**Selective Stage Profiling**
2026-03-24 15:25:52 +08:00
It is highly recommended to profile specific stages to prevent producing overly large trace files:
2026-01-06 08:58:00 +08:00
```python
2026-01-21 09:42:30 +08:00
# Profile all stages
2026-03-24 15:25:52 +08:00
omni_llm . start_profile ()
2026-01-21 09:42:30 +08:00
2026-01-06 08:58:00 +08:00
# Only profile Stage 1
2026-03-24 15:25:52 +08:00
omni_llm . start_profile ( stages = [ 1 ])
# Stage 0 (Thinker) and Stage 2 (Audio Decoder) for qwen omni
omni_llm . start_profile ( stages = [ 0 , 2 ])
2026-01-06 08:58:00 +08:00
```
2026-03-24 15:25:52 +08:00
> **Important:** Always pass the same `stages` list to both `start_profile()` and `stop_profile()`. If you omit `stages` from `stop_profile()`, it defaults to stopping all stages — including ones that were never started — which will produce errors.
2026-01-06 08:58:00 +08:00
2026-01-21 09:42:30 +08:00
**Python Usage** : Wrap your generation logic with `start_profile()` and `stop_profile()` .
```python
2026-03-24 15:25:52 +08:00
profiler_stages = [ 0 ] # Only profile the stages you need
2026-03-18 17:33:53 +08:00
2026-03-24 15:25:52 +08:00
# 1. Start profiling
omni . start_profile ( stages = profiler_stages )
2026-01-21 09:42:30 +08:00
# Initialize generator
2026-03-18 17:33:53 +08:00
omni_generator = omni . generate ( prompts , sampling_params_list , py_generator = args . py_generator )
2026-01-21 09:42:30 +08:00
total_requests = len ( prompts )
processed_count = 0
# Main Processing Loop
for stage_outputs in omni_generator :
# ... [Output processing logic for text/audio would go here] ...
# Update count to track when to stop profiling
2026-03-24 15:25:52 +08:00
processed_count += len ( stage_outputs . request_output )
2026-01-21 09:42:30 +08:00
# 2. Check if all requests are done to stop the profiler safely
if profiler_enabled and processed_count >= total_requests :
print ( f "[Info] Processed { processed_count } / { total_requests } . Stopping profiler inside active loop..." )
# Stop the profiler while workers are still active
2026-03-24 15:25:52 +08:00
# Pass the same stages list used in start_profile()
omni_llm . stop_profile ( stages = profiler_stages )
2026-01-21 09:42:30 +08:00
# Wait for traces to flush to disk
print ( "[Info] Waiting 30s for workers to write trace files to disk..." )
time . sleep ( 30 )
print ( "[Info] Trace export wait time finished." )
2026-03-24 15:25:52 +08:00
omni_llm . close ()
2026-01-21 09:42:30 +08:00
```
2026-03-24 15:25:52 +08:00
**CLI Usage** (using `end2end.py` ):
```bash
# Profile only Stage 0 (Thinker)
python end2end.py --output-wav output_audio \
--query-type text --enable-profiler --profiler-stages 0
# Profile Stage 0 and Stage 2
python end2end.py --output-wav output_audio \
--query-type text --enable-profiler --profiler-stages 0 2
# Profile all stages (omit --profiler-stages)
python end2end.py --output-wav output_audio \
--query-type text --enable-profiler
```
2026-01-06 08:58:00 +08:00
**Examples** :
2026-01-28 20:18:02 +08:00
1. **Qwen2.5-Omni** : [https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/qwen2_5_omni/end2end.py ](https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/qwen2_5_omni/end2end.py )
2026-01-06 08:58:00 +08:00
2026-01-28 20:18:02 +08:00
2. **Qwen3-Omni** : [https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/qwen3_omni/end2end.py ](https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/qwen3_omni/end2end.py )
2026-01-06 08:58:00 +08:00
2026-01-28 20:18:02 +08:00
### 3. Profiling diffusion models
2026-01-21 09:42:30 +08:00
2026-03-24 15:25:52 +08:00
Diffusion profiling is End-to-End, capturing encoding, denoising loops, and decoding. Standalone diffusion scripts use `--profiler-dir` to enable profiling.
2026-01-21 09:42:30 +08:00
**CLI Usage:**
2026-03-24 15:25:52 +08:00
```bash
2026-01-21 09:42:30 +08:00
python image_to_video.py \
--model Wan-AI/Wan2.2-I2V-A14B-Diffusers \
--image qwen-bear.png \
--prompt "A cat playing with yarn, smooth motion" \
2026-03-24 15:25:52 +08:00
--profiler-dir \
2026-01-21 09:42:30 +08:00
\
# Minimize Spatial Dimensions (Optional but helpful):
# Drastically reduces memory usage so the profiler doesn't
# crash due to overhead, though for accurate performance
# tuning you often want target resolutions.
--height 48 \
--width 64 \
\
# Minimize Temporal Dimension (Frames):
# Video models process 3D tensors (Time, Height, Width).
# Reducing frames to the absolute minimum (2) keeps the
# tensor size small, ensuring the trace file doesn't become
# multi-gigabytes in size.
2026-02-11 17:17:48 +08:00
--num-frames 2 \
2026-01-21 09:42:30 +08:00
\
# Minimize Iteration Loop (Steps):
# This is the most critical setting for profiling.
# Diffusion models run the same loop X times.
# Profiling 2 steps gives you the exact same performance
# data as 50 steps, but saves minutes of runtime and
# prevents the trace viewer from freezing.
2026-02-11 17:17:48 +08:00
--num-inference-steps 2 \
2026-01-21 09:42:30 +08:00
\
2026-02-11 17:17:48 +08:00
--guidance-scale 5.0 \
--guidance-scale-high 6.0 \
--boundary-ratio 0.875 \
--flow-shift 12.0 \
2026-01-21 09:42:30 +08:00
--fps 16 \
--output i2v_output.mp4
```
2026-03-24 15:25:52 +08:00
> **Note:** For diffusion stages within a multi-stage omni pipeline, use `profiler_config` in the stage YAML instead (see Section 1).
2026-01-21 09:42:30 +08:00
**Examples** :
1. **Qwen image edit** : [https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/image_to_image/image_edit.py ](https://github.com/vllm-project/vllm-omni/blob/main/examples/offline_inference/image_to_image/image_edit.py )
2. **Wan-AI/Wan2.2-I2V-A14B-Diffusers** : [https://github.com/vllm-project/vllm-omni/tree/main/examples/offline_inference/image_to_video ](https://github.com/vllm-project/vllm-omni/tree/main/examples/offline_inference/image_to_video )
2026-03-24 15:25:52 +08:00
### 4. Profiling Online Serving
2026-01-06 08:58:00 +08:00
2026-03-24 15:25:52 +08:00
When `profiler_config` is set in the stage YAML, the server automatically exposes `/start_profile` and `/stop_profile` HTTP endpoints.
**1. Start the server** with a stage YAML that has `profiler_config` enabled:
```bash
vllm serve Qwen/Qwen2.5-Omni-7B \
--omni \
--stage-configs-path qwen2_5_omni.yaml \
--port 8091
```
Or for one stage diffusion models:
```bash
vllm serve Wan-AI/Wan2.2-I2V-A14B-Diffusers --omni --port 8091 --profiler-config '{"profiler": "torch", "torch_profiler_dir": "./vllm_profile"}'
```
**2. Start profiling** by sending a POST request:
```bash
# Profile all stages that have profiler_config set
curl -X POST http://localhost:8091/start_profile
# Profile specific stages only
curl -X POST http://localhost:8091/start_profile \
-H "Content-Type: application/json" \
-d '{"stages": [0]}'
```
**3. Send your inference requests** as normal while the profiler is running.
**4. Stop profiling** and collect traces:
```bash
# Stop all stages
curl -X POST http://localhost:8091/stop_profile
# Stop specific stages (must match the stages you started)
curl -X POST http://localhost:8091/stop_profile \
-H "Content-Type: application/json" \
-d '{"stages": [0]}'
```
Trace files are written to the `torch_profiler_dir` specified in your stage YAML.
> **Important:** Always stop the same stages you started. Stopping a stage that was never started will produce errors.
### 5. Analyzing Traces
Output files are saved to the `torch_profiler_dir` specified in your stage YAML config.
2026-01-06 08:58:00 +08:00
2026-01-21 09:42:30 +08:00
**Output**
2026-03-24 15:25:52 +08:00
**Chrome Trace** (`.json.gz` ): Visual timeline of kernels and stages. Open in Perfetto UI.
2026-01-06 08:58:00 +08:00
**Viewing Tools:**
2026-03-24 15:25:52 +08:00
- [Perfetto ](https://ui.perfetto.dev/ ) (recommended)
- `chrome://tracing` (Chrome only)
2026-01-06 08:58:00 +08:00
2026-01-28 20:18:02 +08:00
**Note** : vLLM-Omni reuses the PyTorch Profiler infrastructure from vLLM. See the official vLLM profiler documentation: [vLLM Profiling Guide ](https://docs.vllm.ai/en/stable/contributing/profiling/ )