Conversation
…n metrics Extends the /proc host sampler from orchestrator-node-only to every allocated node, and adds the scheduler-level fields needed to attribute host-CPU interference to a remedy from a single baseline run: - per-process run_delay_ns (/proc/pid/schedstat): cumulative run-queue wait — the direct contention signal that CPU pinning remedies - per-process nr_migrations (/proc/pid/sched): cross-core churn, near-zero when pinned - per-process affinity_ncpus (sched_getaffinity): direct pinning-state observable (144 = floating, 36 = pinned rank on GB200/GB300) - host procs_running/procs_blocked and a t_mono companion timestamp (cross-node wall clocks have been observed seconds apart) Collection: host_sampler.py gains a stdlib-only standalone CLI mode (one file per node: host_samples_<node>.jsonl); benchmark_stage launches it on all non-orchestrator nodes via one srun --overlap per het group, gated by the new observability.host_sampler_all_nodes knob (default true, follows observability.enabled). This closes the gaps where worker nodes had no per-process host telemetry and a dedicated frontend node had none at all. Ingest: host_series.json gains a per-node hosts map plus run_delay_ms_per_s / migrations_rate / affinity_ncpus / procs_runnable series; rate denominators prefer the monotonic clock so NTP steps can't skew them. docs/host-attribution-metrics.md documents the metric set and the pinning-vs-placement attribution logic. Teardown hardening from adversarial review: benchmark proc creation moved inside the try so sampler sruns can't leak when placement/launch raises; sampler teardown escalates via terminate_and_reap and logs early-exited samplers; the standalone mode exits nonzero if its sampler thread dies; the sampler never samples itself. Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…idation matrix Replaces the draft rubric with measured thresholds from 7 validation runs (2x baseline, 2x pinned, 3x dedicated-frontend at DSV4 c1010 on GB300): clean-node run-delay floor 0.00-0.01 ms/s; shared-node asymmetry 140-350x (persisting at 190x under pinning, collapsing to 1x in all three dedicated-frontend runs); affinity_ncpus as the direct pinning observable (full-width vs CPUs-per-GPU), unchanged by placement. Adds the operator three-step decision flow and expected-gain guidance (+4.0% pinning on 288-CPU nodes / +1.1% on 144-CPU; +0.5-0.85% placement). Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…ault The Prometheus surface Tachometer captures says nothing about the processes underneath it: Dynamo publishes no process_* or thread metrics and node_exporter only sees the machine. The AgentX/VR200 frontend spin (fastokens 0.3.1 sizing its BPE rayon pool to all 352 CPUs -> 352 idle workers burning ~110 cores) was invisible in every scraped family and was found with sacct plus an out-of-band per-thread /proc sampler. Add ncabatoff/process-exporter (pinned multi-arch image, port 9256) as a third built-in exporter, launched on every node that hosts a backend rank OR a frontend replica -- the frontend node is the one the per-node exporters skip when the frontend is head-placed or dedicated, and it is where frontend CPU pathologies live. Groups come from <log_dir>/process-exporter.yml written at launch (frontend, dynamo_trtllm/sglang/vllm handlers + ranks, the MPI launcher, the benchmark client, infra daemons; first match wins, no catch-all). -threads=true publishes per-thread-name CPU and thread counts, so a runaway pool shows up as a step in thread_count and a CPU cluster on one thread name. Endpoints are scraped unfiltered so groupname/threadname/mode labels pass through to the parquet and to server_metrics_export.jsonl unchanged. node_exporter additionally gets --collector.processes (host-wide thread total, process states, procs_running/blocked). An explicit process_exporter block overrides the image/port/command, and default_exporters: false still disables all built-ins. Dry-run lists the new exporter; docs/config-reference.md documents it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
The tachometer node_exporter launch enabled only cpu/infiniband/meminfo, and
the host sampler read /proc/stat + /proc/meminfo but no PSI. The result: none
of the scheduler-pressure signal the retired steady_probe.sh sampler carried
(PSI stall time, procs_running/blocked, context-switch and page-fault/reclaim
counters, per-NUMA free memory) was collected anywhere -- exactly the class of
signal that distinguishes a busy box from one whose work is blocked waiting.
Two complementary changes, both cheap procfs/sysfs reads with no measured
decode-latency cost (unlike dense NVML sampling):
- node_exporter (all worker nodes): add the stat, vmstat, pressure, and
meminfo_numa collectors. The vendored NodeExporterFilter passes the new
families through its default arm, so no scraper change is needed. Extracted
into tachometer_node_exporter_command_template() mirroring the DCGM template;
an explicit recipe node_exporter.command still wins.
- host_sampler (orchestrator/head node, which gets no exporter): add a
/proc/pressure/{cpu,memory,io} PSI read to each sample. This is that node's
only PSI source and covers the frontend node the exporters never reach.
Tests: node-exporter template asserts the four new collectors and
explicit-command override; host_sampler PSI parse + CONFIG_PSI-absent cases.
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…-setup binary The upstream ncabatoff/process-exporter image is FROM scratch: no shell, no /root. pyxis/enroot on hecate refuses to start it (`enroot-switchroot: failed to change directory: /root`, then `/bin/sh: No such file or directory` once the home is mounted), so the first run from this branch (hecate 565854) had to relaunch the exporter by hand as a bare binary. The exporter is a static Go executable that needs neither a container nor privileges, so ship it the way nats-server and etcd are shipped: `make setup ARCH=<compute_arch>` downloads the release tarball into configs/process-exporter and start_tachometer runs it under plain srun with host paths for the binary and its group file. - TelemetryExporterConfig.binary: host-native launch mode. Relative paths resolve against SRTCTL_SOURCE_DIR / the checkout root, where make setup installs host binaries; container_image is ignored. - DEFAULT_PROCESS_EXPORTER now points at configs/process-exporter with an empty container_image. Validation requires binary or container_image for every exporter, process_exporter included. - Missing binary (checkout whose make setup predates this) skips the process-exporter leg with a warning instead of failing the run; `srtctl apply` warns at submit time as well. - An explicit process_exporter.container_image with binary unset keeps the container launch (group file via the /logs mount). - Makefile setup step (PROCESS_EXPORTER_VERSION ?= 0.8.7), .gitignore, dry-run row shows "host binary configs/process-exporter :9256", docs/config-reference.md, tests for both launch modes, the skip path, binary resolution and validation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
# Conflicts: # src/srtctl/cli/mixins/telemetry_stage.py
…xporterFilter
Two node_exporter families enabled by the combined observability branch lost
their only distinguishing label in the vendored scraper filter, so every series
of the family collapsed into one metric name in the parquet:
- node_memory_numa_*{node="N"} (--collector.meminfo_numa, NVIDIA#415): the generic
`memory_` arm emitted the bare metric name, folding all NUMA nodes together.
Now `memory_numa_<x>{numa_node=N}`; host-wide meminfo stays label-free.
- node_processes_state{state="R"|"S"|"D"|...} and
node_processes_threads_state{thread_state=...} (--collector.processes, NVIDIA#413):
the default arm keeps only a fixed label whitelist that had neither key.
`state` and `thread_state` are added to the whitelist.
Label-free stat/vmstat/pressure families were already passed through unchanged;
a test pins that too.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…docs/comments for the collector union Post-merge fixups from the three-PR integration review: - benchmark_stage._start_remote_host_samplers hardcoded `--interval 2` (NVIDIA#356 predates b83dc4a, which made the in-process sampler follow observability.tachometer.collect_interval_ms). Derive the remote interval from the same knob, clamped to >= 1 s like HostSampler, so head-node and remote host_samples rows share one cadence. Test covers default, 2 s, 5 s, sub-second clamp and 1.5 s. - docs/config-reference.md node_exporter row lists the eight collectors of the union and the widened vmstat field filter (it still named NVIDIA#413's four). - telemetry_stage.py NODE_EXPORTER_COLLECTORS comment no longer claims "no scraper change is needed": the filter keeps numa_node / state / thread_state since the previous commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…urm) Launch every worker srun step through the nsight-slurm wrapper instead of prefixing the command with `nsys profile`, so one coordinator per job collects time-aligned per-rank Nsight Systems reports into a shared report workspace. Independent of `observability.enabled`. - schema: `ProfilingType.NSIGHT_SLURM`, fields `nsight_slurm_home`, `nsight_slurm_tool_path`, `nsight_slurm_profiling_mode` (at-launch | manual | cuda-api), `nsight_slurm_tool_options`, `nvtx_injection_path`; default tool options = the TRT-LLM profiling playbook set minus connector-owned flags. Validation: absolute home, known mode, connector-owned flags rejected, cuda-api requires the TRT-LLM backend (TLLM_PROFILE_START_STOP trigger). Worker env gets the iteration window plus TLLM_PROFILE_LOG_RANKS, DYN_ENABLE_RUST_NVTX and NVTX_INJECTION64_PATH. - slurm.start_srun_process: optional `srun_launcher` / `launcher_env`. With a launcher the native srun options are forwarded unchanged and terminated by `--`; `--export` is omitted (the wrapper appends its own `--export=ALL`) and the export vars ride in the wrapper's process env. - NsightSlurmStageMixin: idempotent `configure tool-path / tool-command / profiling-mode / tool-options / report-output`, `enable pyxis`, `coordinator start` before the first worker step; `coordinator stop --force` in sweep cleanup; all calls logged to <log_dir>/nsight-slurm.out with SLURM_SUBMIT_DIR redirected to the log dir. - worker_stage: both srun launch paths pick up the launcher kwargs. - docs/profiling.md: nsight-slurm section. Tests: tests/test_profiling_nsight_slurm.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…wrapper `srtctl dry-run` rendered nothing about `profiling`, although it changes how every worker step is launched (nsys prefix, or with `type: nsight-slurm` the wrapper `<home>/bin/nsight-slurm srun ... -- <cmd>` plus its pyxis mounts and --export=ALL). Add a Profiling panel: type, per-phase step windows, NVTX injection path, and for nsight-slurm the launcher, install root, tool-path, profiling-mode, effective tool-options and report-output. Tests in tests/test_dry_run.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…teral
The wrapper derives the coordinator address from SLURMD_NODENAME (or the fqdn),
so connectors resolve tcp://<head hostname>:<port> themselves. Both the broker
and the client run their ZMQ sockets with IPV6=1, and ZMQ connects only to the
first address a name resolves to (glibc returns v4-mapped addresses only when
the name has no IPv6 at all). On hecate (job 571147) the 4 ranks that ran on
the coordinator's own node resolved its name to a link-local IPv6 and timed out
("Timeout connecting to Coordinator"), while all 28 remote ranks joined; the
step exited 1 and srtctl aborted the sweep.
Set SLURMD_NODENAME=<runtime.head_node_ip> for the wrapper CLI calls (configure,
enable pyxis, coordinator start/stop) only, so the published command/announce
addresses are IPv4 literals. The wrapper-launched srun steps keep their own
environment. Test asserts the override reaches every wrapper call and does not
leak into launcher_env.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…yxis` pyxis applies only the last --container-mounts flag it receives (SPANK options reach slurmstepd as one environment variable per option). `nsight-slurm enable pyxis` appends its own --container-mounts after the caller's, so every wrapper-launched worker lost the job's /model, /logs and /configs mounts: on hecate (jobs 571147, 571265) the dynamo install preamble found no wheel cache under /configs, tried to clone dynamo and exited 1. Verified on a 1-node allocation: two --container-mounts flags -> only the second one is visible in the container; wrapper with pyxis disabled and caller-supplied mounts -> the connector starts, /configs is visible and the application runs. - start_srun_process(extra_container_mounts=...): raw "src:dst[:flags]" specs merged into srtctl's single --container-mounts value. - ProfilingConfig.nsight_slurm_container_mounts(log_dir): install root read-only, the connector file onto /usr/local/bin/nsight-slurm-connector (the wrapper prefixes the bare command name without pyxis management; /usr/local/bin is on the image PATH), and the log dir at its host path (wrapper config dir and report root live under it). - NsightSlurmStageMixin: `disable pyxis` instead of `enable pyxis`; launch kwargs carry the extra mounts. Docs and tests updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…steps In cuda-api mode a capture range closes at cudaProfilerStop, but the wrapper keeps the nsys session open for the next range (--capture-range-end repeat), so a report only exists once the session ends. srtctl's teardown cancelled the steps with SIGKILL (hecate job 571904: capture ranges observed on all 32 ranks, zero reports on disk). Add NsightSlurmStageMixin.flush_nsight_slurm(registry), called from the sweep's finally block right before registry.cleanup(): `nsight-slurm stop --job <id>` (coordinator -> connectors -> nsys stop), and if no *.nsys-rep appears within first_wait_s, a plain SIGTERM to the wrapper processes of the worker steps (wrapper -> srun -> connector -> nsys writes its report on SIGTERM while the application keeps running). Then wait for the report files to appear and settle (bounded by timeout_s). Best effort, never raises. Tests cover both paths and the no-op without a coordinator. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
… reports on lustre Run 572233 showed two more gaps: 1. The critical-process monitor thread (and the signal handler) call registry.cleanup() directly, so the worker steps were SIGKILLed before the sweep's finally block reached flush_nsight_slurm(). Add ProcessRegistry.add_pre_cleanup_hook(): hooks run once, before the first cleanup() terminates anything, on every teardown path. do_sweep registers the nsight-slurm flush there. 2. In cuda-api mode the connector writes nsys output into its runtime workspace and only copies it to the report root when its state machine sees a collection stop; with the nsys 2026.3 agent the range states (RangeCollection / RangeGeneration) are unknown to connector 1.5.0, so the per-range reports stayed in the container-local /tmp and died with the step. Bind-mount <log_dir>/nsight-slurm-runtime at the short in-container path /nsrt (the connector binds an AF_UNIX callback socket under it; sockaddr_un caps the path at 107 bytes, verified on a hecate node) and hand it to the connector via NSIGHT_SLURM_RUNTIME_DIR in the launcher environment. The flush rescue-copies *.nsys-rep from that workspace into <report_root>/rescued/ before signalling the connectors (their cleanup deletes the workspace) and again at the end. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…d teardown flush Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…se the pre-cleanup hook
Run 572590: the pre-cleanup hook ran, but the finally block and the critical-process
monitor thread called registry.cleanup() within the same second; the second caller saw
the hook as "done" and killed the steps while the flush was still waiting. Hold a
dedicated lock for the whole hook run so concurrent cleanup() callers wait.
The connector runtime workspace on lustre (/nsrt) held 32 rank dirs but their reports/
stayed empty through RangeCollection/RangeGeneration: in cuda-api mode nsys gets no -o
and writes nothing until the session ends. Pass
`-o <report_root>/direct/%q{SLURM_JOB_ID}_%q{SLURMD_NODENAME}_rank%q{SLURM_PROCID}`
in the wrapper tool-options (neither the wrapper CLI nor the connector rejects -o; only
--start-later is checked), so each rank's report lands on the shared filesystem at
session end or on SIGTERM, independent of the connector's scratch/upload state machine.
flush_nsight_slurm(): rescue-copy scratch reports on every poll; send SIGTERM to the
worker wrappers unless NEW reports appeared after `nsight-slurm stop` (pre-existing or
rescued files do not prove the sessions ended). Tests updated; registry race covered.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…'s report workspace `nsight-slurm srun` refuses to start when its report-output directory is non-empty without its own .nsight-cloud-storage.conf marker; pre-creating <report_root>/direct/ for the `-o` target made every worker step exit 2 (hecate job 575849). Write the direct reports to the sibling <log_dir>/nsight-slurm-direct/ instead; the flush counts reports in both places. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…tasks, not the wrapper
Hecate job 576022: the flush now ran before cleanup, but SIGTERM to the wrapper
process is relayed to its srun, and srun cancels the step with SIGKILL
("STEP ... CANCELLED ... DUE to SIGNAL Killed"), so nsys never wrote a report.
The wrapper-launched worker steps are named after their task command,
`nsight-slurm-connector`. The flush now lists them with `squeue -s -j <job>` and
sends the Slurm signal command with `--signal=TERM <job>.<step>`, which reaches
only the tasks: the connectors terminate nsys gracefully (`--kill none` leaves the
application running) and nsys writes its `-o` report. Tests cover the step
selection and that wrapper processes are never signalled.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
…the worker exits Hecate job 576684: the teardown flush now reaches the connector tasks (step "CANCELLED ... DUE to SIGNAL Terminated"), the worker shuts down gracefully, and nsys then prints "The target application terminated. One or more process it created re-parented. Waiting for termination of re-parented processes." and never finalises before cleanup kills it. Add --wait=primary to the tool options so nsys processes its events and writes the -o report as soon as the primary process exits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
Hecate job 576975: with --wait=primary the SIGTERM flush finally made nsys write
reports into the direct output dir, but nsys creates every .nsys-rep as an empty
placeholder first and fills it over minutes ("Processing events... [5%]"). The
flush saw 11 files appear at once, judged the count stable after 20 s, and cleanup
killed nsys mid-write.
Settle on (file count, non-empty count, total bytes) instead, require every report
to be non-empty, and raise the defaults to settle 60 s / timeout 600 s. Test with a
report that grows after the signal.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.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.
Summary
Adds
profiling.type: nsight-slurm, which launches every workersrunstep through theNsight Cloud for Slurm wrapper
(
nsight-slurm srun ... -- <cmd>) instead of prefixing the worker command withnsys profile.One coordinator per job collects time-aligned per-rank Nsight Systems reports into a shared report
workspace (
<log_dir>/nsight-slurm-reports, with manifest and common collection ids).Companion to #418 (playbook-flag
nsyspath). Both are independent ofobservability.enabled,so the profiling overhead can be measured against the default-mode baseline (job 4 / PR #417).
Stacked on #417 (
yna/observability-combined); the diff vs that branch is the last commit.What changes
src/srtctl/core/schema.py):ProfilingType.NSIGHT_SLURM; fieldsnsight_slurm_home,nsight_slurm_tool_path(default/usr/local/bin/nsys),nsight_slurm_profiling_mode(at-launch | manual | cuda-api, defaultcuda-api),nsight_slurm_tool_options(default = the TRT-LLM profiling playbook set minus connector-ownedflags),
nvtx_injection_path. Worker env carries theTLLM_PROFILE_START_STOPwindow plusTLLM_PROFILE_LOG_RANKS=all,DYN_ENABLE_RUST_NVTX=1,NVTX_INJECTION64_PATH.Validation: absolute home, known mode, connector-owned flags (
-o,--force-overwrite,-c/--capture-range*,--start-later) rejected,cuda-apirequiresbackend.type: trtllm.start_srun_process(src/srtctl/core/slurm.py): optionalsrun_launcher/launcher_env. With a launcher, native srun options are forwarded unchanged and terminated by--;--export=...is omitted (the wrapper appends its own--export=ALL) and the export varsride in the wrapper's process environment.
NsightSlurmStageMixin(src/srtctl/cli/mixins/nsight_slurm_stage.py): before the firstworker step, once:
configure tool-path / tool-command profile / profiling-mode / tool-options / report-output,enable pyxis,coordinator start;coordinator stop --forcein sweep cleanup.All wrapper calls logged to
<log_dir>/nsight-slurm.out;SLURM_SUBMIT_DIRredirected to thelog dir so the wrapper's job state lives under the run.
src/srtctl/cli/submit.py): Profiling panel, incl. the nsight-slurm launcher rows.NsightSlurmStageMixin.flush_nsight_slurm, aProcessRegistrypre-cleanup hook): end the nsyssessions gracefully and wait for the reports, since cuda-api mode only writes them when the session ends.
start_srun_process(extra_container_mounts=...),ProfilingConfig.nsight_slurm_container_mounts):the connector's mounts ride in srtctl's single
--container-mounts;disable pyxison the wrapper.Tests
tests/test_profiling_nsight_slurm.py(13): config helpers, env, validation (incl. cuda-apibackend gate), launcher argv/env through a mocked Popen, stage sequencing through a fake
<home>/bin/nsight-slurmthat records argv/env/cwd, idempotence, missing-install error.ruff check/ruff format --checkclean onsrc/srtctl.(pre-commit's pinned ruff v0.8.4 flags two pre-existing
UP038lines indo_sweep.py:239/schema.py:2045that predate this branch; left untouched.)Status / open items
nsight-slurm0.13.3, superprojectd9a7d30, coordinator df7e496, nsight-cloud-storage 57a1570; job 571136). First profiling job 571147
configured the wrapper, started the coordinator and ran the connector inside every worker container, but
the 4 ranks on the coordinator's own node hit
[Nsight ERROR] Timeout connecting to Coordinatorwhile all28 remote ranks joined; the step exited 1 and srtctl aborted the sweep.
Root cause (verified on a compute node with a pyzmq probe): the wrapper publishes
tcp://<SLURMD_NODENAME>:<port>; broker and client setzmq.IPV6=1, so ZMQ resolves withAF_INET6|AI_V4MAPPEDand connects to the first result only. On hecate a node's own name resolves tolink-local
fe80::…addresses (no v4-mapped entry at all), sotcp://<own name>:<port>times outwhile
tcp://<ipv4>:<port>and remote names work. Fix 24aa66d: srtctl setsSLURMD_NODENAME=<head_node_ip>for the wrapper CLI calls so the coordinator address is an IPv4 literal.(Upstream note for nsight-cloud-slurm: publish an IP literal, or iterate over resolved addresses.)
Rerun 571265: all 32 ranks joined the coordinator, but the workers never came up: the wrapper's
enable pyxismode appends a second--container-mounts, and pyxis applies only the last one(verified on a 1-node allocation), so /model, /logs and /configs were gone inside the containers and the
dynamo install preamble failed. Fix 62df1ef: srtctl no longer uses
enable pyxis; it mounts the installroot (ro), the connector onto
/usr/local/bin/nsight-slurm-connector, and the log dir at its host pathinside its own single
--container-mounts(newstart_srun_process(extra_container_mounts=...)).Verified on 1 node: connector starts, /configs visible, app runs.
Run 3 (571904): all 32 ranks joined, workers came up, both capture windows ran (connectors logged the
nsys
RangeCollectionstate), but (a) prefill worker 1 hit the same TRT-LLM hang as PR feat(profiling): adopt the Dynamo Benchmark Playbook nsys recipe for TRT-LLM workers #418's runs, at thesame prefill iteration 2324 (deterministic in the warmup stream with nsys attached), and (b) 0 reports:
in cuda-api mode the wrapper keeps the nsys session open after the range (
--capture-range-end repeat), soreports only exist when the session ends, and srtctl's teardown SIGKILLed the steps. Fix 58477a8:
flush_nsight_slurm()beforeregistry.cleanup()(nsight-slurm stop --job, then SIGTERM to the wrapperprocesses of the worker steps, then wait for
*.nsys-repto appear and settle).Run 4 (572233): same hang (prefill iteration 2319), and the flush ran too late: the critical-process
monitor thread calls
registry.cleanup()itself. Also, the connector keeps nsys output in its runtimeworkspace (container-local
/tmp) and only copies it out on a collection-stop it never sees for thensys 2026.3 range states (
RangeCollection/RangeGenerationare unknown to connector 1.5.0).Fix b009d49:
ProcessRegistry.add_pre_cleanup_hook()(flush runs before any teardown path kills steps)and the runtime workspace bind-mounted from
<log_dir>/nsight-slurm-runtimeat/nsrt(AF_UNIX socketpath limit) with rescue-copy of
*.nsys-repinto<report_root>/rescued/.Run 5 (572590): decode hang at iteration 7624 (= PR feat(profiling): adopt the Dynamo Benchmark Playbook nsys recipe for TRT-LLM workers #418's run 1), and two more findings: (a) the finally
block and the monitor thread raced into
cleanup(), the second caller skipped the hook and killed the steps;(b) the lustre-backed runtime workspaces (32 rank dirs, ipc socket fine) stayed empty through
RangeCollection/RangeGeneration: without-o, cuda-api nsys writes nothing until the session ends.Fix 5261265: hooks run under a dedicated lock (concurrent
cleanup()waits), and the tool-options carry-o <report_root>/direct/%q{SLURM_JOB_ID}_%q{SLURMD_NODENAME}_rank%q{SLURM_PROCID}so every rank writesstraight to the shared filesystem at session end / SIGTERM.
Runs 6-9 (572866, 572948, 572964, 572999) never reached the workers: hecate jobs had lost their Kerberos
credential on the compute nodes. After re-auth:
direct/) -> 576229e moves thedirect output next to it.
step -> c1e3725 signals the connector tasks (
nsight-slurm-connectorsteps) with--signal=TERM.adds
--wait=primary.<log_dir>/nsight-slurm-direct/(11 files appeared, progress bars inthe logs), but the flush judged the file COUNT settled after 20 s and cleanup killed nsys mid-write (all
0 bytes) -> 89c0353 settles on bytes, requires non-empty reports, settle 60 s / timeout 600 s.
Validation run of 89c0353 pending (needs a fresh cluster login). Every run so far also hit the TRT-LLM hang
from PR feat(profiling): adopt the Dynamo Benchmark Playbook nsys recipe for TRT-LLM workers #418 (prefill iteration ~2324 or decode 7624), which is what triggers the teardown flush.
srtctl dry-runshows a Profiling panel (type, windows, launcher, tool-options, report-output) — dc42fa8.🤖 Generated with Claude Code