Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ with patch.dict(os.environ, H100Rack.slurm_env()):
- `endpoints_to_processes()` - Physical process mapping; every port through `NodePortAllocator`
- `build_worker_command(process, runtime)` - Command construction
- `get_process_environment(process)` - Per-process env derived from `Process` ports (side channels, scan bases)
- `get_frontend_integration_environment(mode, frontend_type, frontend_args)` - frontend integration defaults, or `{}`
- `mooncake_kv_store` / `get_mooncake_worker_env(...)` - the Mooncake block and its worker env; `None` / `{}` without one
- `failover` / `get_failover_environment(...)` - shadow engine recovery; `None` / `{}` without it
- `should_set_visible_devices()` - `True` unless the engine takes its devices on the command line; the variable is the cluster's `visible_devices_env`
Expand All @@ -377,6 +378,7 @@ with patch.dict(os.environ, H100Rack.slurm_env()):
4. Add polymorphic deserialization in `BackendConfigField` in `schema.py`

**Current backends:**
- **ATOM**: Native ROCm servers behind AToMesh, with one Slurm node per logical worker and allocator-owned Mooncake handshake ports
- **SGLang**: Per-process srun launching, supports prefill/decode/aggregated modes
- **TRTLLM**: MPI-style launching (one srun per endpoint with all nodes), prefill/decode only
- **vLLM**: Per-process srun launching, prefill/decode/aggregated, `per_node` DP; `frontend_type` selects Dynamo registration or a direct `vllm serve` server, and `_CONNECTOR_MAP` owns the KV connector table
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# srtctl

Command-line tool for distributed LLM inference benchmarks on SLURM clusters using TensorRT LLM, SGLang and vLLM. Replace complex shell scripts and 50+ CLI flags with a declarative `schema: 2` YAML recipe: `engine:` names the engine, `roles:` describes each worker role, and `services:` covers everything launched next to the workers.
Command-line tool for distributed LLM inference benchmarks on SLURM clusters using ATOM, TensorRT LLM, SGLang and vLLM. Replace complex shell scripts and 50+ CLI flags with a declarative `schema: 2` YAML recipe: `engine:` names the engine, `roles:` describes each worker role, and `services:` covers everything launched next to the workers.

## Quick Start

Expand Down
19 changes: 19 additions & 0 deletions docs/config-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ This page is the prose guide: what each block means, how the pieces interact, an

## Overview

### ATOM direct serving and AToMesh

For one aggregate worker, use `engine: atom` with `frontend.type: atom` and
`frontend.enable_multiple_frontends: false`. The ATOM worker binds the public
port directly; no router container or AToMesh installation is needed. Readiness
requires `/health` to succeed and `/v1/models` to list a model. See the
[direct ATOM recipe](../examples/atom/direct.yaml).

Use `engine: atom` with `frontend.type: atomesh` to launch native
`atom.entrypoints.openai_server` workers and the official AToMesh router. Both
aggregate workers and prefill/decode topologies use static HTTP endpoints;
disaggregated workers receive topology-owned Mooncake handshake ports.

Engine flags belong under `roles.prefill.args`, `roles.decode.args`, or
`roles.agg.args` (schema v2).
srt-slurm owns the model path, HTTP port, tensor parallel size, and KV-transfer
contract, so recipes cannot override those arguments. See the complete
[ATOM/AToMesh recipe](../examples/atom/atomesh-disagg.yaml).

```yaml
schema: 2 # Required: recipe layout version
name: "my-benchmark" # Required: job name
Expand Down
16 changes: 14 additions & 2 deletions docs/schema-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Top-level keys of a recipe YAML.
| `name` | str | required | |
| `model` | [ModelConfig](#modelconfig) | required | |
| `resources` | [ResourceConfig](#resourceconfig) | required | |
| `engine` | str \| mapping | required | The engine type (`sglang`, `trtllm`, `vllm`, `mocker`) as a string, or a mapping with `type` plus the engine-wide knobs listed under [Engine types](#engine-types). |
| `engine` | str \| mapping | required | The engine type (`atom`, `sglang`, `trtllm`, `vllm`, `mocker`) as a string, or a mapping with `type` plus the engine-wide knobs listed under [Engine types](#engine-types). |
| `roles` | mapping of role -> [Role](#roles) | required | One block per worker role (`prefill`, `decode`, `agg`): topology, env, and engine args. |
| `schema` | int | `2` | Recipe schema version. Write `schema: 2` for this layout. |
| `slurm` | [SlurmConfig](#slurmconfig) | `SlurmConfig()` | |
Expand Down Expand Up @@ -44,7 +44,7 @@ Three vocabularies are specific to the 2.0 layout. They are normalized into the

### engine

`engine: <type>` or `engine: {type: <type>, ...}`. `type` is one of `sglang`, `trtllm`, `vllm`, `mocker`; the remaining keys are that engine's knobs, listed under [Engine types](#engine-types).
`engine: <type>` or `engine: {type: <type>, ...}`. `type` is one of `atom`, `sglang`, `trtllm`, `vllm`, `mocker`; the remaining keys are that engine's knobs, listed under [Engine types](#engine-types).

### roles

Expand Down Expand Up @@ -573,6 +573,18 @@ Ready when the service's log file contains a line matching the regular expressio

`engine.type` selects one of the following; the remaining `engine` keys are that type's knobs.

### AtomProtocol

`engine.type: atom`

Launch ``atom.entrypoints.openai_server`` on ROCm workers.

| Key | Type | Default | Description |
|---|---|---|---|
| `type` | one of `'atom'` | `'atom'` | |
| `connector` | one of `'mooncake'` | `'mooncake'` | |
| `mooncake_protocol` | one of `'rdma'`, `'tcp'` \| None | `None` | |

### SGLangProtocol

`engine.type: sglang`
Expand Down
15 changes: 9 additions & 6 deletions docs/vllm-router.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ roles:
### Node-local data parallelism

For DEP8 on two four-GPU nodes, upstream srt-slurm creates one hybrid-LB
`vllm serve` process on each node. Router receives both base URLs and srtctl
adds `--intra-node-data-parallel-size 4`, exposing all eight DP ranks.
`vllm serve` process on each node. Router receives both base URLs as two
node-local pools. srtctl does not apply `--intra-node-data-parallel-size` to
this multi-node endpoint because the second pool owns global ranks 4 through
7; vLLM's node-local hybrid load balancer selects among those ranks.

```yaml
resources:
Expand Down Expand Up @@ -137,10 +139,11 @@ roles:
data-parallel-size: 4
```

Router has one global `--intra-node-data-parallel-size`, so every advertised
P/D base must represent the same number of local DP ranks. srtctl derives and
validates that value; do not set it manually unless it exactly matches the
allocated topology.
Router has one global `--intra-node-data-parallel-size`, so srtctl uses it only
when every logical endpoint has one advertised base URL. Multi-node hybrid-LB
endpoints remain unexpanded node-local pools because each later pool starts at
a nonzero global DP rank. Do not set the option manually unless it exactly
matches the allocated topology.

### MoRI-IO discovery

Expand Down
6 changes: 6 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ for p in sorted(Path('examples').rglob('*.yaml')):
print(validate_config_file(p) or f'ok {p}')
"
```

### ATOM and AToMesh

[`atom/atomesh-disagg.yaml`](atom/atomesh-disagg.yaml) launches native ATOM prefill
and decode workers with the AToMesh router. Each logical worker fits on one node;
the cluster configuration selects ROCm device visibility.
32 changes: 32 additions & 0 deletions examples/atom/atomesh-disagg.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Native ATOM prefill/decode on separate Slurm nodes behind AToMesh.
# Configure visible_devices_env: ROCR_VISIBLE_DEVICES in the cluster srtslurm.yaml.
# The container must include both atom.entrypoints.openai_server and atomesh.
schema: 2
name: qwen3-0.6b-atomesh-disagg
model:
path: hf:Qwen/Qwen3-0.6B
container: rocm/atom:latest
precision: bf16
resources:
gpu_type: mi300x
gpus_per_node: 8
engine:
type: atom
mooncake_protocol: tcp
frontend:
type: atomesh
enable_multiple_frontends: false
roles:
prefill:
nodes: 1
workers: 1
gpus: 1
decode:
nodes: 1
workers: 1
gpus: 1
benchmark:
type: sa-bench
isl: 128
osl: 128
concurrencies: "4x8"
25 changes: 25 additions & 0 deletions examples/atom/direct.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# One ATOM aggregate worker owns the public endpoint; no router is launched.
# Configure visible_devices_env: ROCR_VISIBLE_DEVICES in srtslurm.yaml.
schema: 2
name: qwen3-0.6b-atom-direct
model:
path: hf:Qwen/Qwen3-0.6B
container: rocm/atom:latest
precision: bf16
resources:
gpu_type: mi300x
gpus_per_node: 8
engine: atom
frontend:
type: atom
enable_multiple_frontends: false
roles:
agg:
nodes: 1
workers: 1
gpus: 1
benchmark:
type: sa-bench
isl: 128
osl: 128
concurrencies: "4"
6 changes: 5 additions & 1 deletion src/srtctl/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@
- TRTLLM: TensorRT-LLM backend with prefill/decode disaggregation
"""

from .atom import AtomProtocol, AtomServerConfig
from .base import BackendProtocol, BackendType, SrunConfig
from .mocker import MockerProtocol, MockerServerConfig
from .sglang import MooncakeKVStoreConfig, SGLangProtocol, SGLangServerConfig
from .trtllm import TRTLLMProtocol, TRTLLMServerConfig
from .vllm import VLLMFailoverConfig, VLLMMooncakeKVStoreConfig, VLLMProtocol, VLLMServerConfig

# Union type for all backend configs
BackendConfig = SGLangProtocol | TRTLLMProtocol | VLLMProtocol | MockerProtocol
BackendConfig = AtomProtocol | SGLangProtocol | TRTLLMProtocol | VLLMProtocol | MockerProtocol

__all__ = [
# ATOM
"AtomProtocol",
"AtomServerConfig",
"BackendConfig",
# Base types
"BackendProtocol",
Expand Down
Loading
Loading