chore: import upstream snapshot with attribution
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
---
|
||||
title: "Bench Serving Guide"
|
||||
metatags:
|
||||
description: "SGLang bench_serving: benchmark throughput, TTFT, ITL with random/sharegpt/image datasets. Multi-backend support."
|
||||
---
|
||||
This guide explains how to benchmark online serving throughput and latency using `python -m sglang.bench_serving`. It supports multiple inference backends via OpenAI-compatible and native endpoints, and produces both console metrics and optional JSONL outputs.
|
||||
|
||||
### What it does
|
||||
|
||||
- Generates synthetic or dataset-driven prompts and submits them to a target serving endpoint
|
||||
- Measures throughput, time-to-first-token (TTFT), inter-token latency (ITL), per-request end-to-end latency, and more
|
||||
- Supports streaming or non-streaming modes, rate control, and concurrency limits
|
||||
|
||||
### Supported backends and endpoints
|
||||
|
||||
- `sglang` / `sglang-native`: `POST /generate`
|
||||
- `sglang-oai`, `vllm`, `lmdeploy`: `POST /v1/completions`
|
||||
- `sglang-oai-chat`, `vllm-chat`, `lmdeploy-chat`: `POST /v1/chat/completions`
|
||||
- `trt` (TensorRT-LLM): `POST /v2/models/ensemble/generate_stream`
|
||||
- `gserver`: Custom server (Not Implemented yet in this script)
|
||||
- `truss`: `POST /v1/models/model:predict`
|
||||
|
||||
If `--base-url` is provided, requests are sent to it. Otherwise, `--host` and `--port` are used. When `--model` is not provided, the script will attempt to query `GET /v1/models` for an available model ID (OpenAI-compatible endpoints).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- Dependencies typically used by this script: `aiohttp`, `numpy`, `requests`, `tqdm`, `transformers`, and for some datasets `datasets`, `pillow`, `pybase64`. Install as needed.
|
||||
- An inference server running and reachable via the endpoints above
|
||||
- If your server requires authentication, set environment variable `OPENAI_API_KEY` (used as `Authorization: Bearer <key>`)
|
||||
|
||||
### Quick start
|
||||
|
||||
Run a basic benchmark against an sglang server exposing `/generate`:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct
|
||||
```
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--num-prompts 1000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct
|
||||
```
|
||||
|
||||
Or, using an OpenAI-compatible endpoint (completions):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend vllm \
|
||||
--base-url http://127.0.0.1:8000 \
|
||||
--num-prompts 1000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct
|
||||
```
|
||||
|
||||
### Datasets
|
||||
|
||||
Select with `--dataset-name`:
|
||||
|
||||
- `sharegpt` (default): loads ShareGPT-style pairs; optionally restrict with `--sharegpt-context-len` and override outputs with `--sharegpt-output-len`
|
||||
- `random`: random text lengths; sampled from ShareGPT token space
|
||||
- `random-ids`: random token ids (can lead to gibberish)
|
||||
- `image`: generates images and wraps them in chat messages; supports custom resolutions, multiple formats, and different content types
|
||||
- `generated-shared-prefix`: synthetic dataset with shared long system prompts and short questions
|
||||
- `mmmu`: samples from MMMU (Math split) and includes images
|
||||
- `speed-bench`: [SPEED-Bench](https://huggingface.co/datasets/nvidia/SPEED-Bench) (**SPEculative Evaluation Dataset**) — a unified benchmark for evaluating [Speculative Decoding (SD)](https://arxiv.org/abs/2604.09557) algorithms. Uses the Throughput split, which provides fixed-length input sequences (1K–32K tokens) grouped into three output-entropy categories (`low_entropy`, `mixed`, `high_entropy`). Requires a pre-downloaded JSONL file passed via `--dataset-path`.
|
||||
- `agentic-trace`: replays pre-built multi-turn agentic traces (e.g. OpenHands / SWE-smith). Each conversation is replayed round by round, feeding the server's real assistant reply back into the next round's history. Requires a chat backend (`--backend sglang-oai-chat`) and a trace JSON passed via `--dataset-path`.
|
||||
|
||||
Common dataset flags:
|
||||
|
||||
- `--num-prompts N`: number of requests
|
||||
- `--random-input-len`, `--random-output-len`, `--random-range-ratio`: for random/random-ids/image
|
||||
- `--image-count`: Number of images per request (for `image` dataset).
|
||||
|
||||
- `--apply-chat-template`: apply tokenizer chat template when constructing prompts
|
||||
- `--dataset-path PATH`: file path for ShareGPT json; if blank and missing, it will be downloaded and cached
|
||||
|
||||
Generated Shared Prefix flags (for `generated-shared-prefix`):
|
||||
|
||||
- `--gsp-num-groups`
|
||||
- `--gsp-prompts-per-group`
|
||||
- `--gsp-system-prompt-len`
|
||||
- `--gsp-question-len`
|
||||
- `--gsp-output-len`
|
||||
- `--gsp-group-distribution {uniform,zipf}`: per-request prefix-group sampling distribution (default: `uniform`). With `zipf`, each request's group is sampled by rank with `p(rank) = (1/rank**alpha) / sum_k(1/k**alpha)`; rank starts at 1 and group index 0 is the hottest. The on-disk dataset cache uses a distinct key per `(group_distribution, zipf_alpha)`, so uniform-mode caches are never mixed with zipf-mode caches.
|
||||
- `--gsp-zipf-alpha FLOAT`: Zipf exponent for `--gsp-group-distribution=zipf`. Must be a finite float strictly greater than 0; larger values concentrate requests on lower-ranked (hotter) groups. Required when the distribution is `zipf`; must be omitted otherwise.
|
||||
|
||||
Image dataset flags (for `image`):
|
||||
|
||||
- `--image-count`: Number of images per request
|
||||
- `--image-resolution`: Image resolution; supports presets (4k, 1080p, 720p, 360p) or custom 'heightxwidth' format (e.g., 1080x1920, 512x768)
|
||||
- `--image-format`: Image format (jpeg or png)
|
||||
- `--image-content`: Image content type (random or blank)
|
||||
|
||||
Agentic trace flags (for `agentic-trace`):
|
||||
|
||||
- `--dataset-path`: path to the pre-built trace JSON
|
||||
- `--sharegpt-output-len`: per-turn output length (default: 220)
|
||||
- `--dataset-offset`: rotate the conversation list by this many entries before sampling, so successive sweep steps start on fresh conversations
|
||||
- `--agentic-max-turns`: cap each conversation to at most this many turns (useful for small, fast profiling runs)
|
||||
|
||||
SPEED-Bench flags (for `speed-bench`):
|
||||
|
||||
- `--dataset-path PATH`: path to the pre-downloaded SPEED-Bench Throughput JSONL (e.g., `throughput_1k.jsonl`). Use the [SPEED-Bench measurement framework](https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/specdec_bench) to generate it.
|
||||
- `--speed-bench-category`: filter to one entropy category: `low_entropy`, `mixed`, or `high_entropy` (default: all)
|
||||
- `--speed-bench-output-len`: fixed number of output tokens per request (default: 512)
|
||||
|
||||
### Examples
|
||||
|
||||
1. To benchmark image dataset with 3 images per request, 500 prompts, 512 input length, and 512 output length, you can run:
|
||||
|
||||
```bash Command
|
||||
python -m sglang.launch_server --model-path Qwen/Qwen2.5-VL-3B-Instruct --disable-radix-cache
|
||||
```
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_serving \
|
||||
--backend sglang-oai-chat \
|
||||
--dataset-name image \
|
||||
--num-prompts 500 \
|
||||
--image-count 3 \
|
||||
--image-resolution 720p \
|
||||
--random-input-len 512 \
|
||||
--random-output-len 512
|
||||
```
|
||||
|
||||
2. To benchmark random dataset with 3000 prompts, 1024 input length, and 1024 output length, you can run:
|
||||
|
||||
```bash Command
|
||||
python -m sglang.launch_server --model-path Qwen/Qwen2.5-3B-Instruct
|
||||
```
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--dataset-name random \
|
||||
--num-prompts 3000 \
|
||||
--random-input 1024 \
|
||||
--random-output 1024 \
|
||||
--random-range-ratio 0.5
|
||||
```
|
||||
|
||||
3. To benchmark speculative decoding throughput using SPEED-Bench (mixed-entropy category, 1K ISL), you can run:
|
||||
|
||||
```bash Command
|
||||
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct \
|
||||
--speculative-algorithm EAGLE --speculative-draft-model-path <draft-model-path>
|
||||
```
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--dataset-name speed-bench \
|
||||
--dataset-path /path/to/throughput_1k.jsonl \
|
||||
--speed-bench-category mixed \
|
||||
--speed-bench-output-len 512 \
|
||||
--num-prompts 512
|
||||
```
|
||||
|
||||
### Choosing model and tokenizer
|
||||
|
||||
- `--model` is required unless the backend exposes `GET /v1/models`, in which case the first model ID is auto-selected.
|
||||
- `--tokenizer` defaults to `--model`. Both can be HF model IDs or local paths.
|
||||
- For ModelScope workflows, setting `SGLANG_USE_MODELSCOPE=true` enables fetching via ModelScope (weights are skipped for speed).
|
||||
- If your tokenizer lacks a chat template, the script warns because token counting can be less robust for gibberish outputs.
|
||||
|
||||
### Rate, concurrency, and streaming
|
||||
|
||||
- `--request-rate`: requests per second. `inf` sends all immediately (burst). Non-infinite rate uses a Poisson process for arrival times.
|
||||
- `--max-concurrency`: caps concurrent in-flight requests regardless of arrival rate.
|
||||
- `--disable-stream`: switch to non-streaming mode when supported; TTFT then equals total latency for chat completions.
|
||||
|
||||
### Other key options
|
||||
|
||||
- `--output-file FILE.jsonl`: append JSONL results to file; auto-named if unspecified
|
||||
- `--output-details`: include per-request arrays (generated texts, errors, ttfts, itls, input/output lens)
|
||||
- `--extra-request-body '{"top_p":0.9,"temperature":0.6}'`: merged into payload (sampling params, etc.)
|
||||
- `--disable-ignore-eos`: pass through EOS behavior (varies by backend)
|
||||
- `--warmup-requests N`: run warmup requests with short output first (default 1)
|
||||
- `--flush-cache`: call `/flush_cache` (sglang) before main run
|
||||
- `--profile`: call `/start_profile` and `/stop_profile` (requires server to enable profiling, e.g., `SGLANG_TORCH_PROFILER_DIR`)
|
||||
- `--lora-name name1 name2 ...`: randomly pick one per request and pass to backend (e.g., `lora_path` for sglang)
|
||||
- `--tokenize-prompt`: send integer IDs instead of text (currently supports `--backend sglang` only)
|
||||
|
||||
### Authentication
|
||||
|
||||
If your target endpoint requires OpenAI-style auth, set:
|
||||
|
||||
```bash Command
|
||||
export OPENAI_API_KEY=sk-...yourkey...
|
||||
```
|
||||
|
||||
The script will add `Authorization: Bearer $OPENAI_API_KEY` automatically for OpenAI-compatible routes.
|
||||
|
||||
### Metrics explained
|
||||
|
||||
Printed after each run:
|
||||
|
||||
- Request throughput (req/s)
|
||||
- Input token throughput (tok/s) - includes both text and vision tokens
|
||||
- Output token throughput (tok/s)
|
||||
- Total token throughput (tok/s) - includes both text and vision tokens
|
||||
- Total input text tokens and Total input vision tokens - per-modality breakdown
|
||||
- Concurrency: aggregate time of all requests divided by wall time
|
||||
- End-to-End Latency (ms): mean/median/std/p99 per-request total latency
|
||||
- Time to First Token (TTFT, ms): mean/median/std/p99 for streaming mode
|
||||
- Inter-Token Latency (ITL, ms): mean/median/std/p95/p99/max between tokens
|
||||
- TPOT (ms): Token processing time after first token, i.e., `(latency - ttft)/(tokens-1)`
|
||||
- Accept length (sglang-only, if available): speculative decoding accept length
|
||||
|
||||
The script also retokenizes generated text with the configured tokenizer and reports "retokenized" counts.
|
||||
|
||||
### JSONL output format
|
||||
|
||||
When `--output-file` is set, one JSON object is appended per run. Base fields:
|
||||
|
||||
- Arguments summary: backend, dataset, request_rate, max_concurrency, etc.
|
||||
- Duration and totals: completed, total_input_tokens, total_output_tokens, retokenized totals
|
||||
- Throughputs and latency statistics as printed in the console
|
||||
- `accept_length` when available (sglang)
|
||||
|
||||
With `--output-details`, an extended object also includes arrays:
|
||||
|
||||
- `input_lens`, `output_lens`
|
||||
- `ttfts`, `itls` (per request: ITL arrays)
|
||||
- `generated_texts`, `errors`
|
||||
|
||||
### End-to-end examples
|
||||
|
||||
1) sglang native `/generate` (streaming):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name random \
|
||||
--random-input-len 1024 --random-output-len 1024 --random-range-ratio 0.5 \
|
||||
--num-prompts 2000 \
|
||||
--request-rate 100 \
|
||||
--max-concurrency 512 \
|
||||
--output-file sglang_random.jsonl --output-details
|
||||
```
|
||||
|
||||
2) OpenAI-compatible Completions (e.g., vLLM):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend vllm \
|
||||
--base-url http://127.0.0.1:8000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name sharegpt \
|
||||
--num-prompts 1000 \
|
||||
--sharegpt-output-len 256
|
||||
```
|
||||
|
||||
3) OpenAI-compatible Chat Completions (streaming):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend vllm-chat \
|
||||
--base-url http://127.0.0.1:8000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name random \
|
||||
--num-prompts 500 \
|
||||
--apply-chat-template
|
||||
```
|
||||
|
||||
4) Images (VLM) with chat template:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model your-vlm-model \
|
||||
--dataset-name image \
|
||||
--image-count 2 \
|
||||
--image-resolution 720p \
|
||||
--random-input-len 128 --random-output-len 256 \
|
||||
--num-prompts 200 \
|
||||
--apply-chat-template
|
||||
```
|
||||
|
||||
4a) Images with custom resolution:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model your-vlm-model \
|
||||
--dataset-name image \
|
||||
--image-count 1 \
|
||||
--image-resolution 512x768 \
|
||||
--random-input-len 64 --random-output-len 128 \
|
||||
--num-prompts 100 \
|
||||
--apply-chat-template
|
||||
```
|
||||
|
||||
4b) 1080p images with PNG format and blank content:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model your-vlm-model \
|
||||
--dataset-name image \
|
||||
--image-count 1 \
|
||||
--image-resolution 1080p \
|
||||
--image-format png \
|
||||
--image-content blank \
|
||||
--random-input-len 64 --random-output-len 128 \
|
||||
--num-prompts 100 \
|
||||
--apply-chat-template
|
||||
```
|
||||
|
||||
5) Generated shared prefix (long system prompts + short questions):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name generated-shared-prefix \
|
||||
--gsp-num-groups 64 --gsp-prompts-per-group 16 \
|
||||
--gsp-system-prompt-len 2048 --gsp-question-len 128 --gsp-output-len 256 \
|
||||
--num-prompts 1024
|
||||
```
|
||||
|
||||
Zipfian / power-law prefix popularity (opt-in via `--gsp-group-distribution=zipf`):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name generated-shared-prefix \
|
||||
--gsp-num-groups 64 --gsp-prompts-per-group 16 \
|
||||
--gsp-system-prompt-len 2048 --gsp-question-len 128 --gsp-output-len 256 \
|
||||
--gsp-group-distribution zipf --gsp-zipf-alpha 1.2 \
|
||||
--seed 42
|
||||
```
|
||||
|
||||
`zipf` mode samples each request's prefix group from the rank-based distribution `p(rank) = (1/rank**alpha) / sum_k(1/k**alpha)` with rank starting at 1, so group index 0 is the hottest. The total request count stays `num_groups * prompts_per_group` — identical to `uniform` mode — and only the per-request group assignment changes. `alpha` must be a finite float strictly greater than 0; larger values concentrate requests on lower-ranked (hotter) groups.
|
||||
|
||||
The on-disk dataset cache at `~/.cache/sglang/benchmark/gen_shared_prefix_*.pkl` includes `group_distribution` and `zipf_alpha` in its key, so uniform-mode and zipf-mode runs (or two zipf runs with different alpha) never share a cache file. Uniform-mode filenames are unchanged from the legacy format, so existing caches remain valid.
|
||||
|
||||
This flag controls prefix-popularity shape only. It does not by itself reproduce any production trace or guarantee an observed cache-hit rate for a given engine.
|
||||
|
||||
6) Tokenized prompts (ids) for strict length control (sglang only):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name random \
|
||||
--tokenize-prompt \
|
||||
--random-input-len 2048 --random-output-len 256 --random-range-ratio 0.2
|
||||
```
|
||||
|
||||
7) Profiling and cache flush (sglang):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--profile \
|
||||
--flush-cache
|
||||
```
|
||||
|
||||
8) TensorRT-LLM streaming endpoint:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend trt \
|
||||
--base-url http://127.0.0.1:8000 \
|
||||
--model your-trt-llm-model \
|
||||
--dataset-name random \
|
||||
--num-prompts 100 \
|
||||
--disable-ignore-eos
|
||||
```
|
||||
|
||||
9) Evaluating large-scale KVCache sharing with mooncake trace (sglang only):
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30000 \
|
||||
--model model-name \
|
||||
--dataset-name mooncake \
|
||||
--mooncake-slowdown-factor 1.0 \
|
||||
--mooncake-num-rounds 1000 \
|
||||
--mooncake-workload conversation|mooncake|agent|synthetic
|
||||
--use-trace-timestamps true \
|
||||
--random-output-len 256
|
||||
```
|
||||
|
||||
10) Fake decode stress testing (PD disaggregation, decode-only):
|
||||
|
||||
When benchmarking pure decode performance in a PD disaggregation setup, you can bypass the prefill node entirely by using `--fake-prefill`. This requires the decode server to be started with `--disaggregation-transfer-backend fake`:
|
||||
|
||||
```bash Command
|
||||
# Step 1: Start a decode-only server with fake transfer backend
|
||||
python -m sglang.launch_server \
|
||||
--model-path meta-llama/Llama-3.1-8B-Instruct \
|
||||
--disaggregation-mode decode \
|
||||
--disaggregation-transfer-backend fake \
|
||||
--port 30001
|
||||
|
||||
# Step 2: Run bench_serving with --fake-prefill
|
||||
python3 -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 127.0.0.1 --port 30001 \
|
||||
--model meta-llama/Llama-3.1-8B-Instruct \
|
||||
--dataset-name random \
|
||||
--num-prompts 500 \
|
||||
--random-input-len 1024 --random-output-len 256 \
|
||||
--fake-prefill
|
||||
```
|
||||
|
||||
Similarly, `bench_one_batch_server` also supports `--fake-prefill`:
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_one_batch_server \
|
||||
--base-url http://127.0.0.1:30001 \
|
||||
--model-path meta-llama/Llama-3.1-8B-Instruct \
|
||||
--batch-size 32 --input-len 1024 --output-len 256 \
|
||||
--fake-prefill
|
||||
```
|
||||
|
||||
The `--fake-prefill` flag automatically injects special sentinel values into each request, telling the decode server to skip real KV transfer and generate fake KV data locally.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- All requests failed: verify `--backend`, server URL/port, `--model`, and authentication. Check warmup errors printed by the script.
|
||||
- Throughput seems too low: adjust `--request-rate` and `--max-concurrency`; verify server batch size/scheduling; ensure streaming is enabled if appropriate.
|
||||
- Token counts look odd: prefer chat/instruct models with proper chat templates; otherwise tokenization of gibberish may be inconsistent.
|
||||
- Image/MMMU datasets: ensure you installed extra deps (`pillow`, `datasets`, `pybase64`).
|
||||
- Authentication errors (401/403): set `OPENAI_API_KEY` or disable auth on your server.
|
||||
|
||||
### Notes
|
||||
|
||||
- The script raises the file descriptor soft limit (`RLIMIT_NOFILE`) to help with many concurrent connections.
|
||||
- For sglang, `/server_info` is queried post-run to report speculative decoding accept length when available.
|
||||
@@ -0,0 +1,506 @@
|
||||
---
|
||||
title: "Benchmark and Profiling"
|
||||
metatags:
|
||||
description: "SGLang benchmarking and profiling: PyTorch Profiler, Nsight Systems, layerwise NVTX, PD disaggregation profiling."
|
||||
---
|
||||
## Benchmark
|
||||
|
||||
SGLang provides four benchmark tools that operate at different levels of the stack. The table below summarizes their key differences:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tool</th>
|
||||
<th>HTTP Server</th>
|
||||
<th>Scheduler</th>
|
||||
<th>Use Case</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>bench_serving</code></td>
|
||||
<td>Yes (async HTTP client to a running server)</td>
|
||||
<td>Yes (indirectly, via server)</td>
|
||||
<td>Realistic online serving benchmarks with latency metrics (TTFT, TPOT, ITL)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>bench_one_batch_server</code></td>
|
||||
<td>Yes (sends HTTP requests to a running server)</td>
|
||||
<td>Yes (indirectly, via server)</td>
|
||||
<td>End-to-end single-batch latency including HTTP and scheduler overhead</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>bench_offline_throughput</code></td>
|
||||
<td>No</td>
|
||||
<td>Yes (directly uses <code>Engine</code> in-process)</td>
|
||||
<td>Maximum throughput measurement without HTTP overhead</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>bench_one_batch</code></td>
|
||||
<td>No</td>
|
||||
<td>No (directly calls <code>ModelRunner</code>)</td>
|
||||
<td>Kernel-level latency profiling of a single static batch</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Use `bench_serving` by default unless there are specific needs.
|
||||
|
||||
**`bench_serving`** is an async HTTP load-testing client that sends requests at controlled rates with configurable concurrency to a running server. It measures realistic online serving metrics including time-to-first-token (TTFT), time-per-output-token (TPOT), inter-token latency (ITL), and throughput. Use `num-prompts >= 5 * max-concurrency` to measure steady-state performance. Launch a server with `sglang.launch_server` first.
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_serving --backend sglang --max-concurrency 16 --num-prompts 80 --random-input-len 256 --random-output-len 32 --dataset-name random
|
||||
```
|
||||
|
||||
**`bench_one_batch_server`** sends a single batch as one HTTP request to a running server. Due to only having a single batch, the server is never in a steady-state and metrics will be biased. Launch a server with `sglang.launch_server` first.
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_one_batch_server --base-url http://127.0.0.1:30000 --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch-size 32 --input-len 256 --output-len 32
|
||||
```
|
||||
|
||||
- Pass `--enable-multi-batch` and set `--batch-size` to a multiple of the server's `--max-running-requests` to stabilize throughput measurements. Surplus requests are queued by the scheduler and promoted batch-by-batch, amortizing per-request prefill and first-step transients into steady-state decode. Under this flag, only `overall_throughput` is authoritative; `input_throughput`, `output_throughput`, `last_ttft`, and ITL include cross-batch queueing in their denominators and should be treated as informational.
|
||||
- Pass `--lora-name <name>` to route every prompt through a pre-loaded LoRA adapter. Requires the server to be launched with `--enable-lora --lora-paths <name>=<path>`.
|
||||
|
||||
**`bench_offline_throughput`** directly instantiates the `Engine` object in-process (no HTTP server) and submits all requests at once via `engine.generate()`. The engine's scheduler handles batching and execution. This measures maximum achievable throughput without any network overhead.
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_offline_throughput --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --num-prompts 10
|
||||
```
|
||||
|
||||
**`bench_one_batch`** is the lowest-level tool. It directly instantiates a `ModelRunner` and calls `extend()` / `decode()` on a fixed static batch, bypassing the scheduler entirely. The prefill and decode phases are run separately, making profiling easier but rendering the metrics unrealistic. Because there is no dynamic batching, it may run out of memory for batch sizes that a real server can handle (a real server chunks prefill into smaller batches). This is best suited for profiling individual kernel performance.
|
||||
|
||||
```bash Command
|
||||
python3 -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch-size 32 --input-len 256 --output-len 32
|
||||
```
|
||||
|
||||
## Profile with PyTorch Profiler
|
||||
|
||||
[Pytorch Profiler](https://pytorch.org/tutorials/recipes/recipes/profiler_recipe.html) is a convenient basic tool to inspect kernel execution time, call stack, and kernel overlap and occupancy.
|
||||
|
||||
### Profile a server with `sglang.bench_serving`
|
||||
|
||||
```bash Command
|
||||
# set trace path
|
||||
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
|
||||
|
||||
# start server
|
||||
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct
|
||||
|
||||
# send profiling request from client
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile
|
||||
```
|
||||
|
||||
For `bench_serving --profile`, the output directory is selected on the client side from `--profile-output-dir` or `SGLANG_TORCH_PROFILER_DIR` (fallback: `/tmp`), then sent in the `/start_profile` request.
|
||||
If you call `/start_profile` directly and do not provide `output_dir`, the server uses its own `SGLANG_TORCH_PROFILER_DIR` (fallback: `/tmp`).
|
||||
|
||||
Setting `SGLANG_TORCH_PROFILER_DIR` on both server and client is still recommended to avoid confusion about where traces are written.
|
||||
|
||||
For more details, please refer to [Bench Serving Guide](./bench_serving).
|
||||
|
||||
### Profile In PD Disaggregation Mode
|
||||
|
||||
When profiling in PD disaggregation mode, prefill and decode workers **must be profiled separately** due to torch profiler limitations. The `bench_serving` command provides dedicated options for this:
|
||||
|
||||
#### Profile Prefill Workers
|
||||
|
||||
```bash Command
|
||||
# set trace path
|
||||
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
|
||||
|
||||
# start prefill and decode servers (see PD disaggregation docs for setup)
|
||||
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode prefill
|
||||
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disaggregation-mode decode --port 30001 --base-gpu-id 1
|
||||
|
||||
# start router
|
||||
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000
|
||||
|
||||
# send profiling request targeting prefill workers
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000
|
||||
```
|
||||
|
||||
#### Profile Decode Workers
|
||||
|
||||
```bash Command
|
||||
# send profiling request targeting decode workers
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --sharegpt-output-len 100 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001
|
||||
```
|
||||
|
||||
#### Important Notes
|
||||
|
||||
- `--profile-prefill-url` and `--profile-decode-url` are **mutually exclusive** - you cannot profile both at the same time
|
||||
- Both options support multiple worker URLs for multi-instance setups:
|
||||
```bash Command
|
||||
# Profile multiple prefill workers
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-prefill-url http://127.0.0.1:30000 http://127.0.0.1:30002
|
||||
|
||||
# Profile multiple decode workers
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 10 --profile --pd-separated --profile-decode-url http://127.0.0.1:30001 http://127.0.0.1:30003
|
||||
```
|
||||
- Make sure `SGLANG_TORCH_PROFILER_DIR` is set on all worker nodes before starting the servers
|
||||
- For more details on setting up PD disaggregation, see [PD Disaggregation Guide](../advanced_features/pd_disaggregation)
|
||||
|
||||
### Profile a server with `sglang.bench_offline_throughput`
|
||||
```bash Command
|
||||
export SGLANG_TORCH_PROFILER_DIR=/root/sglang/profile_log
|
||||
|
||||
# profile one batch with bench_one_batch.py
|
||||
# batch size can be controlled with --batch argument
|
||||
python3 -m sglang.bench_one_batch --model-path meta-llama/Llama-3.1-8B-Instruct --batch 32 --input-len 1024 --output-len 10 --profile
|
||||
|
||||
# profile multiple batches with bench_offline_throughput.py
|
||||
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8
|
||||
```
|
||||
|
||||
### Profile a server with `sglang.profiler`
|
||||
|
||||
When the server is running (e.g., processing a decoding request), you can start live profiling immediately by sending a profile request to the server.
|
||||
|
||||
You can do this by running `python3 -m sglang.profiler`. For example:
|
||||
|
||||
```text Output
|
||||
# Terminal 1: Send a generation request
|
||||
python3 -m sglang.test.send_one
|
||||
|
||||
# Terminal 2: Before the above request finishes, quickly launch the following command in a separate terminal.
|
||||
# It will generate a profile of the above request for several decoding batches.
|
||||
python3 -m sglang.profiler
|
||||
```
|
||||
|
||||
You can also combine the above operations into a single command
|
||||
|
||||
```text Output
|
||||
python3 -m sglang.test.send_one --profile
|
||||
```
|
||||
|
||||
### Profile a server with HTTP API endpoints
|
||||
|
||||
SGLang provides HTTP API endpoints to control profiling on a running server. This allows you to start and stop profiling programmatically, which is useful for capturing specific workload patterns.
|
||||
|
||||
#### Using `/start_profile` endpoint
|
||||
|
||||
The `/start_profile` endpoint starts profiling on the server. You can control when profiling begins and how long it runs using the following parameters:
|
||||
|
||||
**Basic usage:**
|
||||
|
||||
```bash Command
|
||||
# Start profiling immediately for 10 steps
|
||||
curl -X POST http://127.0.0.1:30000/start_profile \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"num_steps": 10
|
||||
}'
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `output_dir` (optional): Directory where profile traces will be saved. If not specified, uses `SGLANG_TORCH_PROFILER_DIR` environment variable, or `/tmp` as the default
|
||||
- `num_steps` (optional): Number of steps to profile. If not specified, profiling continues until manually stopped with `/stop_profile`
|
||||
- `start_step` (optional): Step number at which to start profiling (inclusive). Useful for skipping warmup iterations
|
||||
- `activities` (optional): List of activities to profile, e.g., `["CPU", "GPU"]`. Default is `["CPU", "GPU"]`
|
||||
- `merge_profiles` (optional): Whether to merge distributed traces. Default is `false`
|
||||
|
||||
**Note on step ranges:** Profiling starts at `start_step` (inclusive) and continues for `num_steps` iterations. For example, with `start_step=3` and `num_steps=10`, profiling captures steps 3, 4, 5, 6, 7, 8, 9, 10, 11, and 12 (10 steps total, starting from step 3).
|
||||
|
||||
**Advanced usage with `start_step`:**
|
||||
|
||||
```bash Command
|
||||
# Wait 5 steps (warmup), then profile for 10 steps
|
||||
curl -X POST http://127.0.0.1:30000/start_profile \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"output_dir": "/tmp/profiles",
|
||||
"start_step": 5,
|
||||
"num_steps": 10,
|
||||
"activities": ["CPU", "GPU"]
|
||||
}'
|
||||
```
|
||||
|
||||
**Continuous profiling (manual stop):**
|
||||
|
||||
```bash Command
|
||||
# Start profiling without num_steps - must manually stop with /stop_profile
|
||||
curl -X POST http://127.0.0.1:30000/start_profile
|
||||
```
|
||||
|
||||
#### Using `/stop_profile` endpoint
|
||||
|
||||
The `/stop_profile` endpoint stops an ongoing profiling session and saves the trace file.
|
||||
|
||||
```bash Command
|
||||
# Stop profiling and save traces
|
||||
curl -X POST http://127.0.0.1:30000/stop_profile
|
||||
```
|
||||
|
||||
This is only needed when you start profiling without specifying `num_steps`. If `num_steps` is specified, profiling will automatically stop after that many steps.
|
||||
|
||||
#### Example workflow
|
||||
|
||||
```bash Command
|
||||
# Terminal 1: Start the server
|
||||
export SGLANG_TORCH_PROFILER_DIR=/tmp/profiles
|
||||
python -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct
|
||||
|
||||
# Terminal 2: Start continuous profiling
|
||||
curl -X POST http://127.0.0.1:30000/start_profile \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"start_step": 3
|
||||
}'
|
||||
|
||||
# Terminal 3: Send requests to generate load
|
||||
python -m sglang.bench_serving --backend sglang --num-prompts 100
|
||||
|
||||
# Terminal 2: Stop profiling when done
|
||||
curl -X POST http://127.0.0.1:30000/stop_profile
|
||||
```
|
||||
|
||||
### Profiler Trace Merger for Distributed Traces
|
||||
|
||||
SGLang now supports automatic merging of profiling traces from distributed setups with multiple parallelism types (TP, DP, PP, EP). This feature is particularly useful for analyzing performance across distributed runs.
|
||||
|
||||
#### Multi-Node Profiling and Shared Storage Considerations
|
||||
|
||||
Single-node profiler output merging is completely supported. When profiling in distributed environments spanning multiple nodes, shared storage (e.g., NFS, Lustre) should be accessible by all nodes for the output directory to enable merging of trace files.
|
||||
|
||||
If there is no shared storage accessible across nodes, automatic merging of trace files during profiling is not supported directly as of now.
|
||||
|
||||
#### HTTP API Usage
|
||||
|
||||
```bash Command
|
||||
# Start profiling with automatic trace merging enabled
|
||||
curl -X POST <BASE_URL>/start_profile \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"output_dir": "/tmp/profiles", # where to store profile traces
|
||||
"num_steps": 10,
|
||||
"activities": ["CPU", "GPU"],
|
||||
"merge_profiles": true # optional argument to merge profile traces (default=False)
|
||||
}'
|
||||
```
|
||||
|
||||
#### Command Line Usage
|
||||
|
||||
```bash Command
|
||||
# Start profiling with merge enabled
|
||||
python -m sglang.profiler \
|
||||
--num-steps 10 \
|
||||
--cpu \
|
||||
--gpu \
|
||||
--output-dir /tmp/profiles \
|
||||
--merge-profiles # optional argument to merge profile traces (default=False)
|
||||
```
|
||||
|
||||
#### Output Files
|
||||
|
||||
The profile merger generates:
|
||||
- Individual rank trace files: `{profile_id}-TP-{tp}-DP-{dp}-PP-{pp}-EP-{ep}.trace.json.gz`
|
||||
- Merged trace file: `merged-{profile_id}.trace.json.gz`
|
||||
|
||||
### Possible PyTorch bugs
|
||||
If in any cases you encounter the following error (for example, using qwen 2.5 VL):
|
||||
```bash Command
|
||||
RuntimeError: !stack.empty() INTERNAL ASSERT FAILED at "/pytorch/torch/csrc/autograd/profiler_python.cpp":983, please report a bug to PyTorch. Python replay stack is empty.
|
||||
```
|
||||
This is likely a PyTorch Bug reported in [Bug: vLLM Profiler](https://github.com/vllm-project/vllm/issues/18240) and [Bug: torch.profiler.profile](https://github.com/pytorch/pytorch/issues/101632). As a workaround, you may disable `with_stack` with an environment variable such as follows:
|
||||
```bash Command
|
||||
export SGLANG_PROFILE_WITH_STACK=False
|
||||
python -m sglang.bench_offline_throughput --model-path meta-llama/Llama-3.1-8B-Instruct --dataset-name random --num-prompts 10 --profile --mem-frac=0.8
|
||||
```
|
||||
|
||||
### View traces
|
||||
|
||||
Trace files can be loaded and visualized from:
|
||||
|
||||
1. https://ui.perfetto.dev/ (any browser)
|
||||
2. chrome://tracing (Chrome browser only)
|
||||
|
||||
If browser cannot open trace file due to its large size,
|
||||
client can generate a small trace file (<100MB) by controlling number of prompts and lengths of prompt outputs.
|
||||
For example, when profiling a server,
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_serving --backend sglang --model meta-llama/Llama-3.1-8B-Instruct --num-prompts 2 --sharegpt-output-len 100 --profile
|
||||
```
|
||||
|
||||
This command sets the number of prompts to 2 with `--num-prompts` argument and limits the length of output sequences to 100 with `--sharegpt-output-len` argument, which can generate a small trace file for browser to open smoothly.
|
||||
|
||||
Additionally, if you want to locate the SGLang Python source code through the cuda kernel in Trace, you need to disable CUDA Graph when starting the service. This can be done by using the `--disable-cuda-graph` parameter in the command to start the service.
|
||||
|
||||
## Profile with Nsight
|
||||
|
||||
[Nsight systems](https://docs.nvidia.com/nsight-systems/) is an advanced tool that exposes more profiling details, such as register and shared memory usage, annotated code regions and low-level CUDA APIs and events.
|
||||
|
||||
1. Prerequisite:
|
||||
|
||||
Install using apt, or run inside a [NVIDIA Docker container](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/pytorch/tags) or [SGLang Docker container](https://github.com/sgl-project/sglang/tree/main/docker).
|
||||
|
||||
```bash Command
|
||||
# install nsys
|
||||
# https://docs.nvidia.com/nsight-systems/InstallationGuide/index.html
|
||||
apt update
|
||||
apt install -y --no-install-recommends gnupg
|
||||
echo "deb http://developer.download.nvidia.com/devtools/repos/ubuntu$(source /etc/lsb-release; echo "$DISTRIB_RELEASE" | tr -d .)/$(dpkg --print-architecture) /" | tee /etc/apt/sources.list.d/nvidia-devtools.list
|
||||
apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
|
||||
apt update
|
||||
apt install nsight-systems-cli
|
||||
```
|
||||
|
||||
2. To profile a single batch, use
|
||||
|
||||
```bash Command
|
||||
nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node python3 -m sglang.bench_one_batch --model meta-llama/Meta-Llama-3-8B --batch-size 64 --input-len 512
|
||||
```
|
||||
|
||||
3. To profile a server, e.g.
|
||||
|
||||
```bash Command
|
||||
# launch the server, set the delay and duration times according to needs
|
||||
# after the duration time has been used up, server will be killed by nsys
|
||||
|
||||
nsys profile --trace-fork-before-exec=true --cuda-graph-trace=node -o sglang.out --delay 60 --duration 70 python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --disable-radix-cache
|
||||
|
||||
# client
|
||||
python3 -m sglang.bench_serving --backend sglang --num-prompts 1000 --dataset-name random --random-input 1024 --random-output 512
|
||||
```
|
||||
|
||||
In practice, we recommend users to set `--duration` argument to a large value. Whenever user wants the server to stop profiling. Firstly run:
|
||||
|
||||
```bash Command
|
||||
nsys sessions list
|
||||
```
|
||||
|
||||
to get the session id in the form of `profile-XXXXX`, then run:
|
||||
|
||||
```bash Command
|
||||
nsys stop --session=profile-XXXXX
|
||||
```
|
||||
|
||||
to manually kill the profiler and generate `nsys-rep` files instantly.
|
||||
|
||||
4. Use NVTX to annotate code regions, e.g. to see their execution time.
|
||||
|
||||
```bash Command
|
||||
# install nvtx
|
||||
pip install nvtx
|
||||
```
|
||||
|
||||
```python Example
|
||||
# code snippets
|
||||
import nvtx
|
||||
with nvtx.annotate("description", color="color"):
|
||||
# some critical code
|
||||
```
|
||||
|
||||
### Layer-wise NVTX Profiling with Nsight Systems
|
||||
|
||||
SGLang provides built-in layerwise NVTX annotations that can be combined with the CUDA Profiler for detailed per-layer profiling in Nsight Systems. This is particularly useful for identifying performance bottlenecks at the layer level.
|
||||
|
||||
#### Using `--enable-layerwise-nvtx-marker` with Nsight Systems and `/start_profile`
|
||||
|
||||
The `--enable-layerwise-nvtx-marker` flag automatically adds NVTX markers to every layer in your model. This is particularly powerful when combined with Nsight Systems profiling to see detailed per-layer performance.
|
||||
|
||||
**Method 1: Using `/start_profile` with CUDA_PROFILER (for programmatic control)**
|
||||
|
||||
This method allows you to control exactly when profiling starts/stops via HTTP API while Nsight Systems is running.
|
||||
|
||||
1. Launch the server with layerwise NVTX enabled under Nsight Systems:
|
||||
|
||||
```bash Command
|
||||
# Terminal 1: Start server with nsys and capture-range option
|
||||
nsys profile --trace-fork-before-exec=true \
|
||||
--cuda-graph-trace=node \
|
||||
--capture-range=cudaProfilerApi \
|
||||
--capture-range-end=stop \
|
||||
-o layerwise_profile \
|
||||
python -m sglang.launch_server \
|
||||
--model-path meta-llama/Llama-3.1-8B-Instruct \
|
||||
--enable-layerwise-nvtx-marker \
|
||||
--disable-cuda-graph
|
||||
```
|
||||
|
||||
Note: NVTX markers are not emitted for kernel launches captured by CUDA graphs. Use `--disable-cuda-graph` to ensure all layerwise NVTX markers are emitted in the trace.
|
||||
|
||||
2. In another terminal, control profiling via `/start_profile` with `CUDA_PROFILER` activity:
|
||||
|
||||
```bash Command
|
||||
# Terminal 2: Wait for server to be ready, then start CUDA profiling
|
||||
# Wait 3 steps for warmup, then profile for 10 steps
|
||||
curl -X POST http://127.0.0.1:30000/start_profile \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"start_step": 3,
|
||||
"num_steps": 10,
|
||||
"activities": ["CUDA_PROFILER"]
|
||||
}'
|
||||
```
|
||||
|
||||
3. Send requests to generate load:
|
||||
|
||||
```bash Command
|
||||
# Terminal 3: Generate workload
|
||||
python -m sglang.bench_serving --backend sglang --num-prompts 100
|
||||
```
|
||||
|
||||
4. Profiling will automatically stop after 10 steps (due to `num_steps: 10`). If you hadn't specified `num_steps`, you would need to manually stop it:
|
||||
|
||||
```bash Command
|
||||
# Terminal 2: Only needed if num_steps was not specified
|
||||
curl -X POST http://127.0.0.1:30000/stop_profile
|
||||
```
|
||||
|
||||
The `--capture-range=cudaProfilerApi` option tells Nsight Systems to only capture data between `cudaProfilerStart()` and `cudaProfilerStop()` calls (triggered by `/start_profile` and `/stop_profile`), reducing overhead and file size. The `start_step` parameter skips the first 3 steps to avoid capturing warmup overhead.
|
||||
|
||||
**Method 2: Simpler approach without `/start_profile` API**
|
||||
|
||||
For simpler use cases where you don't need fine-grained control over profiling start/stop, you can profile with Nsight Systems capturing the entire workload:
|
||||
|
||||
```bash Command
|
||||
# Terminal 1: Start server with layerwise NVTX
|
||||
# Note: --disable-cuda-graph ensures all NVTX markers are emitted
|
||||
python -m sglang.launch_server \
|
||||
--model-path meta-llama/Llama-3.1-8B-Instruct \
|
||||
--enable-layerwise-nvtx-marker \
|
||||
--disable-cuda-graph
|
||||
|
||||
# Terminal 2: Profile the benchmarking client
|
||||
nsys profile --trace-fork-before-exec=true \
|
||||
--cuda-graph-trace=node \
|
||||
-o layerwise_profile \
|
||||
python -m sglang.bench_serving --backend sglang --num-prompts 10
|
||||
```
|
||||
|
||||
This approach profiles the entire client execution, including all server interactions. The layerwise NVTX markers will be visible in the Nsight Systems timeline.
|
||||
|
||||
**Viewing the profiling results:**
|
||||
|
||||
Open the generated `.qdrep` file with Nsight Systems:
|
||||
|
||||
```bash Command
|
||||
nsys-ui layerwise_profile.qdrep
|
||||
```
|
||||
|
||||
In the Nsight Systems GUI, you'll see:
|
||||
- **NVTX ranges**: Each layer appears as a labeled range in the timeline with detailed information in the marker metadata
|
||||
- **CUDA kernels**: All GPU kernels are shown alongside the layer annotations
|
||||
- **Layer hierarchy**: The full module path (e.g., `meta-llama/Meta-Llama-3.1-8B-Instruct.model.layers.0.self_attn.qkv_proj`) helps identify specific layers. The prefix uses the full model path from `--model-path`.
|
||||
- **Tensor shapes**: Input/output dimensions and parameter shapes are included in the NVTX marker data
|
||||
|
||||
**Benefits of layerwise NVTX profiling:**
|
||||
|
||||
- **Granular visibility**: See exactly which layers are taking the most time
|
||||
- **Memory tracking**: Identify layers with large memory allocations
|
||||
- **Bottleneck identification**: Quickly locate inefficient operations
|
||||
- **Communication overhead**: In multi-GPU setups, see per-layer communication costs
|
||||
- **Development debugging**: Validate that model architecture changes have the expected performance impact
|
||||
|
||||
## Other tips
|
||||
|
||||
1. You can benchmark a model using dummy weights by only providing the config.json file. This allows for quick testing of model variants without training. To do so, add `--load-format dummy` to the above commands and then you only need a correct `config.json` under the checkpoint folder.
|
||||
2. You can benchmark a model with modified configs (e.g., less layers) by using `--json-model-override-args`. For example, you can benchmark a model with only 2 layers and 2 kv heads using:
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_one_batch --model-path meta-llama/Meta-Llama-3.1-8B-Instruct --batch 32 --input-len 256 --output-len 32 --load-format dummy --json-model-override-args '{"num_hidden_layers": 1, "num_key_value_heads": 1}'
|
||||
```
|
||||
|
||||
3. You can use `--python-backtrace=cuda` to see python call stack for all CUDA kernels, as in PyTorch Profiler. (Caveat: this can cause inaccurately long kernel runtimes for CUDA event based timing)
|
||||
4. For more arguments see [Nsight Systems User Guide](https://docs.nvidia.com/nsight-systems/UserGuide/index.html).
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
title: "Contribution Guide"
|
||||
mode: wide
|
||||
metatags:
|
||||
description: "SGLang contribution guide: source install, pre-commit, unit tests, CI triggers, code style, sgl-kernel updates."
|
||||
---
|
||||
Welcome to **SGLang**! We appreciate your interest in contributing. This guide provides a concise overview of how to set up your environment, run tests, build documentation, and open a Pull Request (PR). Whether you’re fixing a small bug or developing a major feature, we encourage following these steps for a smooth contribution process.
|
||||
|
||||
## Install SGLang from Source
|
||||
|
||||
### Fork and clone the repository
|
||||
|
||||
**Note**: New contributors do **not** have the write permission to push to the official SGLang repo. Please fork the repository under your GitHub account, then clone your fork locally.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your_user_name>/sglang.git
|
||||
```
|
||||
|
||||
### Build from source
|
||||
|
||||
Refer to [Install SGLang from Source](../get-started/install#method-2-from-source).
|
||||
|
||||
## Format code with pre-commit
|
||||
|
||||
We use [pre-commit](https://pre-commit.com/) to maintain consistent code style checks. Before pushing your changes, please run:
|
||||
|
||||
```bash
|
||||
pip3 install pre-commit
|
||||
pre-commit install
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
- **`pre-commit run --all-files`** manually runs all configured checks, applying fixes if possible. If it fails the first time, re-run it to ensure lint errors are fully resolved. Make sure your code passes all checks **before** creating a Pull Request.
|
||||
- **Do not commit** directly to the `main` branch. Always create a new branch (e.g., `feature/my-new-feature`), push your changes, and open a PR from that branch.
|
||||
- Link checking with lychee is **enforced in CI**. By default, it is not blocking local commits.
|
||||
- To run local link checks manually, use: `pre-commit run --hook-stage manual lychee --all-files`.
|
||||
|
||||
## Run and add unit tests
|
||||
|
||||
If you add a new feature or fix a bug, please add corresponding unit tests to ensure coverage and prevent regression.
|
||||
|
||||
### Unit tests (no server required)
|
||||
|
||||
Unit tests live under [`test/registered/unit/`](https://github.com/sgl-project/sglang/tree/main/test/registered/unit), organized to mirror the `python/sglang/srt/` source tree. These tests validate component logic **without** launching a server or loading real model weights.
|
||||
SGLang uses Python's built-in [unittest](https://docs.python.org/3/library/unittest.html) framework with [pytest](https://docs.pytest.org/) as the test runner.
|
||||
|
||||
**When to add a unit test:** If you modify a file under `python/sglang/srt/`, check whether a corresponding test exists in `test/registered/unit/` and add coverage for your changes. For example:
|
||||
|
||||
```
|
||||
srt/mem_cache/radix_cache.py → unit/mem_cache/test_radix_cache.py
|
||||
srt/sampling/sampling_params.py → unit/sampling/test_sampling_params.py
|
||||
```
|
||||
|
||||
**Run unit tests locally:**
|
||||
|
||||
```bash Command
|
||||
pytest test/registered/unit/ -v # all unit tests
|
||||
pytest test/registered/unit/mem_cache/ -v # one module
|
||||
```
|
||||
|
||||
**Run with coverage:**
|
||||
|
||||
```bash Command
|
||||
pytest test/registered/unit/ --cov --cov-config=.coveragerc -v
|
||||
```
|
||||
|
||||
For conventions on CI registration, test structure, and examples, see [`test/registered/unit/README.md`](https://github.com/sgl-project/sglang/tree/main/test/registered/unit/README.md).
|
||||
|
||||
### E2E tests (server required)
|
||||
|
||||
For tests that require launching a server, refer to [`test/registered/README.md`](https://github.com/sgl-project/sglang/tree/main/test/registered/README.md) for guidance on where to place your test.
|
||||
|
||||
For detailed instructions on running tests and integrating them into CI, refer to [test/README.md](https://github.com/sgl-project/sglang/tree/main/test/README.md).
|
||||
|
||||
## Write documentations
|
||||
|
||||
We recommend new contributors start from writing documentation, which helps you quickly understand SGLang codebase.
|
||||
For more details, please refer to [docs/README.md](https://github.com/sgl-project/sglang/tree/main/docs/README.md).
|
||||
|
||||
## Test the accuracy
|
||||
If your code changes the model output, please run the accuracy tests. A quick sanity check is the few-shot GSM8K.
|
||||
|
||||
```text Output
|
||||
# Launch a server
|
||||
python3 -m sglang.launch_server --model Qwen/Qwen2-7B-Instruct
|
||||
|
||||
# Evaluate
|
||||
python3 -m sglang.test.few_shot_gsm8k --num-questions 200
|
||||
```
|
||||
|
||||
Please note that the above script is primarily a sanity check, not a rigorous accuracy or speed test.
|
||||
This test can have significant variance (1%–5%) in accuracy due to batching and the non-deterministic nature of the inference engine.
|
||||
Also, do not rely on the "Latency/Output throughput" from this script, as it is not a proper speed test.
|
||||
|
||||
GSM8K is too easy for state-of-the-art models nowadays. Please try your own more challenging accuracy tests.
|
||||
You can find additional accuracy eval examples in:
|
||||
- [test_eval_accuracy_large.py](https://github.com/sgl-project/sglang/blob/main/test/registered/eval/test_eval_accuracy_large.py)
|
||||
- [test_gpt_oss_1gpu.py](https://github.com/sgl-project/sglang/blob/main/test/registered/core/test_gpt_oss_1gpu.py)
|
||||
|
||||
## Benchmark the speed
|
||||
Refer to [Benchmark and Profiling](./benchmark_and_profiling).
|
||||
|
||||
## Requesting a review for merge
|
||||
You can follow the pull request merge process described in [MAINTAINER.md](https://github.com/sgl-project/sglang/blob/main/.github/MAINTAINER.md).
|
||||
You will need to work with the Merge Oncall, Codeowner, and other reviewers to get their approvals.
|
||||
Then your PR can be merged.
|
||||
|
||||
## How to Trigger CI Tests
|
||||
|
||||
We have a lot of open PRs but limited CI machines, so only top and trusted contributors have permission to trigger CI tests.
|
||||
Users with permission are listed in the [CI_PERMISSIONS.json](https://github.com/sgl-project/sglang/blob/main/.github/CI_PERMISSIONS.json)
|
||||
|
||||
**PR authors** can always use `/rerun-failed-ci` on their own PRs, even if they are not listed in `CI_PERMISSIONS.json`.
|
||||
|
||||
For CI to run on a pull request, it must have the "run-ci" label. Authorized users can add the label or rerun failed tests by commenting on the PR with one of these commands:
|
||||
|
||||
- `/tag-run-ci-label`: Adds the "run-ci" label. Only **future** commits trigger CI; the current commit is unaffected. Add the `extra` argument (`/tag-run-ci-label extra`) to additionally apply the "run-ci-extra" label, opting the PR into the extra test workflow (`pr-test-extra.yml`).
|
||||
- `/rerun-failed-ci`: Reruns workflows from the latest commit with conclusion **failed, flaky, or skipped**.
|
||||
- `/tag-and-rerun-ci`: Runs both. Use this on a fresh PR to kick off CI on the current commit — `/tag-run-ci-label` alone won't. Accepts the same `extra` argument (`/tag-and-rerun-ci extra`).
|
||||
- `/rerun-stage <stage-name>`: Reruns a single test stage without waiting for its dependencies. Useful for quickly validating a specific test fix instead of waiting ~30 minutes for preceding stages.
|
||||
- `/rerun-test <test-spec> [<test-spec> ...]`: Reruns one or more specific tests directly, bypassing stage boundaries. Each `<test-spec>` is pytest-style `<file>::<TestClass>[.<test_method>]` (the `::TestClass` and `.<test_method>` parts are optional). The handler resolves each spec, groups specs by their registered runner-label, and dispatches one [Rerun Test workflow](https://github.com/sgl-project/sglang/actions/workflows/rerun-test.yml) per group. Examples: `/rerun-test test_srt_endpoint.py`, `/rerun-test registered/core/test_srt_endpoint.py::TestSRTEndpoint.test_simple_decode`, `/rerun-test test_a.py test_b.py` (multiple at once).
|
||||
|
||||
If you have permission, the [Slash Command Handler](https://github.com/sgl-project/sglang/actions/workflows/slash-command-handler.yml) will run your command and react with a 👍 to your comment. It may take up to a few minutes for the reaction to appear. Here’s a usage [example](https://github.com/sgl-project/sglang/pull/14253#issuecomment-3599509302).
|
||||
|
||||
To avoid spamming a PR with too many `/rerun-failed-ci` comments, you can also trigger the command by editing an existing comment and adding any suffix (e.g., `/rerun-failed-ci try again`).
|
||||
|
||||
Example of rerunning a single test stage: `/rerun-stage unit-test-backend-4-gpu`.
|
||||
|
||||
If you don’t have permission and you’re not the PR author, please ask maintainers to trigger CI for you.
|
||||
|
||||
### CI rate limits
|
||||
|
||||
Due to CI scheduling and limited resources, higher-priority PRs may preempt running jobs. In such cases, you may need to rerun the tests.
|
||||
We apply CI rate limits to prevent abuse and ensure fair usage of our CI resources.
|
||||
|
||||
Each CI workflow has a default limit defined in its workflow configuration file. For example, in [pr-gate.yml](https://github.com/sgl-project/sglang/blob/main/.github/workflows/pr-gate.yml), the default cooldown period is 120 minutes, and each workflow can override it via the `cool-down-minutes` input parameter:
|
||||
|
||||
```yaml Config
|
||||
cool-down-minutes:
|
||||
description: "Default cooldown period in minutes; 0 disables rate limiting"
|
||||
type: number
|
||||
default: 120
|
||||
```
|
||||
|
||||
Users listed in [CI_PERMISSIONS.json](https://github.com/sgl-project/sglang/blob/main/.github/CI_PERMISSIONS.json) may have a per-user cooldown interval. In practice, we use the minimum of the workflow’s default window and the user-specific interval.
|
||||
|
||||
## Code style guidance
|
||||
- Avoid code duplication. If the same code snippet (more than five lines) appears multiple times, extract it into a shared function.
|
||||
- Minimize device synchronization. Reduce expensive CPU-GPU synchronization operations, such as `tensor.item()` or `tensor.cpu()`, whenever possible. Use vectorized code.
|
||||
- Prioritize extreme efficiency. SGLang is a runtime, and most of your code runs on the critical path for every request. Optimize all minor overheads as much as possible, especially in the model forward code.
|
||||
- A common pattern is some runtime checks in the model forward pass (e.g., [this](https://github.com/sgl-project/sglang/blob/f1b0eda55c2c4838e8ab90a0fac7fb1e3d7064ab/python/sglang/srt/models/deepseek_v2.py#L486-L491)). These are very likely the same for every layer. Please cache the result as a single boolean value in `__init__` whenever possible.
|
||||
- Make functions as pure as possible. Avoid in-place modification of arguments.
|
||||
- Keep files concise. If a file exceeds 2,000 lines of code, split it into multiple smaller files. (e.g., `scheduler.py`, `scheduler_output_processor_mixin.py`)
|
||||
- In a file, put core data structures at the top of the file. Put utility functions at the bottom of the file.
|
||||
- Keep tests run fast.
|
||||
- If a single test file run longer than 500 seconds, split it into multiple smaller files (e.g., `test_eagle_infer_a.py`, `test_eagle_infer_b.py`).
|
||||
- If a single job in a github workflow runs longer than 30 mins, split it into smaller jobs/steps.
|
||||
- Reuse server launches in your unit tests to make tests run faster.
|
||||
- Never use `pickle.loads()`, `pickle.load()`, or `recv_pyobj()` to deserialize untrusted or network-received data. Python's [pickle module is not secure](https://docs.python.org/3/library/pickle.html) — it can execute arbitrary code during deserialization. Use safe serialization formats such as [msgpack](https://github.com/jcrist/msgspec) or JSON instead.
|
||||
- When supporting new hardware or features, follow these guidelines:
|
||||
- Do not drastically change existing code.
|
||||
- Always prefer new files to introduce specific components for your new hardware (e.g., `allocator_ascend.py`).
|
||||
- If you write multiple if/else blocks for new features, ensure the common path (e.g., NVIDIA hardware or the existing code path) is the first branch.
|
||||
|
||||
## How to update sgl-kernel
|
||||
Since sglang and the `sglang-kernel` (prior `sgl-kernel`) distribution are separate Python packages, our current GitHub CI infrastructure does not support updating a kernel and using it immediately within the same pull request (PR).
|
||||
To add a new kernel or modify an existing one in the `sgl-kernel/` source tree, you must use multiple PRs.
|
||||
|
||||
Follow these steps:
|
||||
|
||||
1. Submit a PR to update the sgl-kernel source code without using it in sglang python package (e.g., [#8884](https://github.com/sgl-project/sglang/pull/8884/files)).
|
||||
2. Bump the version of the kernel package (e.g., [#9220](https://github.com/sgl-project/sglang/pull/9220/files)).
|
||||
- Once merged, this will trigger an automatic release of the `sglang-kernel` wheel to PyPI.
|
||||
- If not urgent, you can wait for other people to release the wheel. A new version will typically be released within one week.
|
||||
3. Apply the changes:
|
||||
- Update the `sglang-kernel` version in `sglang/python/pyproject.toml` to use the modified kernels.
|
||||
- Update the related caller code in the sglang to use the new kernel.
|
||||
|
||||
## Tips for newcomers
|
||||
|
||||
If you want to contribute but don’t have a specific idea in mind, pick issues labeled [“good first issue” or “help wanted”](https://github.com/sgl-project/sglang/issues?q=is%3Aissue+label%3A%22good+first+issue%22%2C%22help+wanted%22). These tasks typically have lower complexity and provide an excellent introduction to the codebase.
|
||||
|
||||
Also check out the following materials as startup guide:
|
||||
- [Mini-SGLang](https://github.com/sgl-project/mini-sglang) for a quick overview on the structure of sglang.
|
||||
- [Code Walk-through](https://github.com/zhaochenyang20/Awesome-ML-SYS-Tutorial/tree/main/sglang/code-walk-through) for a deeper look into SGLang’s workflow.
|
||||
- [GTC-2026 Training Lab](https://drive.google.com/file/d/1mwOZEtipNLJzrflCTodj34KhuOZEoEw5/view?usp=drive_link) for hands-on practices of how to do optimization, benchmarking, or profiling on a launched SGLang instance.
|
||||
|
||||
If you have any questions or want to start a discussion, please feel free to ask in our [Slack channel](https://slack.sglang.io).
|
||||
|
||||
Thank you for your interest in SGLang. Happy coding!
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "Development Guide Using Docker"
|
||||
sidebarTitle: "Using Docker"
|
||||
metatags:
|
||||
description: "SGLang Docker development: VSCode dev container, remote tunnels, debugger setup, nsys profiling."
|
||||
---
|
||||
## Setup VSCode on a Remote Host
|
||||
(Optional - you can skip this step if you plan to run sglang dev container locally)
|
||||
|
||||
1. In the remote host, download `code` from [VSCode](https://code.visualstudio.com/download) and run `code tunnel` in a shell.
|
||||
|
||||
Example
|
||||
```bash Command
|
||||
wget https://vscode.download.prss.microsoft.com/dbazure/download/stable/fabdb6a30b49f79a7aba0f2ad9df9b399473380f/vscode_cli_alpine_x64_cli.tar.gz
|
||||
tar xf vscode_cli_alpine_x64_cli.tar.gz
|
||||
|
||||
# https://code.visualstudio.com/docs/remote/tunnels
|
||||
./code tunnel
|
||||
```
|
||||
|
||||
2. In your local machine, press F1 in VSCode and choose "Remote Tunnels: Connect to Tunnel".
|
||||
|
||||
## Setup Docker Container
|
||||
|
||||
### Option 1. Use the default dev container automatically from VSCode
|
||||
There is a `.devcontainer` folder in the sglang repository root folder to allow VSCode to automatically start up within dev container. You can read more about this VSCode extension in VSCode official document [Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers).
|
||||
<Frame>
|
||||
<img src="https://github.com/user-attachments/assets/6a245da8-2d4d-4ea8-8db1-5a05b3a66f6d" alt="VSCode Dev Container Architecture" />
|
||||
</Frame>
|
||||
|
||||
*Figure 1: Diagram from VSCode official documentation [Developing inside a Container](https://code.visualstudio.com/docs/devcontainers/containers).*
|
||||
|
||||
To enable this, you only need to:
|
||||
1. Start Visual Studio Code and install [VSCode dev container extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
|
||||
2. Press F1, type and choose "Dev Container: Open Folder in Container.
|
||||
3. Input the `sglang` local repo path in your machine and press enter.
|
||||
|
||||
The first time you open it in dev container might take longer due to docker pull and build. Once it's successful, you should set on your status bar at the bottom left displaying that you are in a dev container:
|
||||
|
||||
<Frame>
|
||||
<img src="https://github.com/user-attachments/assets/650bba0b-c023-455f-91f9-ab357340106b" alt="VSCode Dev Container Status Bar" />
|
||||
</Frame>
|
||||
|
||||
Now when you run `sglang.launch_server` in the VSCode terminal or start debugging using F5, sglang server will be started in the dev container with all your local changes applied automatically:
|
||||
|
||||
<Frame>
|
||||
<img src="https://github.com/user-attachments/assets/748c85ba-7f8c-465e-8599-2bf7a8dde895" alt="SGLang Server Running in Dev Container" />
|
||||
</Frame>
|
||||
|
||||
|
||||
### Option 2. Start up containers manually (advanced)
|
||||
|
||||
The following startup command is an example for internal development by the SGLang team. You can **modify or add directory mappings as needed**, especially for model weight downloads, to prevent repeated downloads by different Docker containers.
|
||||
|
||||
❗️ **Note on RDMA**
|
||||
|
||||
1. `--network host` and `--privileged` are required by RDMA. If you don't need RDMA, you can remove them but keeping them there does not harm. Thus, we enable these two flags by default in the commands below.
|
||||
2. You may need to set `NCCL_IB_GID_INDEX` if you are using RoCE, for example: `export NCCL_IB_GID_INDEX=3`.
|
||||
|
||||
```bash Command
|
||||
# Change the name to yours
|
||||
docker run -itd --shm-size 32g --gpus all -v <volumes-to-mount> --ipc=host --network=host --privileged --name sglang_dev lmsysorg/sglang:dev /bin/zsh
|
||||
docker exec -it sglang_dev /bin/zsh
|
||||
```
|
||||
Some useful volumes to mount are:
|
||||
1. **Huggingface model cache**: mounting model cache can avoid re-download every time docker restarts. Default location on Linux is `~/.cache/huggingface/`.
|
||||
2. **SGLang repository**: code changes in the SGLang local repository will be automatically synced to the .devcontainer.
|
||||
|
||||
Example 1: Monting local cache folder `/opt/dlami/nvme/.cache` but not the SGLang repo. Use this when you prefer to manually transfer local code changes to the devcontainer.
|
||||
```bash Command
|
||||
docker run -itd --shm-size 32g --gpus all -v /opt/dlami/nvme/.cache:/root/.cache --ipc=host --network=host --privileged --name sglang_zhyncs lmsysorg/sglang:dev /bin/zsh
|
||||
docker exec -it sglang_zhyncs /bin/zsh
|
||||
```
|
||||
Example 2: Mounting both HuggingFace cache and local SGLang repo. Local code changes are automatically synced to the devcontainer as the SGLang is installed in editable mode in the dev image.
|
||||
```bash Command
|
||||
docker run -itd --shm-size 32g --gpus all -v $HOME/.cache/huggingface/:/root/.cache/huggingface -v $HOME/src/sglang:/sgl-workspace/sglang --ipc=host --network=host --privileged --name sglang_zhyncs lmsysorg/sglang:dev /bin/zsh
|
||||
docker exec -it sglang_zhyncs /bin/zsh
|
||||
```
|
||||
## Debug SGLang with VSCode Debugger
|
||||
1. (Create if not exist) open `launch.json` in VSCode.
|
||||
2. Add the following config and save. Please note that you can edit the script as needed to apply different parameters or debug a different program (e.g. benchmark script).
|
||||
```JSON Config
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python Debugger: launch_server",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "sglang.launch_server",
|
||||
"console": "integratedTerminal",
|
||||
"args": [
|
||||
"--model-path", "meta-llama/Llama-3.2-1B",
|
||||
"--host", "0.0.0.0",
|
||||
"--port", "30000",
|
||||
"--trust-remote-code",
|
||||
],
|
||||
"justMyCode": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. Press "F5" to start. VSCode debugger will ensure that the program will pause at the breakpoints even if the program is running at remote SSH/Tunnel host + dev container.
|
||||
|
||||
## Profile
|
||||
|
||||
```bash Command
|
||||
# Change batch size, input, output and add `disable-cuda-graph` (for easier analysis)
|
||||
# e.g. DeepSeek V3
|
||||
nsys profile -o deepseek_v3 python3 -m sglang.bench_one_batch --batch-size 1 --input 128 --output 256 --model deepseek-ai/DeepSeek-V3 --trust-remote-code --tp 8 --disable-cuda-graph
|
||||
```
|
||||
|
||||
## Evaluation
|
||||
|
||||
```bash Command
|
||||
# e.g. gsm8k 8 shot
|
||||
python3 benchmark/gsm8k/bench_sglang.py --num-questions 2000 --parallel 2000 --num-shots 8
|
||||
```
|
||||
@@ -0,0 +1,425 @@
|
||||
---
|
||||
title: "Development Guide for JIT Kernels"
|
||||
sidebarTitle: "JIT Kernels"
|
||||
metatags:
|
||||
description: "SGLang JIT kernel development: clangd setup, TensorMatcher, LaunchKernel, add_constant example walkthrough."
|
||||
---
|
||||
## Environment Setup
|
||||
|
||||
We strongly recommend using `clangd` as the language server for JIT kernel development.
|
||||
For Ubuntu/Debian, you can download clangd from [apt.llvm.org](https://apt.llvm.org/).
|
||||
If you are using VS Code, we recommend installing the `clangd` extension for better IDE integration.
|
||||
|
||||
All JIT-related files are located in `python/sglang/jit_kernel`.
|
||||
Unlike `sgl-kernel`, which compiles CUDA/C++ binaries ahead of time (AOT), just-in-time (JIT) kernels are compiled at runtime.
|
||||
Consequently, a static `compile_commands.json` cannot be generated.
|
||||
To enable code completion with `clangd`, run `python -m sglang.jit_kernel` to generate a `.clangd` configuration file in your current directory.
|
||||
After generating the file, restart the clangd language server. It should now recognize all JIT kernel files.
|
||||
|
||||
## Code Structure
|
||||
|
||||
### C++ Implementation
|
||||
|
||||
C++ source code is located in `python/sglang/jit_kernel/csrc`.
|
||||
Reusable functions should be placed in `python/sglang/jit_kernel/include`.
|
||||
|
||||
We use [tvm-ffi](https://github.com/apache/tvm-ffi) for efficient foreign language bindings.
|
||||
Refer to the [documentation](https://tvm.apache.org/ffi/) for advanced usage, such as exporting C++ objects.
|
||||
Typically, `tvm::ffi::TensorView` is sufficient for passing PyTorch Tensors from Python.
|
||||
|
||||
### Python Interface
|
||||
|
||||
Python interfaces are defined in `python/sglang/jit_kernel`.
|
||||
The `load_jit` utility function in `python/sglang/jit_kernel/utils.py` loads and returns the compiled module.
|
||||
To export a C++ function (e.g., `cpp_func`), pass `cuda_wrappers=[("func", "cpp_func")]` to `load_jit`.
|
||||
The function can then be called in Python as `module.func`.
|
||||
|
||||
For caching compiled modules, prefer `sglang.jit_kernel.utils.cache_once` over `functools.lru_cache`.
|
||||
`functools.lru_cache` is not compatible with `torch.compile`.
|
||||
|
||||
### C++ Utilities
|
||||
|
||||
The following C++ utilities are available:
|
||||
|
||||
#### Integer Range
|
||||
|
||||
Similar to PyTorch, we provide an `irange` function to represent an integer range.
|
||||
|
||||
```C++ Example
|
||||
#include <sgl_kernel/utils.h>
|
||||
|
||||
void test() {
|
||||
for (auto i : host::irange(100)) { // [0, 100)
|
||||
// do something
|
||||
}
|
||||
for (auto i : host::irange(0, 100)) { // [0, 100)
|
||||
// do something
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Runtime Checking
|
||||
|
||||
`RuntimeCheck` validates conditions at runtime. It accepts optional arguments for error reporting.
|
||||
If the check fails, these arguments are output to aid debugging.
|
||||
`RuntimeDeviceCheck` verifies the status of the last kernel launch.
|
||||
|
||||
```C++ Example
|
||||
#include <sgl_kernel/utils.h>
|
||||
#include <sgl_kernel/utils.cuh>
|
||||
|
||||
void test() {
|
||||
host::RuntimeCheck(1 + 1 == 2, 1 + 1, " != ", 2);
|
||||
host::RuntimeDeviceCheck();
|
||||
// check the provided `cudaError_t`
|
||||
host::RuntimeDeviceCheck(cudaGetLastError());
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Tensor Checking
|
||||
|
||||
`TensorMatcher` provides a readable way to validate and extract tensor shape information.
|
||||
|
||||
```cpp Example
|
||||
#include <sgl_kernel/tensor.h>
|
||||
|
||||
void test(const tvm::ffi::TensorView k_cache, const tvm::ffi::TensorView v_cache) {
|
||||
using namespace host;
|
||||
|
||||
auto D = SymbolicSize{"D"}; // cache dimension
|
||||
auto N = SymbolicSize{"N"}; // kvcache stride
|
||||
auto dtype = SymbolicDType{};
|
||||
auto device = SymbolicDevice{};
|
||||
|
||||
TensorMatcher({-1, D}) //
|
||||
.with_strides({N, 1})
|
||||
.with_dtype<int32_t, int64_t>(dtype)
|
||||
.with_device<kDLCUDA, kDLCPU>(device)
|
||||
.verify(k_cache)
|
||||
.verify(v_cache);
|
||||
}
|
||||
```
|
||||
|
||||
Configure the `TensorMatcher` with expected stride, dtype, and device properties before verification.
|
||||
- If `with_strides` is omitted, the tensor is expected to be contiguous.
|
||||
- Template arguments in `with_dtype` restrict the allowed data types.
|
||||
- Template arguments in `with_device` restrict the allowed devices.
|
||||
- Values passed to `with_xxx` methods enforce equality checks.
|
||||
- Passing `-1` for size or stride allows matching any value.
|
||||
|
||||
A `Symbolic` variable must resolve to the same value across all verifications.
|
||||
Use `.unwrap()` to retrieve the matched value after verification.
|
||||
|
||||
> Note: `TensorMatcher` is a temporary expression and should not be stored in a variable.
|
||||
|
||||
> Tip: Add `//` at the end of the `TensorMatcher` chain to enforce proper indentation.
|
||||
|
||||
#### Kernel Launching
|
||||
|
||||
`LaunchKernel::resolve_device` retrieves the current `cudaStream` from PyTorch.
|
||||
Kernels can also be launched directly using `LaunchKernel`.
|
||||
|
||||
```cpp Example
|
||||
#include <sgl_kernel/utils.cuh>
|
||||
|
||||
#include <dlpack/dlpack.h>
|
||||
|
||||
__global__ void kernel() {}
|
||||
|
||||
void test() {
|
||||
const auto num_blocks = 1;
|
||||
const auto num_threads = 32;
|
||||
const auto dynamic_smem = 0;
|
||||
|
||||
DLDevice dev; // suppose this is initialized properly
|
||||
host::LaunchKernel(num_blocks, num_threads, dev)(kernel);
|
||||
|
||||
cudaStream_t stream = host::LaunchKernel::resolve_device(dev);
|
||||
host::LaunchKernel(num_blocks, num_threads, stream, dynamic_smem)(kernel);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Add new kernels
|
||||
|
||||
This section walks through a complete, end-to-end example of adding a new JIT kernel to the system.
|
||||
We use a simple add_constant kernel as a running example, which adds a constant integer value to every element of an input tensor.
|
||||
|
||||
Conceptually, the Python interface looks like this:
|
||||
|
||||
```python Example
|
||||
def add_constant(src: torch.Tensor, c: int):
|
||||
return src + c
|
||||
```
|
||||
|
||||
### STEP 1: Write the C++ kernel
|
||||
|
||||
Write your CUDA kernel in [jit_kernel/csrc/add_constant.cuh](https://github.com/sgl-project/sglang/blob/main/python/sglang/jit_kernel/csrc/add_constant.cuh). For demonstration purposes, we pass the constant value as a template parameter.
|
||||
|
||||
```cpp Example
|
||||
#include <sgl_kernel/tensor.h> // For TensorMatcher, SymbolicSize, SymbolicDevice
|
||||
#include <sgl_kernel/utils.cuh> // For LaunchKernel
|
||||
#include <sgl_kernel/utils.h> // For div_ceil, RuntimeCheck
|
||||
|
||||
#include <dlpack/dlpack.h>
|
||||
#include <tvm/ffi/container/tensor.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
template <int32_t kConstant>
|
||||
__global__ void add_constant_kernel(int32_t* dst, const int32_t* src, size_t length) {
|
||||
size_t idx = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (idx < length) {
|
||||
dst[idx] = src[idx] + kConstant;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t kBlockSize = 256;
|
||||
|
||||
// You can also use struct with static method as an alternative
|
||||
template <int32_t kConstant>
|
||||
void add_constant(tvm::ffi::TensorView dst, tvm::ffi::TensorView src) {
|
||||
using namespace host;
|
||||
|
||||
// 1. Validate input tensors
|
||||
SymbolicSize N = {"num_elements"};
|
||||
SymbolicDevice device_;
|
||||
TensorMatcher({N}) // 1D tensor, must be contiguous
|
||||
.with_dtype<int32_t>() // must be int32
|
||||
.with_device<kDLCUDA>(device_) // must be on CUDA device
|
||||
.verify(dst) // check tensor dst
|
||||
.verify(src); // check tensor src
|
||||
|
||||
// 2. Extract required parameters, prepare for kernel launch
|
||||
const size_t num_elements = N.unwrap();
|
||||
const size_t grid_size = div_ceil(num_elements, kBlockSize);
|
||||
const DLDevice device = device_.unwrap();
|
||||
// some extra runtime checks using host::RuntimeCheck
|
||||
RuntimeCheck(num_elements > 0, "We only support non-empty tensors, got num_elements = ", num_elements);
|
||||
|
||||
// 3. Launch the kernel. Error code will be automatically checked.
|
||||
LaunchKernel(grid_size, kBlockSize, device /*, dynamic_smem*/)(
|
||||
// kernel function
|
||||
add_constant_kernel<kConstant>,
|
||||
// kernel arguments
|
||||
static_cast<int32_t*>(dst.data_ptr()),
|
||||
static_cast<int32_t*>(src.data_ptr()),
|
||||
num_elements);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
```
|
||||
|
||||
### STEP 2: Create Python Interfaces
|
||||
|
||||
Next, expose the kernel through a Python wrapper.
|
||||
Create a new file at [jit_kernel/add_constant.py](https://github.com/sgl-project/sglang/blob/main/python/sglang/jit_kernel/add_constant.py) and expose the needed interfaces.
|
||||
|
||||
```python Example
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
from sglang.jit_kernel.utils import cache_once, load_jit, make_cpp_args
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tvm_ffi.module import Module
|
||||
|
||||
|
||||
@cache_once
|
||||
def _jit_add_constant_module(constant: int) -> Module:
|
||||
args = make_cpp_args(constant) # pass all the template argument
|
||||
return load_jit(
|
||||
"add_constant",
|
||||
*args,
|
||||
cuda_files=["add_constant.cuh"],
|
||||
cuda_wrappers=[("add_constant", f"add_constant<{args}>")],
|
||||
)
|
||||
|
||||
|
||||
def add_constant(src: torch.Tensor, constant: int) -> torch.Tensor:
|
||||
if not src.is_cuda:
|
||||
raise RuntimeError("src must be a CUDA tensor")
|
||||
if src.dtype != torch.int32:
|
||||
raise RuntimeError(f"Unsupported dtype {src.dtype}. Supported: int32")
|
||||
dst = torch.empty_like(src)
|
||||
module = _jit_add_constant_module(constant)
|
||||
module.add_constant(dst, src)
|
||||
return dst
|
||||
|
||||
```
|
||||
|
||||
Keep the Python wrapper thin, but still validate the basic invariants such as device and dtype before dispatch. In the current JIT/FFI path, invalid tensors are not always rejected safely before launch.
|
||||
|
||||
### STEP 3: Use your kernel
|
||||
|
||||
Finally, import and use the kernel like a regular Python function:
|
||||
|
||||
```python Example
|
||||
from sglang.jit_kernel.add_constant import add_constant
|
||||
```
|
||||
|
||||
For a complete, runnable example, refer to [test_add_constant.py](https://github.com/sgl-project/sglang/blob/main/test/registered/jit/test_add_constant.py).
|
||||
|
||||
## C++ Include Library Reference
|
||||
|
||||
The JIT kernel framework provides a set of reusable C++ headers in
|
||||
`python/sglang/jit_kernel/include/sgl_kernel/`. Each header is designed
|
||||
to be lightweight and self-contained. Below is a summary of each header
|
||||
and its key APIs.
|
||||
|
||||
### Core Utilities
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>utils.h</code></td>
|
||||
<td><code>host</code></td>
|
||||
<td>Host-side essentials: <code>RuntimeCheck</code>, <code>Panic</code>, <code>div_ceil</code>, <code>irange</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>utils.cuh</code></td>
|
||||
<td><code>device</code> / <code>host</code></td>
|
||||
<td>Type aliases (<code>fp16_t</code>, <code>bf16_t</code>, ...), <code>SGL_DEVICE</code> macro, PDL helpers, <code>LaunchKernel</code>, <code>RuntimeDeviceCheck</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>source_location.h</code></td>
|
||||
<td>(global)</td>
|
||||
<td>Portable <code>std::source_location</code> wrapper for error reporting</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>runtime.cuh</code></td>
|
||||
<td><code>host::runtime</code></td>
|
||||
<td>CUDA runtime queries: <code>get_blocks_per_sm</code>, <code>get_sm_count</code>, <code>get_cc_major</code>, <code>get_runtime_version</code>, <code>get_available_dynamic_smem_per_block</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Tensor Validation
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>tensor.h</code></td>
|
||||
<td><code>host</code></td>
|
||||
<td><code>TensorMatcher</code>, <code>SymbolicSize</code>, <code>SymbolicDType</code>, <code>SymbolicDevice</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Math & Type System
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>math.cuh</code></td>
|
||||
<td><code>device::math</code></td>
|
||||
<td><code>max</code>, <code>min</code>, <code>abs</code>, <code>sqrt</code>, <code>rsqrt</code>, <code>exp</code>, <code>sin</code>, <code>cos</code>, constants</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>type.cuh</code></td>
|
||||
<td>(global) / <code>device</code></td>
|
||||
<td><code>dtype_trait<T></code>, <code>packed_t<T></code>, <code>device::cast<To>(from)</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Memory Access
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>vec.cuh</code></td>
|
||||
<td><code>device</code></td>
|
||||
<td><code>AlignedVector<T, N></code> - vectorized load/store (up to 128-bit; 256-bit requires Blackwell GPUs)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>tile.cuh</code></td>
|
||||
<td><code>device::tile</code></td>
|
||||
<td><code>Memory<T></code> - cooperative tiled memory I/O (thread/warp/CTA)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Parallel Primitives
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>warp.cuh</code></td>
|
||||
<td><code>device::warp</code></td>
|
||||
<td><code>reduce_sum</code>, <code>reduce_max</code> via <code>__shfl_xor_sync</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>cta.cuh</code></td>
|
||||
<td><code>device::cta</code></td>
|
||||
<td><code>reduce_max</code> across warps via shared memory</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>atomic.cuh</code></td>
|
||||
<td><code>device::atomic</code></td>
|
||||
<td><code>max</code> - atomic float max (CUDA + ROCm fallback)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Reusable Kernel Templates
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Namespace</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>impl/norm.cuh</code></td>
|
||||
<td><code>host::norm</code> / <code>device::norm</code></td>
|
||||
<td>RMSNorm building blocks (warp & CTA paths, <code>StorageType</code>)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: "Evaluating New Models with SGLang"
|
||||
metatags:
|
||||
description: "SGLang model evaluation: MMLU, GSM8K, GPQA, HumanEval, MMMU benchmarks. Latency and throughput testing commands."
|
||||
---
|
||||
This document provides commands for evaluating models' accuracy and performance. Before open-sourcing new models, we strongly suggest running these commands to verify whether the score matches your internal benchmark results.
|
||||
|
||||
**For cross verification, please submit commands for installation, server launching, and benchmark running with all the scores and hardware requirements when open-sourcing your models.**
|
||||
|
||||
[Reference: MiniMax M2](https://github.com/sgl-project/sglang/pull/12129)
|
||||
|
||||
## Accuracy
|
||||
|
||||
### LLMs
|
||||
|
||||
SGLang provides built-in scripts to evaluate common benchmarks.
|
||||
|
||||
**MMLU**
|
||||
|
||||
```bash Command
|
||||
python -m sglang.test.run_eval \
|
||||
--eval-name mmlu \
|
||||
--port 30000 \
|
||||
--num-examples 1000 \
|
||||
--max-tokens 8192
|
||||
```
|
||||
|
||||
**GSM8K**
|
||||
|
||||
```bash Command
|
||||
python -m sglang.test.few_shot_gsm8k \
|
||||
--host http://127.0.0.1 \
|
||||
--port 30000 \
|
||||
--num-questions 200 \
|
||||
--num-shots 5
|
||||
```
|
||||
|
||||
**HellaSwag**
|
||||
|
||||
```bash Command
|
||||
python benchmark/hellaswag/bench_sglang.py \
|
||||
--host http://127.0.0.1 \
|
||||
--port 30000 \
|
||||
--num-questions 200 \
|
||||
--num-shots 20
|
||||
```
|
||||
|
||||
**GPQA**
|
||||
|
||||
```bash Command
|
||||
python -m sglang.test.run_eval \
|
||||
--eval-name gpqa \
|
||||
--port 30000 \
|
||||
--num-examples 198 \
|
||||
--max-tokens 120000 \
|
||||
--repeat 8
|
||||
```
|
||||
|
||||
<Tip>
|
||||
For reasoning models, add `--thinking-mode <mode>` (e.g., `qwen3`, `deepseek-r1`, `deepseek-v3`). You may skip it if the model has forced thinking enabled.
|
||||
</Tip>
|
||||
|
||||
**HumanEval**
|
||||
|
||||
```bash Command
|
||||
pip install human_eval
|
||||
|
||||
python -m sglang.test.run_eval \
|
||||
--eval-name humaneval \
|
||||
--num-examples 10 \
|
||||
--port 30000
|
||||
```
|
||||
|
||||
### VLMs
|
||||
|
||||
**MMMU**
|
||||
|
||||
```bash Command
|
||||
python benchmark/mmmu/bench_sglang.py \
|
||||
--port 30000 \
|
||||
--concurrency 64
|
||||
```
|
||||
|
||||
<Tip>
|
||||
You can set max tokens by passing `--extra-request-body '{"max_tokens": 4096}'`.
|
||||
</Tip>
|
||||
|
||||
For models capable of processing video, we recommend extending the evaluation to include `VideoMME`, `MVBench`, and other relevant benchmarks.
|
||||
|
||||
## Performance
|
||||
|
||||
Performance benchmarks measure **Latency** (Time To First Token - TTFT) and **Throughput** (tokens/second).
|
||||
|
||||
### LLMs
|
||||
|
||||
**Latency-Sensitive Benchmark**
|
||||
|
||||
This simulates a scenario with low concurrency (e.g., single user) to measure latency.
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 0.0.0.0 \
|
||||
--port 30000 \
|
||||
--dataset-name random \
|
||||
--num-prompts 10 \
|
||||
--max-concurrency 1
|
||||
```
|
||||
|
||||
**Throughput-Sensitive Benchmark**
|
||||
|
||||
This simulates a high-traffic scenario to measure maximum system throughput.
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_serving \
|
||||
--backend sglang \
|
||||
--host 0.0.0.0 \
|
||||
--port 30000 \
|
||||
--dataset-name random \
|
||||
--num-prompts 1000 \
|
||||
--max-concurrency 100
|
||||
```
|
||||
|
||||
**Single Batch Performance**
|
||||
|
||||
You can also benchmark the performance of processing a single batch offline.
|
||||
|
||||
```bash Command
|
||||
python -m sglang.bench_one_batch_server \
|
||||
--model <model-path> \
|
||||
--batch-size 8 \
|
||||
--input-len 1024 \
|
||||
--output-len 1024
|
||||
```
|
||||
|
||||
You can run more granular benchmarks:
|
||||
|
||||
- **Low Concurrency**: `--num-prompts 10 --max-concurrency 1`
|
||||
- **Medium Concurrency**: `--num-prompts 80 --max-concurrency 16`
|
||||
- **High Concurrency**: `--num-prompts 500 --max-concurrency 100`
|
||||
|
||||
## Reporting Results
|
||||
|
||||
For each evaluation, please report:
|
||||
|
||||
1. **Metric Score**: Accuracy % (LLMs and VLMs); Latency (ms) and Throughput (tok/s) (LLMs only).
|
||||
2. **Environment settings**: GPU type/count, SGLang commit hash.
|
||||
3. **Launch configuration**: Model path, TP size, and any special flags.
|
||||
4. **Evaluation parameters**: Number of shots, examples, max tokens.
|
||||
@@ -0,0 +1,601 @@
|
||||
---
|
||||
title: "MSProbe Debugging Guide"
|
||||
metatags:
|
||||
description: "Debugging AI model accuracy anomalies and numerical errors during inference using MSProbe in SGLang."
|
||||
---
|
||||
MSProbe is a debugging tool for AI models that diagnoses accuracy anomalies and
|
||||
numerical errors during model training and inference. It captures and monitors intermediate data (feature maps, weights,
|
||||
activations, layer outputs) and contextual metadata (prompts, tensor dtypes, hardware configuration), and supports
|
||||
visual analysis to systematically trace the root cause of accuracy degradation or numerical errors (e.g., NaN/Inf,
|
||||
output drift, mismatched predictions).
|
||||
|
||||
## Basic Details
|
||||
|
||||
### Background Concepts: MSProbe Dumping Levels
|
||||
|
||||
MSProbe supports three accuracy levels for data dumping, each for different debugging needs:
|
||||
|
||||
- **L0**: Dumps tensors/statistics at the **module level** and generates `construct.json` (for network structure
|
||||
reconstruction in visualization). Requires passing a model/submodule handle.
|
||||
- **L1**: Dumps tensors/statistics at the **torch API level**, suitable for fine-grained API-level numerical checking.
|
||||
- **mix**: Combines L0 + L1, ideal for scenarios that require both **graph reconstruction** and **numerical comparison**.
|
||||
|
||||
### Prerequisites: Install MSProbe
|
||||
|
||||
Install MSProbe with pip:
|
||||
|
||||
```shell
|
||||
pip install mindstudio-probe --pre
|
||||
```
|
||||
|
||||
### Key Configuration Parameters
|
||||
|
||||
MSProbe uses a JSON configuration file for customized data dumping. All core parameters are listed in the table below,
|
||||
with the default JSON configuration provided for reference.
|
||||
|
||||
#### Configuration Parameter Table
|
||||
|
||||
| Field | Description | Required |
|
||||
|:------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|
|
||||
| `task` | Type of dump task. Common PyTorch values include `"statistics"` and `"tensor"`. A statistics task collects tensor statistics (mean, variance, max, min, etc.) while a tensor task captures arbitrary tensors. | Yes |
|
||||
| `dump_path` | Directory where dump results are stored. When omitted, `MSProbe` uses its default path. | No |
|
||||
| `rank` | Ranks to sample. An empty list collects every rank. For single-card tasks you must set this field to `[]`. | No |
|
||||
| `step` | Token iteration(s) to sample. An empty list means every iteration. | No |
|
||||
| `level` | Dump level string (`"L0"`, `"L1"`, or `"mix"`). `L0` targets `nn.Module`, `L1` targets `torch.api`, and `mix` collects both. | Yes |
|
||||
| `async_dump` | Whether to enable asynchronous dump (supported for PyTorch `statistics`/`tensor` tasks). Defaults to `false`. | No |
|
||||
| `scope` | Customize the scope of dump. Provide two module or API names that follow the tool's naming convention to lock a range, only data between the two names will be dumped. An empty list dumps every module or torch API.<br/><br/>Examples:<br/>`"scope": ["Module.conv1.Conv2d.forward.0", "Module.fc2.Linear.forward.0"]`<br/>`"scope": ["Tensor.add.0.forward", "Functional.square.2.forward"]`<br/><br/>The `level` setting determines what can be provided—modules when `level=L0`, APIs when `level=L1`, and either modules or APIs when `level=mix`. | No |
|
||||
| `list` | Customize dump list, only dumps elements from the list. An empty list dumps every module or torch API. Options include:<br/><br/>•Supply the full names of specific APIs in PyTorch eager mode to only dump those APIs. Example: `"list": ["Tensor.permute.1.forward", "Tensor.transpose.2.forward", "Torch.relu.3.backward"]`.<br/>•When `level=mix`, you can provide module names so that the dump expands to everything produced while the module is running. Example: `"list": ["Module.module.language_model.encoder.layers.0.mlp.ParallelMlp.forward.0"]`.<br/>•Provide a substring such as `"list": ["relu"]` to dump every API whose name contains the substring. When `level=mix`, modules whose names contain the substring are also expanded. | No |
|
||||
|
||||
#### Default configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "statistics",
|
||||
"dump_path": "./dump_path",
|
||||
"rank": [],
|
||||
"step": [],
|
||||
"level": "L1",
|
||||
"async_dump": false,
|
||||
"statistics": {
|
||||
"scope": [],
|
||||
"list": [],
|
||||
"data_mode": [
|
||||
"all"
|
||||
],
|
||||
"summary_mode": "statistics"
|
||||
},
|
||||
"tensor": {
|
||||
"scope": [],
|
||||
"list": [],
|
||||
"data_mode": [
|
||||
"all"
|
||||
],
|
||||
"file_format": "npy"
|
||||
},
|
||||
"acc_check": {
|
||||
"white_list": [],
|
||||
"black_list": [],
|
||||
"error_data_path": "./"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Outputs
|
||||
|
||||
Dump files are written into `dump_path` you defined. They usually contain:
|
||||
|
||||
- `dump.json`, which records metadata such as dtype, shape, min, max, mean, L2 norm, and `requires_grad`.
|
||||
- `construct.json`, hierarchical structure description, when `level` is `L0` or `mix` (required for visualization), its
|
||||
content is not empty.
|
||||
- `stack.json`, record the call stack information of API/Module.
|
||||
- `dump_tensor_data`, generated when `task` is `tensor` and save the collected tensor data.
|
||||
|
||||
See [dump directory description](#dump-directory-description) for details.
|
||||
|
||||
> **Note**: When MSProbe is enabled, cuda graph is disabled (disable_cuda_graph=True) because MSProbe only supports dump
|
||||
> in eager mode, warmup is disabled (skip_server_warmup=True) because there is no need to dump data for this stage.
|
||||
|
||||
## End-to-End Examples
|
||||
|
||||
MSProbe’s full debugging workflow follows **Enable → Collect Data → Visualize → Analyze Root Cause**. Below is a common
|
||||
E2E example for SGLang-based model inference debugging.
|
||||
|
||||
### Example : Advanced Debugging with Custom Configuration
|
||||
|
||||
Suitable for targeted debugging (e.g., only collect statistics data for specific ranks/steps, enable mix level for graph
|
||||
reconstruction + numerical comparison) and root cause analysis via **problem vs. benchmark comparison**.
|
||||
|
||||
#### Step 1: Enable
|
||||
##### Prepare Custom Configuration JSON
|
||||
|
||||
Create `msprobe-config.json` (dump statistics data for rank0/1, step0/1, mix level):
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "statistics",
|
||||
"dump_path": "./problem_dump",
|
||||
"rank": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"step": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"level": "mix",
|
||||
"async_dump": false,
|
||||
"statistics": {
|
||||
"scope": [],
|
||||
"list": [],
|
||||
"data_mode": [
|
||||
"all"
|
||||
],
|
||||
"summary_mode": "statistics"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### Enable MSProbe with Custom Configuration in SGLang
|
||||
|
||||
Launch the SGLang server and specify the configuration file path with `--msprobe-dump-config`:
|
||||
|
||||
```bash
|
||||
python3 -m sglang.launch_server \
|
||||
--model-path Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--host 127.0.0.1 \
|
||||
--port 1027 \
|
||||
--msprobe-dump-config /home/msprobe-config.json
|
||||
```
|
||||
#### Step 2: Collect Data
|
||||
##### Collect Dump Data for Problem & Benchmark Sides
|
||||
|
||||
Send normal inference requests to trigger model running (MSProbe automatically collects data during request processing):
|
||||
|
||||
```bash
|
||||
curl -H "Content-type: application/json" \
|
||||
-X POST \
|
||||
-d '{
|
||||
"model": "Qwen/Qwen2.5-0.5B-Instruct",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello, my name is"
|
||||
}
|
||||
],
|
||||
"max_tokens": 10
|
||||
}' \
|
||||
http://127.0.0.1:1027/v1/chat/completions
|
||||
```
|
||||
|
||||
- **Problem side**: Run the above SGLang server (with the accuracy/numerical issue) and send inference request; dump
|
||||
data is saved to `./problem_dump`.
|
||||
- **Benchmark side**: Launch a normal SGLang server (without the issue, e.g., stable framework version/operator) with
|
||||
the **same custom configuration** and send the **same inference request**; rename the dump directory
|
||||
to `./bench_dump`.
|
||||
|
||||
> **Key Requirement**: Problem and benchmark dumps must use the same inputs and sampling points (rank/step)
|
||||
> for valid comparison.
|
||||
|
||||
##### Check Generated Dump Files
|
||||
|
||||
Dump files are saved to `./problem_dump` and `./bench_dump` you defined and include core files for subsequent analysis:
|
||||
|
||||
- `dump.json`: Records tensor metadata of APIs and modules (dtype, shape, min/max/mean, L2 norm, `requires_grad`, etc.).
|
||||
- `stack.json`: Logs call stack information of APIs and modules.
|
||||
- `construct.json`: hierarchical structure description, required for visualization, its content is not empty.
|
||||
|
||||
#### Step 3: Visualize
|
||||
##### Visualize Problem vs. Benchmark Comparison (Multi-Rank)
|
||||
|
||||
Generate a multi-rank comparison visualization file (mix level generates `construct.json` for graph reconstruction):
|
||||
|
||||
```shell
|
||||
msprobe graph_visualize -tp ./problem_dump/step0 -gp ./bench_dump/step0 -o ./graph_output
|
||||
```
|
||||
|
||||
- `-tp`: Path to problem-side dump data
|
||||
- `-gp`: Path to benchmark-side dump data
|
||||
- `-o`: Output directory for visualization files
|
||||
|
||||
If you want overflow check (for NaN/Inf detection), please specify the parameter `-oc`
|
||||
|
||||
```shell
|
||||
msprobe graph_visualize -tp ./problem_dump/step0 -gp ./bench_dump/step0 -o ./graph_output -oc
|
||||
```
|
||||
|
||||
After the comparison or build task finishes, a `compare_{timestamp}.vis.db` file is created under `graph_output`.
|
||||
|
||||
The dumped data can be used to visualize and analyze differences using tables or charts generated with visualization tools such as Matplotlib and Excel.
|
||||
|
||||
##### Launch TensorBoard
|
||||
|
||||
Start TensorBoard:
|
||||
```bash
|
||||
tensorboard --logdir ./graph_output --bind_all --port 6006
|
||||
```
|
||||
#### Step 4: Analyze Root Cause
|
||||
##### Locate Root Cause
|
||||
|
||||
Root Cause Analysis in TensorBoard:
|
||||
- Divergent nodes (with accuracy/numerical differences) are highlighted in **red** (darker red = larger difference).
|
||||
- Click on divergent nodes to view detailed tensor data (inputs/outputs, parameters) and API/module call stacks.
|
||||
- Use the **search/filter** function to quickly locate key layers/APIs (e.g., "relu", "conv").
|
||||
- Switch between ranks/steps via the UI to check cross-rank/cross-step divergence.
|
||||
- Check the **overflow check** tab for NaN/Inf values in specific nodes (the direct cause of numerical instability).
|
||||
|
||||
##### Verify the Root Cause
|
||||
|
||||
After locating the divergent node (e.g., a specific Conv layer or torch API with abnormal tensor values), verify by:
|
||||
|
||||
- Narrowing the dump scope to this node (via `scope`/`list` in the configuration file) for fine-grained data collection.
|
||||
- Modifying the problematic layer/API (e.g., replacing the operator, adjusting the dtype) and re-running the debugging
|
||||
workflow to confirm the issue is resolved.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Dump Files Generated
|
||||
|
||||
1. To confirm if MSProbe is installed, use `pip show mindstudio_probe` to troubleshoot. If it is installed, the MSProbe
|
||||
version information will be printed. If it is confirmed that it has not been installed, please
|
||||
use `pip install mindstudio-probe --pre` for installation;
|
||||
2. Confirm the `--msprobe-dump-config` parameter points to the **correct JSON file path**.
|
||||
|
||||
### Dump Files Are Too Large (Excessive Data)
|
||||
|
||||
1. Start with `task: "statistics"` instead of `"tensor"` to collect only tensor statistics (avoids raw tensor dump);
|
||||
2. Narrow the dump range with the `scope` field (specify start/end module/API);
|
||||
3. Filter dump targets with the `list` field (only dump specific modules/APIs or substrings);
|
||||
4. Sample specific `rank` and `step` (avoid dumping all ranks/iterations).
|
||||
|
||||
### TensorBoard Visualization Fails
|
||||
|
||||
1. Confirm `construct.json` is not empty (requires `level: L0` or `mix` – L1 does not generate graph files);
|
||||
2. Check that the `-tp` (problem dump) and `-gp` (benchmark dump) paths point to **valid rank/step subdirectories** (
|
||||
e.g., `step0/rank0`);
|
||||
3. Ensure the MSProbe version is up-to-date (reinstall with `pip install mindstudio-probe --pre --upgrade`);
|
||||
4. Verify TensorBoard is installed and the `--logdir` parameter points to the directory containing `.vis.db` files (not
|
||||
the file itself).
|
||||
|
||||
### Numerical Comparison Shows No Divergence But Model Accuracy Is Low
|
||||
|
||||
1. Expand the dump `step` range (check more token iterations for late-stage divergence);
|
||||
2. Switch to `task: "tensor"` (statistics may mask subtle numerical differences in raw tensor data);
|
||||
3. Ensure the problem and benchmark dumps use **the same input data/hardware configuration** (different inputs lead to
|
||||
invalid comparisons);
|
||||
4. Use the `manual mapping` feature in TensorBoard (automatic mapping may miss some nodes for custom models).
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
|
||||
### Dump directory description
|
||||
|
||||
```text
|
||||
├── problem_dump or bench_dump
|
||||
│ ├── step0
|
||||
│ │ ├── rank0
|
||||
│ │ │ ├── dump_tensor_data
|
||||
│ │ │ │ ├── Tensor.permute.1.forward.pt
|
||||
│ │ │ │ ├── Functional.linear.5.backward.output.pt # Format: {api_type}.{api_name}.{call_count}.{forward/backward}.{input/output}.{arg_index}.
|
||||
│ │ │ │ │ # arg_index is the nth input or output of the API. If an input is a list, keep numbering with decimals (e.g., 1.1 is the first element of the first argument).
|
||||
│ │ │ │ ├── Module.conv1.Conv2d.forward.0.input.0.pt # Format: {Module}.{module_name}.{class_name}.{forward/backward}.{call_count}.{input/output}.{arg_index}.
|
||||
│ │ │ │ ├── Module.conv1.Conv2d.forward.0.parameters.bias.pt # Module parameter data: {Module}.{module_name}.{class_name}.forward.{call_count}.parameters.{parameter_name}.
|
||||
│ │ │ │ └── Module.conv1.Conv2d.parameters_grad.weight.pt # Module parameter gradients: {Module}.{module_name}.{class_name}.parameters_grad.{parameter_name}. Gradients do not include call_count because the same gradient updates all invocations.
|
||||
│ │ │ │ # When the `model` argument passed to dump is a List[torch.nn.Module] or Tuple[torch.nn.Module], module-level data names also include the index inside the list ({Module}.{index}.*), e.g., Module.0.conv1.Conv2d.forward.0.input.0.pt.
|
||||
│ │ │ ├── dump.json
|
||||
│ │ │ ├── stack.json
|
||||
│ │ │ ├── dump_error_info.log
|
||||
│ │ │ └── construct.json
|
||||
│ │ ├── rank1
|
||||
│ │ │ ├── dump_tensor_data
|
||||
│ │ │ │ └── ...
|
||||
│ │ │ ├── dump.json
|
||||
│ │ │ ├── stack.json
|
||||
│ │ │ ├── dump_error_info.log
|
||||
│ │ │ └── construct.json
|
||||
│ │ ├── ...
|
||||
│ │ │
|
||||
│ │ └── rank7
|
||||
│ ├── step1
|
||||
│ │ ├── ...
|
||||
│ ├── step2
|
||||
```
|
||||
|
||||
- `rank`: Device ID. Each card writes its data to the corresponding `rank{ID}` directory. In non-distributed scenarios
|
||||
the directory is simply named `rank`.
|
||||
- `dump_tensor_data`: Save the collected tensor data.
|
||||
- `dump.json`: Statistics for the forward data of each API or module, including names, dtype, shape, max, min, mean, L2
|
||||
norm (square root of the L2 variance), and CRC-32 when `summary_mode="md5"`.
|
||||
See [dump.json file description](#dumpjson-file-description) for details.
|
||||
- `dump_error_info.log`: Present only when the dump tool encountered an error and records the failure log.
|
||||
- `stack.json`: Call stacks for APIs/modules.
|
||||
- `construct.json`: Hierarchical structure description. Empty when `level=L1`.
|
||||
|
||||
### dump.json file description
|
||||
|
||||
#### L0 level
|
||||
|
||||
An L0 `dump.json` contains forward/backward I/O for modules together with parameters and parameter gradients. Using
|
||||
PyTorch's `Conv2d` as an example, the network code looks like:
|
||||
|
||||
`output = self.conv2(input) # self.conv2 = torch.nn.Conv2d(64, 128, 5, padding=2, bias=True)`
|
||||
|
||||
`dump.json` contains the following entries:
|
||||
|
||||
- `Module.conv2.Conv2d.forward.0`: Forward data of the module. `input_args` represents positional inputs, `input_kwargs`
|
||||
represents keyword inputs, `output` stores forward outputs, and `parameters` stores weights/biases.
|
||||
- `Module.conv2.Conv2d.parameters_grad`: Parameter gradients (weight and bias).
|
||||
- `Module.conv2.Conv2d.backward.0`: Backward data of the module. `input` represents gradients that flow into the
|
||||
module (gradients of the forward outputs) and `output` represents gradients that flow out (gradients of the module
|
||||
inputs).
|
||||
|
||||
**Note**: When the `model` parameter passed to the dump API is `List[torch.nn.Module]` or `Tuple[torch.nn.Module]`,
|
||||
module-level names include the index inside the list (`{Module}.{index}.*`). Example: `Module.0.conv1.Conv2d.forward.0`.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>L0 dump.json</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "tensor",
|
||||
"level": "L0",
|
||||
"framework": "pytorch",
|
||||
"dump_data_dir": "/dump/path",
|
||||
"data": {
|
||||
"Module.conv2.Conv2d.forward.0": {
|
||||
"input_args": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
8,
|
||||
16,
|
||||
14,
|
||||
14
|
||||
],
|
||||
"Max": 1.638758659362793,
|
||||
"Min": 0.0,
|
||||
"Mean": 0.2544615864753723,
|
||||
"Norm": 70.50277709960938,
|
||||
"requires_grad": true,
|
||||
"data_name": "Module.conv2.Conv2d.forward.0.input.0.pt"
|
||||
}
|
||||
],
|
||||
"input_kwargs": {},
|
||||
"output": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
8,
|
||||
32,
|
||||
10,
|
||||
10
|
||||
],
|
||||
"Max": 1.6815717220306396,
|
||||
"Min": -1.5120246410369873,
|
||||
"Mean": -0.025344856083393097,
|
||||
"Norm": 149.65576171875,
|
||||
"requires_grad": true,
|
||||
"data_name": "Module.conv2.Conv2d.forward.0.output.0.pt"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"weight": {
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"Max": 0.05992485210299492,
|
||||
"Min": -0.05999220535159111,
|
||||
"Mean": -0.0006165213999338448,
|
||||
"Norm": 3.421217441558838,
|
||||
"requires_grad": true,
|
||||
"data_name": "Module.conv2.Conv2d.forward.0.parameters.weight.pt"
|
||||
},
|
||||
"bias": {
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32
|
||||
],
|
||||
"Max": 0.05744686722755432,
|
||||
"Min": -0.04894155263900757,
|
||||
"Mean": 0.006410328671336174,
|
||||
"Norm": 0.17263513803482056,
|
||||
"requires_grad": true,
|
||||
"data_name": "Module.conv2.Conv2d.forward.0.parameters.bias.pt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Module.conv2.Conv2d.parameters_grad": {
|
||||
"weight": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"Max": 0.018550323322415352,
|
||||
"Min": -0.008627401664853096,
|
||||
"Mean": 0.0006675920449197292,
|
||||
"Norm": 0.26084786653518677,
|
||||
"requires_grad": false,
|
||||
"data_name": "Module.conv2.Conv2d.parameters_grad.weight.pt"
|
||||
}
|
||||
],
|
||||
"bias": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32
|
||||
],
|
||||
"Max": 0.014914230443537235,
|
||||
"Min": -0.006656786892563105,
|
||||
"Mean": 0.002657240955159068,
|
||||
"Norm": 0.029451673850417137,
|
||||
"requires_grad": false,
|
||||
"data_name": "Module.conv2.Conv2d.parameters_grad.bias.pt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Module.conv2.Conv2d.backward.0": {
|
||||
"input": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
8,
|
||||
32,
|
||||
10,
|
||||
10
|
||||
],
|
||||
"Max": 0.0015069986693561077,
|
||||
"Min": -0.001139344065450132,
|
||||
"Mean": 3.3215508210560074e-06,
|
||||
"Norm": 0.020567523315548897,
|
||||
"requires_grad": false,
|
||||
"data_name": "Module.conv2.Conv2d.backward.0.input.0.pt"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
8,
|
||||
16,
|
||||
14,
|
||||
14
|
||||
],
|
||||
"Max": 0.0007466732058674097,
|
||||
"Min": -0.00044813455315306783,
|
||||
"Mean": 6.814070275140693e-06,
|
||||
"Norm": 0.01474067009985447,
|
||||
"requires_grad": false,
|
||||
"data_name": "Module.conv2.Conv2d.backward.0.output.0.pt"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### L1 level
|
||||
|
||||
An L1 `dump.json` records forward/backward I/O for APIs. Using PyTorch's `relu` function as an
|
||||
example (`output = torch.nn.functional.relu(input)`), the file contains:
|
||||
|
||||
- `Functional.relu.0.forward`: Forward data of the API. `input_args` are positional inputs, `input_kwargs` are keyword
|
||||
inputs, and `output` stores the forward outputs.
|
||||
- `Functional.relu.0.backward`: Backward data of the API. `input` represents the gradients of the forward outputs,
|
||||
and `output` represents the gradients that flow back to the forward inputs.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>L1 dump.json</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "tensor",
|
||||
"level": "L1",
|
||||
"framework": "pytorch",
|
||||
"dump_data_dir": "/dump/path",
|
||||
"data": {
|
||||
"Functional.relu.0.forward": {
|
||||
"input_args": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
28,
|
||||
28
|
||||
],
|
||||
"Max": 1.3864083290100098,
|
||||
"Min": -1.3364859819412231,
|
||||
"Mean": 0.03711778670549393,
|
||||
"Norm": 236.20692443847656,
|
||||
"requires_grad": true,
|
||||
"data_name": "Functional.relu.0.forward.input.0.pt"
|
||||
}
|
||||
],
|
||||
"input_kwargs": {},
|
||||
"output": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
28,
|
||||
28
|
||||
],
|
||||
"Max": 1.3864083290100098,
|
||||
"Min": 0.0,
|
||||
"Mean": 0.16849493980407715,
|
||||
"Norm": 175.23345947265625,
|
||||
"requires_grad": true,
|
||||
"data_name": "Functional.relu.0.forward.output.0.pt"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Functional.relu.0.backward": {
|
||||
"input": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
28,
|
||||
28
|
||||
],
|
||||
"Max": 0.0001815402356442064,
|
||||
"Min": -0.00013352684618439525,
|
||||
"Mean": 0.00011915402356442064,
|
||||
"Norm": 0.007598237134516239,
|
||||
"requires_grad": false,
|
||||
"data_name": "Functional.relu.0.backward.input.0.pt"
|
||||
}
|
||||
],
|
||||
"output": [
|
||||
{
|
||||
"type": "torch.Tensor",
|
||||
"dtype": "torch.float32",
|
||||
"shape": [
|
||||
32,
|
||||
16,
|
||||
28,
|
||||
28
|
||||
],
|
||||
"Max": 0.0001815402356442064,
|
||||
"Min": -0.00012117840378778055,
|
||||
"Mean": 2.0098118724831693e-08,
|
||||
"Norm": 0.006532244384288788,
|
||||
"requires_grad": false,
|
||||
"data_name": "Functional.relu.0.backward.output.0.pt"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### mix level
|
||||
|
||||
A `mix` dump.json contains both L0 and L1 level data; the file format is the same as the examples above.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: Developer Guide
|
||||
description: Contributing to SGLang — development setup, benchmarking, and evaluation.
|
||||
---
|
||||
|
||||
- [Contribution Guide](./contribution_guide)
|
||||
- [Development Guide (Docker)](./development_guide_using_docker)
|
||||
- [JIT Kernels](./development_jit_kernel_guide)
|
||||
- [Quantization Contribution Guide](./quantization_contribution_guide)
|
||||
- [Benchmark and Profiling](./benchmark_and_profiling)
|
||||
- [Bench Serving](./bench_serving)
|
||||
- [Evaluating New Models](./evaluating_new_models)
|
||||
- [MSProbe Debugging Guide](./msprobe_debugging_guide)
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: "Quantization Contribution Guide"
|
||||
metatags:
|
||||
description: "Guidance for contributing SGLang quantization methods, schemes, backend kernels, tests, and validation results."
|
||||
---
|
||||
|
||||
This guide describes how to add or refactor quantization support in SGLang. It focuses on the common structure used by weight-only and weight-activation quantization methods such as AWQ, GPTQ, compressed-tensors, ModelSlim, Quark, and related backend kernels.
|
||||
|
||||
## Design Goals
|
||||
|
||||
Quantization code should keep the quantization format semantics separate from hardware-specific execution. This makes it easier to add new formats, reuse kernels across formats, and review platform-specific changes independently.
|
||||
|
||||
Follow the architecture proposed in [Quantization Modifications](https://github.com/sgl-project/sglang/issues/15194):
|
||||
|
||||
- **Config**: parses model and runtime quantization parameters, validates supported options, and selects the proper scheme.
|
||||
- **Scheme**: owns quantized weight creation, weight loading, post-processing, and quantized layer wiring for Linear, MoE, embedding, or other module types.
|
||||
- **Backend kernel**: wraps hardware-specific execution, layout conversion, kernel selection, and kernel calls for GPU (CUDA/HIP/XPU), NPU, or other backends.
|
||||
|
||||
Avoid putting config parsing, weight loading, and backend kernel calls in a single monolithic file. If a method needs multiple formats or backends, add a package under `python/sglang/srt/layers/quantization/<method>/` and split schemes into `schemes/`.
|
||||
|
||||
## Recommended File Layout
|
||||
|
||||
Use this layout for a quantization method that has multiple schemes or backend-specific execution paths:
|
||||
|
||||
```text
|
||||
python/sglang/srt/layers/quantization/<method>/
|
||||
__init__.py
|
||||
<method>.py
|
||||
schemes/
|
||||
__init__.py
|
||||
<method>_scheme.py
|
||||
<method>_linear.py
|
||||
<method>_moe.py
|
||||
<method>_<variant>.py
|
||||
```
|
||||
|
||||
Backend kernels should live under the hardware backend they target:
|
||||
|
||||
```text
|
||||
python/sglang/srt/hardware_backend/gpu/quantization/<method>_kernels.py
|
||||
python/sglang/srt/hardware_backend/npu/quantization/<method>_kernels.py
|
||||
```
|
||||
|
||||
Keep shared method selection in the quantization package and keep backend imports narrow. This prevents circular imports and keeps non-target platforms from importing unavailable kernel dependencies.
|
||||
|
||||
## Adding or Refactoring a Quantization Method
|
||||
|
||||
1. Define the config entry point and register it through `python/sglang/srt/layers/quantization/__init__.py` when needed.
|
||||
2. Add explicit scheme selection helpers such as `get_linear_scheme` and `get_moe_scheme`.
|
||||
3. Move layer-specific weight creation and weight loading into scheme classes.
|
||||
4. Move GPU (CUDA/HIP/XPU), NPU, or other hardware kernel calls into backend kernel modules.
|
||||
5. Keep Linear, MoE, embedding, and non-linear module handling explicit. Do not assign a Linear quantization method to a module type that needs different semantics.
|
||||
6. Preserve compatibility for existing quantized checkpoints and runtime flags.
|
||||
7. Add tests that cover both config parsing and execution paths touched by the change.
|
||||
|
||||
For examples, see the AWQ and GPTQ refactors:
|
||||
|
||||
- [PR #21126](https://github.com/sgl-project/sglang/pull/21126): splits AWQ schemes, weight initialization, and backend kernel calls.
|
||||
- [PR #26402](https://github.com/sgl-project/sglang/pull/26402): applies the same scheme/kernel split to GPTQ.
|
||||
|
||||
## Tests and Validation
|
||||
|
||||
Quantization changes can affect both accuracy and performance. Include validation that matches the blast radius of the change.
|
||||
|
||||
For Python-only structure changes:
|
||||
|
||||
```bash
|
||||
ruff check <changed-python-files>
|
||||
git diff --check
|
||||
```
|
||||
|
||||
For quantized model behavior:
|
||||
|
||||
- Launch at least one representative model for each touched quantization method.
|
||||
- Send a `/generate` request and confirm the output path succeeds.
|
||||
- Run an accuracy sanity test if the change can affect numerics.
|
||||
- Include warmup-aware benchmark results when the change affects kernel calls, layout conversion, or dispatch.
|
||||
|
||||
For backend-specific changes:
|
||||
|
||||
- Validate GPU changes on a supported GPU environment (NVIDIA, AMD, or Intel).
|
||||
- Validate NPU changes on a supported Ascend environment.
|
||||
- Include the exact model, quantization flag, backend flag, hardware, and command used in the PR description.
|
||||
|
||||
## PR Checklist
|
||||
|
||||
Before requesting review, make sure the PR description includes:
|
||||
|
||||
- The quantization method and backend paths changed.
|
||||
- The issue, design proposal, or roadmap item the PR follows.
|
||||
- Any compatibility notes for existing checkpoints or flags.
|
||||
- Accuracy results when model outputs can change.
|
||||
- Benchmark or profiling results when runtime performance can change.
|
||||
- The exact local checks and model launch tests that were run.
|
||||
|
||||
Use the general [Contribution Guide](./contribution_guide) for source setup, formatting, unit tests, CI triggering, and review process details.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: "PyPI Package Release Process"
|
||||
metatags:
|
||||
description: "SGLang PyPI release: version update, upload_pypi.sh script, GitHub release creation."
|
||||
---
|
||||
## Update the version in code
|
||||
Update the package version in `python/pyproject.toml` and `python/sglang/__init__.py`.
|
||||
|
||||
## Upload the PyPI package
|
||||
|
||||
```text Output
|
||||
pip install build twine
|
||||
```
|
||||
|
||||
```text Output
|
||||
cd python
|
||||
bash upload_pypi.sh
|
||||
```
|
||||
|
||||
## Make a release in GitHub
|
||||
Make a new release https://github.com/sgl-project/sglang/releases/new.
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "Set Up Self-Hosted Runners for GitHub Action"
|
||||
metatags:
|
||||
description: "SGLang GitHub Actions self-hosted runner: Docker setup for NVIDIA/AMD GPUs, config.sh and run.sh."
|
||||
---
|
||||
## Add a Runner
|
||||
|
||||
### Step 1: Start a docker container.
|
||||
|
||||
**You can mount a folder for the shared huggingface model weights cache. **
|
||||
The command below uses `/tmp/huggingface` as an example.
|
||||
|
||||
```
|
||||
docker pull nvidia/cuda:12.9.1-devel-ubuntu22.04
|
||||
# Nvidia
|
||||
docker run --shm-size 128g -it -v /tmp/huggingface:/hf_home --gpus all nvidia/cuda:12.9.1-devel-ubuntu22.04 /bin/bash
|
||||
# AMD
|
||||
docker run --rm --device=/dev/kfd --device=/dev/dri --group-add video --shm-size 128g -it -v /tmp/huggingface:/hf_home lmsysorg/sglang:v0.5.8-rocm700-mi30x /bin/bash
|
||||
# AMD just the last 2 GPUs
|
||||
docker run --rm --device=/dev/kfd --device=/dev/dri/renderD176 --device=/dev/dri/renderD184 --group-add video --shm-size 128g -it -v /tmp/huggingface:/hf_home lmsysorg/sglang:v0.5.8-rocm700-mi30x /bin/bash
|
||||
```
|
||||
|
||||
### Step 2: Configure the runner by `config.sh`
|
||||
|
||||
Run these commands inside the container.
|
||||
|
||||
```text Output
|
||||
apt update && apt install -y curl python3-pip git
|
||||
pip install --upgrade pip
|
||||
export RUNNER_ALLOW_RUNASROOT=1
|
||||
```
|
||||
|
||||
Then follow https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners to run `config.sh`
|
||||
|
||||
**Notes**
|
||||
- Do not need to specify the runner group
|
||||
- Give it a name (e.g., `test-sgl-gpu-0`) and some labels (e.g., `1-gpu-h100`). The labels can be edited later in Github Settings.
|
||||
- Do not need to change the work folder.
|
||||
|
||||
### Step 3: Run the runner by `run.sh`
|
||||
|
||||
- Set up environment variables
|
||||
```text Output
|
||||
export HF_HOME=/hf_home
|
||||
export SGLANG_IS_IN_CI=true
|
||||
export HF_TOKEN=hf_xxx
|
||||
export OPENAI_API_KEY=sk-xxx
|
||||
export CUDA_VISIBLE_DEVICES=0
|
||||
```
|
||||
|
||||
- Run it forever
|
||||
```text Output
|
||||
while true; do ./run.sh; echo "Restarting..."; sleep 2; done
|
||||
```
|
||||
Reference in New Issue
Block a user