Skip to content

feat: [AMD Support via SemiAnalysis][1/4] AMD hardware and required cluster runtime - #431

Merged
ishandhanani merged 1 commit into
NVIDIA:mainfrom
SemiAnalysisAI:upstream/amd-runtime
Sep 23, 2026
Merged

ishandhanani merged 1 commit into
NVIDIA:mainfrom
SemiAnalysisAI:upstream/amd-runtime

Conversation

@cquil11

@cquil11 cquil11 commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Scope

Enable AMD hardware and make native srt-slurm jobs work on our Slurm clusters. This combines the former hardware and required-runtime PRs; functionality needed to launch the deployment is no longer hidden in a separate prerequisite layer.

  • Cluster configuration owns GPU visibility, GPU-exporter defaults, network interface, mounts, model paths, and Slurm options. NVIDIA defaults are preserved. There is no vendor enum, accelerator dispatch module, or new GRES convention.
  • Resolve GPU-exporter defaults once at config load, with explicit recipe overrides taking precedence.
  • Apply the configured visibility variable to allocated GPU subsets; preserve full-node and backend device-binding behavior. vLLM has one set_visible_devices option.
  • Respect the configured interface for control-plane and SGLang worker addresses, and forward recipe Slurm options to native routers.
  • Write worker configuration inside the existing container log mount.
  • Static routers that need ready HTTP workers opt into the existing health polling before launch. SGLang enables it so slow model loading cannot exhaust initial registration. Worker URLs are resolved once and reused.

Upstream scheduling escape hatches handle GRES: use_gpus_per_node_directive: false and default_sbatch_directives: {gres: "gpu:8"}. Cluster host setup uses the existing lifecycle. No engine patch, new deployment system, automatic network fallback reordering, or Dynamo installation workaround is added.

Review map

  • core/schema.py, core/config.py, core/runtime.py: cluster defaults and runtime context.
  • cli/mixins/worker_stage.py, backends/vllm.py: GPU binding and container-visible config.
  • frontends/, services/implicit.py: configured addresses, Slurm options, and native startup.
  • Example profile, dry-run, docs, and focused behavioral tests accompany those changes.

Optional deployment fork #16, Dynamo installation fork #15, and Infera fork #3 are outside this validation.

Review the stack

The upstream PRs target NVIDIA main and are manually stacked, so later upstream diffs include preceding layers. The downstream fork PRs form an actual branch-based stack (main → #1 → #11 → #7 → #14); each fork PR's Files changed tab isolates its layer for easier review.

Merge in that order, then rebase the remaining layers. ATOM uses Mooncake, not MoRI; its stack position is review ordering, not an engine dependency. The core runtime does not require the observation layer, but the InferenceX launcher uses its srtctl wait command.

E2E validation

  • AMD hardware/runtime #431: MI300X aggregate smoke — passed; Qwen3-0.6B, 16/16 requests. Tests a second AMD generation/cluster and direct SGLang serving without disaggregation or a router.
  • AMD hardware/runtime #431: MI355X DSpark SGLang/MoRI AgentX c4 — passed; 190 measured requests, zero errors, one end-of-window cancellation. Tests separate prefill/decode nodes, native SGLang routing, and MoRI transfer.
  • AMD hardware/runtime #431: R1 2P1D c8 — passed; 80/80 requests. Tests registration and routing across two prefill replicas and one decode replica with SGLang/MoRI.
  • AMD hardware/runtime #431: R1 1P2D c8 — passed; 80/80 requests. Tests one prefill replica and two TP8 decode replicas with SGLang/MoRI; both decode endpoints served requests, including the reprovisioned g50 node.
  • AMD hardware/runtime #431: DSpark UMBP c128 smoke — passed; five-minute measurement, 795 successful requests, zero request errors, 12 cutoff cancellations (cancellation grace expired). Tests managed UMBP startup/teardown, GPU IPC registration, DP-aware routing across eight prefill and eight decode ranks, and host-cache reuse. Uses a 64 GiB smoke cache; does not validate the production 1.5 TB cache setting.
  • vLLM/MoRI #432: Colocated MiniMax M3 c4 — passed; 40/40 requests. Tests TP4 prefill and TP4 decode on one node, GPU separation, distinct listener ports, and vLLM routing with MoRI-IO.
  • ATOM/AToMesh #433: DeepSeek V4 ATOM + AToMesh/Mooncake c4 — passed; 40/40 requests. Tests the ATOM engine, AToMesh router, and Mooncake KV transfer.
  • All runs above use fork stack 7a7ca652 and exercise job observation #476. These are functional serving smoke tests, not accuracy, power-telemetry, or full-sweep validation.

@ishandhanani ishandhanani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The net diff is small (9 files, ~180 lines) and the scope discipline is good: GPU scheduling stays on use_gpus_per_node_directive / default_sbatch_directives, and the sidecar special case in worker_stage.py was only moved, not added. The concern is that the design center, accelerator_vendor, is a closed enum whose two effects (pick a visibility env var, suppress the DCGM default) are both hardcoded in Python, when each already has a cluster-config pattern in this repo. srtslurm is meant to be portable across clusters by editing srtslurm.yaml, not by adding vendor branches. Inline comments have the specifics.

Suggested shape instead of the enum:

  • visible_devices_env: str = "CUDA_VISIBLE_DEVICES" on ClusterConfig, read once into RuntimeContext, same as network_interface. An AMD profile sets ROCR_VISIBLE_DEVICES. No accelerator.py, no ValueError path, no Literal to keep in sync across three files.
  • default_gpu_exporter: TelemetryExporterConfig | None on ClusterConfig, following default_health_check / default_host_setup. An AMD profile points it at AMD's device-metrics-exporter once; NVIDIA clusters keep the built-in DCGM default; observability.tachometer.dcgm_exporter in a recipe still wins. The schema property then stops reading global config.

Not in the diff, but worth noting for a PR titled base AMD support:

  • src/srtctl/core/fingerprint.py:330 and :917 shell out to nvidia-smi; :353-363 call nvcc and torch.cuda.nccl.version(). On AMD the fingerprint and lockfile silently record GPU, CUDA, and NCCL as unavailable.
  • srtslurm.yaml.example is not updated here (#432 adds the line).
  • The CLAUDE.md hunk is a trailing-newline removal only.

Housekeeping:

  • The first commit touched ~30 files and the second reverted nearly all of them. Please squash so the history matches what lands.
  • CI conventional-title is red on the [AMD Support][1/3] prefix.

Comment thread src/srtctl/core/accelerator.py Outdated
Comment thread src/srtctl/core/accelerator.py Outdated
Comment thread src/srtctl/core/schema.py Outdated
Comment thread src/srtctl/core/schema.py Outdated
Comment thread src/srtctl/core/runtime.py Outdated
Comment thread src/srtctl/backends/vllm.py Outdated
Comment thread tests/test_accelerator.py Outdated
@ishandhanani ishandhanani changed the title [AMD Support][1/3] Base AMD runtime support feat(amd support): PR 1/3 submitted by Semianalysis on behalf of AMD to support their stack in srt-slurm Sep 15, 2026
@cquil11
cquil11 force-pushed the upstream/amd-runtime branch from bb1efc3 to dd26457 Compare September 17, 2026 22:24
@cquil11 cquil11 changed the title feat(amd support): PR 1/3 submitted by Semianalysis on behalf of AMD to support their stack in srt-slurm [AMD Support][1/4] AMD hardware and required cluster runtime Sep 17, 2026
@cquil11 cquil11 changed the title [AMD Support][1/4] AMD hardware and required cluster runtime feat: [AMD Support][1/4] AMD hardware and required cluster runtime Sep 17, 2026
@cquil11 cquil11 changed the title feat: [AMD Support][1/4] AMD hardware and required cluster runtime feat: [AMD Support via SemiAnalysis][1/4] AMD hardware and required cluster runtime Sep 17, 2026
@cquil11
cquil11 force-pushed the upstream/amd-runtime branch 3 times, most recently from a9ebc67 to d804d1c Compare September 18, 2026 21:36

@ishandhanani ishandhanani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bet

@ishandhanani

Copy link
Copy Markdown
Collaborator

Merged main into this branch (5b61ec6) so it lands cleanly on top of #486, #487, and #489. Three files conflicted and were resolved by hand; the rest of the branch is unchanged.

What moved, and why:

  • should_set_visible_devices() is now a BackendProtocol member. refactor: ports through NodePortAllocator, backends through BackendProtocol #489 made every backend question go through the protocol (no getattr(backend, ...) in src/, enforced by tests/test_backend_protocol.py). The rename from this PR stays; SGLang, TRT-LLM, and the mocker answer True, vLLM answers from set_visible_devices.
  • _visible_device_environment reads self.backend.should_set_visible_devices() and self.config.dynamo.sidecar directly. Same behavior as before, without the getattr defaults. Both worker launch paths build the mask from runtime.visible_devices_env through this one helper.
  • Static router pre-start probe reads config.health_check and passes runtime.srun_options directly. The MockConfig test fake gained health_check: None, which is how tests opt out of the probe; the probe itself is covered by test_sglang_router_starts_only_after_workers_are_healthy.
  • SGLangRouterFrontend.resolve_worker_host passes the network interface. The base class already did after refactor(frontends): the frontend class owns registration, validation, worker shape, and endpoints #487; the override now matches.

Validation on the merged head: full suite 3034 passed on Python 3.13 and 3.10, make lint scope clean, schema docs in sync, and srtctl dry-run on all 26 example recipes differs from main only by the GPU subset visibility variable line this PR adds.

ishandhanani added a commit to SemiAnalysisAI/srt-slurm that referenced this pull request Sep 22, 2026
…M Router

Merge of upstream/amd-runtime (main + NVIDIA#431) into this branch, with the
MoRI-IO integration rebuilt on the seams main now has instead of beside
them. What the feature does is unchanged: engine.connector: moriio runs a
ROCm prefill/decode pair over AMD's MoRI-IO connector with the vLLM Router
in ZMQ discovery mode.

Backend (backends/vllm.py)
- The connector table rows are KVConnector(kv_connector, kv_role,
  module_path, discovery). "moriio" is a row with discovery=True and a
  mode-dependent kv_role; no connector name is compared in a branch.
- connector_for_mode(mode) is the one resolver for engine.connector and the
  roles.<role>.args.connector override; kv_connector_for_mode and
  discovers_workers are built on it. All three command paths use it.
- kv_transfer_config(mode, process, runtime) builds --kv-transfer-config.
  For a discovery connector the extra config carries proxy_ip (head node),
  proxy_ping_port, http_port, host_ip (the worker's own routable IP),
  handshake_port and notify_port (the keys moriio_common.py reads,
  vllm-project/vllm 9679173788), read_mode. Upstream's defaults of 6301 and
  61005 for every worker collide on colocated P/D; a worker built without
  its listeners is refused rather than given them.
- The allocator hands a discovery worker MORIIO_HANDSHAKE_PORTS and a
  MORIIO_NOTIFY_PORTS block of one port per local rank (upstream adds the
  DP and TP rank to the notify base) and no VLLM_PORT scan range, since
  MoRI-IO opens its other listeners inside TP children that inherit it.
  Process gains moriio_handshake_port and moriio_notify_port.

Frontend (frontends/vllm_router.py, static_router.py)
- StaticRouterFrontend.discovers_workers(backend) decides whether the P/D
  URLs go on the command line; build_router_command takes the backend.
- VLLMRouterFrontend adds --kv-connector <name> --vllm-discovery-address
  0.0.0.0:36367 (RouterArgs in vllm-project/router), advertises no NIXL
  bootstrap port, and validates the discovery rules: both roles on the
  connector, a P/D topology, one router on the head node.
- Readiness is the Router's own /health, 503 until a prefill and a decode
  registered (vllm-project/router 43140bc8e2, VllmPDRouter::health), through
  probe_ready. probe_ready now receives the recipe on every frontend, and
  wait_for_model passes it; the completions POST in core/health.py is gone.
- The schema refuses a discovery connector with any other frontend.

Docs, example, tests
- docs/vllm-router.md gains a MoRI-IO discovery section with the contract
  table; config-reference.md points at it (the duplicate section is gone);
  ports tables in CLAUDE.md and docs/architecture.md list the two kinds.
- examples/vllm/vllm-router-moriio-disagg.yaml, colocated P/D, is in the
  examples matrix and in every example-driven test.
- Tests cover the worker JSON against the realized topology, the refusal
  without listeners, colocated listener allocation, the role override, the
  discovery command, the bootstrap port, the /health probe, and the recipe
  rules.

Signed-off-by: Ishan Dhanani <idhanani@nvidia.com>
@cquil11
cquil11 force-pushed the upstream/amd-runtime branch from 1086678 to 4b5f7e9 Compare September 22, 2026 18:13
@cquil11

cquil11 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Passed: MI355X DeepSeek V4 DSpark smoke, SGLang + MoRI 1P1D TP4, c4, on fork stack 7a7ca652. 190 measured requests succeeded, zero request errors; one end-of-window cancellation. Throughput smoke only, no accuracy eval.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@9dbbf43). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #431   +/-   ##
=======================================
  Coverage        ?   82.06%           
=======================================
  Files           ?      139           
  Lines           ?    20623           
  Branches        ?        0           
=======================================
  Hits            ?    16925           
  Misses          ?     3698           
  Partials        ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ishandhanani
ishandhanani merged commit 2917b06 into NVIDIA:main Sep 23, 2026
15 checks passed
ishandhanani added a commit to SemiAnalysisAI/srt-slurm that referenced this pull request Sep 23, 2026
Signed-off-by: Ishan Dhanani <idhanani@nvidia.com>

NVIDIA#431 landed on main as the squash 2917b06, so the AMD runtime commit on this branch is now also in main; the merge keeps one copy and the diff against main is only the MoRI-IO layer. Also picks up the TRT-LLM served-model-name forward (NVIDIA#495) and its VRNVL72 NUMA default (NVIDIA#493). docs/schema-reference.md was the only conflict and is regenerated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants