feat: add phase timing markers to ray.sub for diagnosing startup stalls#3209
Merged
Conversation
ray.sub runs several blocking calls that reach the SLURM controller
(sinfo/scontrol/srun) and imports a multi-GB container image before Ray
comes up. When any of those stall (an overloaded controller, a slow
prolog, contended shared storage), the bare `set -x` trace has no
timestamps, so it is impossible to tell from the logs where the
wall-clock actually went -- we recently had a run lose ~20 min before
training started with no way to attribute it.
Add a `log_phase` helper that stamps an ISO wall-clock time plus
seconds-since-job-start, and call it at the key phase boundaries:
- script entry (compare to SLURM StartTime to measure the pre-script
prolog/allocation overhead that ray.sub cannot see)
- GRES detection (sinfo controller RPC)
- CPU auto-detection (scontrol controller RPC)
- node hostname -> IP resolution (DNS)
- Ray head/worker srun launch (enroot image import)
- Ray head GCS up (STARTED_RAY_HEAD observed)
Also add runtime timestamps to the head container's worker-join poll
("Number of actors online" / "All workers connected") and the worker
container's per-attempt start line, so a slow worker registration or a
slow container import is localizable too.
Markers are kept coarse (phase boundaries, not per-command) so the trace
stays readable. Subtract two adjacent markers' elapsed counters to get a
phase's duration.
Signed-off-by: Terry Kong <terryk@nvidia.com>
Extends the submit-side [NRL_PHASE] markers into the head and worker
containers so a stall *after* the srun launch (enroot image import, ray
head bringup, worker registration) is localizable too -- not just the
pre-Ray submit-side phases.
Each container defines a small log_phase that reuses the propagated
NRL_JOB_START_EPOCH, so the elapsed counters line up with the submit-side
markers into one end-to-end timeline. Markers added:
head: container started (import complete) / starting ray head /
GCS listening (STARTED_RAY_HEAD) / cluster ready, launching driver
worker: container started (import complete) / head GCS ready, connecting
Validated on a live 2-node run: the markers cleanly separate prolog
(StartTime -> entry, 32s) from enroot image import (srun launch -> head
container started, ~65s) -- exactly the ambiguity that was unresolvable
from a bare set -x trace.
Signed-off-by: Terry Kong <terryk@nvidia.com>
…gaps - Add a trap (EXIT/TERM/HUP/INT) that logs a final [NRL_PHASE] marker on script exit, so epilog/teardown = SLURM EndTime - last marker, symmetric to prolog = first marker - StartTime. It traps signals (not just EXIT) so a time-limit kill / scancel is stamped too; verified on a live 2-node cancel that the marker fires under SIGTERM (KillWait=120s grace), epilog ~4s. - Timestamp the previously-unmarked paths: interactive submit-side worker wait + attach-helper scontrol RPC, the head sandbox-readiness poll, and the shared-FS log-dir setup. - Tighten every marker message to a terse declarative statement; the rationale (controller RPC, image import, contended storage, ...) lives in the surrounding code comments, not the runtime log line. Signed-off-by: Terry Kong <terryk@nvidia.com>
Collaborator
Author
|
/ok to test 21d2523 |
Signed-off-by: Terry Kong <terryk@nvidia.com>
Collaborator
Author
|
/ok to test 8229e93 |
terrykong
enabled auto-merge (squash)
July 15, 2026 06:51
yuki-97
approved these changes
Jul 15, 2026
terrykong
added a commit
that referenced
this pull request
Jul 15, 2026
… diagnosing startup stalls (#3214) Signed-off-by: Terry Kong <terryk@nvidia.com> Co-authored-by: Terry Kong <terryk@nvidia.com>
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.
What does this PR do ?
Adds coarse, timestamped phase markers to
ray.subso that startup/teardown stalls (before Ray, and after the driver) can be localized from the job log.Motivation: a recent run burned ~20 min of a fixed wall-clock budget before the training driver even started, and it was impossible to tell from the log where that time went —
ray.subruns withset -x, but the xtrace has no timestamps, and the slow region was a mix of pre-script SLURM launch (prolog/allocation), controller RPCs (sinfo/scontrol), DNS resolution, and container image import. None of those were individually attributable after the fact.This adds a
log_phasehelper that stamps an ISO wall-clock time plus seconds-since-job-start, called at the key phase boundaries on the submit host and inside the head/worker containers. Subtract two adjacent markers' elapsed counters to get that phase's duration. The timeline is bookended so the two thingsray.subcan't see itself are still measurable:first marker − SLURM StartTimeSLURM EndTime − last marker(via atrap … EXIT TERM HUP INT, so a time-limit kill /scancelis stamped too — a bareEXITtrap doesn't fire on an uncaught signal)Markers — submit host:
ray.sub started· shared-FS log dir ready · GRES (sinfo) · CPU (scontrol show node) · node→IP resolution ·srunlaunch · Ray head GCS up · attach-helper (scontrol show job, interactive path) ·ray.sub exiting(trap).Inside the containers (reuse the propagated
NRL_JOB_START_EPOCHso all counters share one timeline): head — container started / starting ray head / GCS listening / cluster ready, launching driver / worker-join poll / sandbox-readiness poll. worker — container started / connecting / per-attempt ray start.Kept deliberately coarse (phase boundaries, not per-command); the rationale (which op is a controller RPC, where image import happens, etc.) lives in code comments, not the runtime log lines.
Issues
None.
Usage
ray.subruns underset -x, so grep the timestamped form ([NRL_PHASE][2…) to skip the xtrace/definition lines:Example (from live 2-node validation runs)
SLURM
StartTimewas…:12:39. Merged submit + head + worker markers (node names genericized):Reading phase durations straight off the counters:
StartTime+2s−+0s+67s(head started) −+2s(srun launch)+83s−+70s+96s−+84sEndTime− last markerscanceltest)The point: in the incident that motivated this, a ~20-min gap was unattributable. It now lands unambiguously as either a large
StartTime → startedgap (prolog), or a largesrun launch → container startedgap (image import), or a largeexiting → EndTimegap (epilog) — separated instead of hidden in an untimestamped trace.Before your PR is "Ready for review"
Pre checks:
bash -nvalidated the outer script + the heredoc-generated head/worker scripts, the exit-trap was unit-tested to fire on SIGTERM, and the whole thing was exercised end-to-end on live 2-node runs including ascancelto confirm the epilog marker)Additional Information
ray.subchanges; purely additiveecho/log_phaselines plus a logging-only exit trap — no change to the launch path's behavior.log_phasereusesNRL_JOB_START_EPOCH; the container copies read it from the propagated env so all markers share one timeline.ray.subruns underset -x, each marker also appears once as a+ echo …xtrace line; grep the[NRL_PHASE][2…timestamped form to get just the markers.