Repository navigation
Multinode vLLM in one srun step, without Ray (#173) - #177
Open
dadamsncsa wants to merge 8 commits into
Open
dadamsncsa wants to merge 8 commits into
dadamsncsa wants to merge 8 commits into
Conversation
vec-inf 0.9.0 launches num_nodes > 1 vLLM as a Ray cluster in N+1 srun steps. On DeltaAI each step gets its own Slingshot VNI, so the ranks cannot reach each other over CXI. For multinode vLLM only, LLMHub now builds MultinodeLauncher, a vec-inf ModelLauncher whose generator replaces the Ray branch. The job runs one srun step with one task per node and --kill-on-bad-exit=1. A rank script, written into the job directory, derives the node's hsn<digits> address, waits on a barrier, and execs the same container vec-inf would. Rank 0 runs vllm serve with the API; the other ranks run it --headless. They join through vLLM's --nnodes/--node-rank/--master-addr/--master-port with the mp executor. vLLM runs under `env -u FI_LOG_LEVEL`, so the image's libfabric warnings cannot make vec-inf report a serving job as FAILED. Single-node launches, and anything that is not vLLM, go to vec-inf unchanged. The route is chosen on vec-inf's resolved params, so the catalog's node count counts. The adapter refuses a multinode launch on any vec-inf other than 0.9.0. Contract tests T1-T5 cover the version guard, single-node byte identity over the catalog, the job's shape, the rank script run with stubbed tools, and the vec-inf names it depends on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
Drop the heredoc-delimiter guard (no generated line can equal it), inline the job-directory helper, and leave the multinode check to the generator, which refuses before sbatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
- Clear the rendezvous directory before srun: a requeued job keeps its id, and stale rank files would satisfy the barrier at once. - Decide the NCCL debug file on the rank, so NCCL_DEBUG reaching the container through APPTAINERENV_* is caught too, not only the job env. - Time the barrier by the wall clock, not by loop iterations. - Document that a non-container multinode launch is refused, and that the rank's --env flags rely on llm_inference's one-flag-per-variable patch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
… fixes Behaviour change: every multinode launch now records NCCL INFO for INIT and NET, written to one file per process in the job directory's nccl-debug/ and never to stderr. That is how a multinode job shows which transport each rank chose (provider, NIC, GDR). It applies unless the job env or the host sets a level, and a NCCL_DEBUG_FILE given by either is kept. From the fresh reader: - A rank whose srun step has no CUDA_VISIBLE_DEVICES fails with a reason, not a bash "unbound variable". - A job env that sets VLLM_HOST_IP, NCCL_SOCKET_IFNAME or GLOO_SOCKET_IFNAME is refused: each rank derives them, and --env would silently win. - The master-port probe's stderr stays out of the job's .err. - T5 also names ModelLauncher.slurm_script_path, which the override sets and launch() reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
…check - The job env's VLLM_HOST_IP, NCCL_SOCKET_IFNAME, GLOO_SOCKET_IFNAME and VLLM_PORT are left out of a multinode job's container env and noted in the job log, not refused: each rank sets its own, and a deployment may set them for single-node jobs. - With no NCCL level anywhere, the level is INFO even when a debug file is named. - A rank without CUDA_VISIBLE_DEVICES fails before the barrier, so no other rank waits on it; a rank that cannot write its barrier marker says so. - The master-port probe's stderr is visible again: a failing ss should leave a trace. - T4 runs the rank script for each NCCL case, job env and host alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
- The job JSON records the env the job was given, without the per-rank keys left out of it. - A missing ss is reported on stdout; ss's own stderr stays out of the .err that vec-inf scans for fatal patterns. - A container module other than apptainer is refused: the rank script passes its values as APPTAINERENV_* and binds through APPTAINER_BINDPATH. - T3 and T4 also cover a job env that sets both the NCCL level and file; T5 names CONTAINER_MODULE_NAME. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
…ted in full Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #173. Part of #60. Upstream: VectorInstitute/vector-inference#333.
Why
vec-inf 0.9.0 launches a
num_nodes > 1vLLM job as a Ray cluster: onesrunstep for the head, one per worker, andvllm serveoutside all of them. On DeltaAI that fails four ways, each found by fixing the one before it:hostname --ip-addressreturns 18 addresses, link-local IPv6 first (3286271).--containallPID namespace hides the head's raylet from the driver (3286313).On Delta, (2) fails too (21500825), so the Ray path serves on neither cluster, and nothing that works is replaced here.
What
For multinode vLLM only, the call site (
llm_inference.py) now buildsMultinodeLauncher, aModelLaunchersubclass whose generator replaces vec-inf's Ray branch (app/utils/vec_inf_multinode.py):srunspanning every node, one task per node,--kill-on-bad-exit=1.hsn<digits>address (never DNS);VLLM_HOST_IP,NCCL_SOCKET_IFNAMEandGLOO_SOCKET_IFNAMEfor that rank;vllm servewith the API; the other ranks run--headless. They join through vLLM's own--nnodes/--node-rank/--master-addr/--master-portwith thempexecutor.env -u FI_LOG_LEVEL. The image bakeswarn, and libfabric's benignFailed to …lines made vec-inf mark a serving 2-node job FAILED (3533520: 1,284 lines).client.launch_modelunchanged. Status, shutdown, the job JSON and the log layout are all vec-inf's.The adapter is temporary. The same launcher is proposed upstream (vector-inference#333), and the adapter is deleted at the pin bump once a vec-inf release ships it. Until then, T1 keeps a bump from silently routing multinode back to Ray, and T5 names every vec-inf member the adapter depends on.
Behaviour changes for multinode jobs:
nccl-debug/<host>.<pid>in the job directory, never to stderr. This records each rank's transport. It applies unless the job env or the host sets a level, and a file they name is kept.VLLM_HOST_IP,NCCL_SOCKET_IFNAME,GLOO_SOCKET_IFNAMEandVLLM_PORTfrom the deployment or request env are left out of the containers' env, and the job log says so. Each rank sets its own; as--envflags they would override that on every rank.Scope of the evidence: hardware-tested on DeltaAI only. The adapter also takes Delta's multinode vLLM entries: six at 2 nodes, and Llama-3.1-405B at 8. Delta's 2-node run is milestone 2 of #60. Until then a Delta multinode launch uses code that has run only on GH200, in place of a Ray path that fails there.
Contract tests (
tests/test_multinode_t*.py): 84 passed at 93aeeebcheck_vec_inf_version()deleted → 2 failedsrun,--kill-on-bad-exit=1, noray,mp, native flags,--headless,env -u FI_LOG_LEVEL, rank script in the job dir, deployment env on every rank, NCCL debug never on stderr--kill-on-bad-exit=1dropped → 1 failedip/hostname/apptainer: rank → flags, master fromhsn<digits>, refusal without a fabric IPv4, barrier timeout reported FAILED by vec-inf's own scanhsnmatched by prefix → 15 failed_generate_launch_cmd, as a vec-inf bump would → 1 failedFull suite: 271 passed, 1 skipped. black, isort and flake8 at CI's pins: clean. Removal records:
builds/llmhub/multinode-build-2026-11/test-results/deltaai/pr1-gate/in llm-service-software.Removal records (93aeeeb)
T1 @ 93aeeeb: MultinodeLauncher no longer checks the vec-inf version
T2-routing @ 93aeeeb: the dispatch sends every launch to the adapter, single-node included
T2-no-adapter @ 93aeeeb: the dispatch sends every launch to stock vec-inf, multinode included
T3 @ 93aeeeb: srun loses --kill-on-bad-exit=1
T4 @ 93aeeeb: fabric interfaces matched by prefix instead of exact hsn
T5 @ 93aeeeb: no code change: vec-inf renames SlurmScriptGenerator._generate_launch_cmd (pytest plugin seam_renamed.py)
On hardware (DeltaAI, 2 × GH200, Qwen2.5-7B-Instruct TP=4 PP=2)
Submitted through
LLMInferenceDirectClient.launch_modelfrom a dev session; Slurm's stored batch script is byte-identical to the generated one.Job 3541300, at this PR's last code commit (93aeeeb), passed 14/14 on gh[102,127]:
RUNNING; LLMHub statusREADY.Worker_PP0_TP0..3andWorker_PP1_TP0..3.Selected provider is cxion all 8 ranks;via NET/Libfabric/0..3/GDRDMA.libfabric:lines before ready (3533520, with the image's level, had 1,284). The pair came from the run's ownVEC_INF_ENV: the kit adds it to every job in infra/delta: multinode config, DeltaAI catalog, launch-test --nodes (#174) #178, and this PR alone doesn't.scancel, CANCELLED. Both nodes were released: another user's jobs started on gh102 39 s and on gh127 98 s after this one ended (sacct).Job 3541160, at 8b2d695, passed the same 14 checks before the last review fixes. Evidence:
builds/llmhub/multinode-build-2026-11/in llm-service-software.CI on this PR, at e0be734: backend 271 passed, 1 skipped; changelog and every other check pass (run 42292508778, backend job 128149342014).
Not in this PR
launch-test --nodes(Kit: multinode config for Delta and DeltaAI (fabric env, DeltaAI catalog, 2-node launch-test) #174, stacked on this branch).🤖 Generated with Claude Code
https://claude.ai/code/session_01HnSD7f83LXZjJVqJ3RLAAD