feat(sys): capture and log the NCCL environment on run start - #144
Draft
asaiacai wants to merge 5 commits into
Draft
feat(sys): capture and log the NCCL environment on run start#144asaiacai wants to merge 5 commits into
asaiacai wants to merge 5 commits into
Conversation
Distributed failures are almost always configuration failures, so record the NCCL configuration on every run without any code change from the user. - collect_nccl_env() in pluto/sys.py is now the single source of truth. It widens the old NCCL_-only scan to the vars that actually shape NCCL behaviour — TORCH_NCCL_* (ProcessGroupNCCL), FI_*/OFI_* (libfabric / aws-ofi-nccl on EFA), UCX_*, and TORCH_DISTRIBUTED_DEBUG and friends — sorts the result, and masks credential-looking keys before anything is stored or sent. - Op._log_nccl_env() emits the environment as one console line from start(), after the logger and sync process are up so it is captured and uploaded with the rest of the run's output. This is not redundant with systemMetadata: resuming ranks go through /api/runs/resume, which carries no system info, so in multi-node runs the metadata describes only the rank that created the run. The console line is per-rank, which is where a misconfigured worker shows up. The line is suppressed in noop mode and under disable_system_metrics (backfill hosts say nothing about the run being written), swallows collection errors, and truncates so a large FI_*/UCX_* set cannot push a multi-KB line into the console stream. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQ3d4ZUUUVCBYjCYonyGye
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
scripts/gen_api_docs.py --check is part of CI; sys.System is one of the documented symbols, so the docstring edit made the committed MDX stale. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQ3d4ZUUUVCBYjCYonyGye
start() publishes pluto.log/alert/watch, appends to pluto.ops, and registers an atexit finish. Undo all three so the test leaves no trace for whatever else runs in the same xdist worker. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQ3d4ZUUUVCBYjCYonyGye
test_fork_e2e_log_metrics polled only until the metric *name* was queryable, which happens as soon as the first point lands — then read the series and asserted all five values were there. CI caught the race on 3.13 (len(values) == 1, [0.5]) while 3.10/3.11/3.12 passed on the same commit against the same server. Poll for the full series instead, the way the parent fixture already does via _poll_max_step. The assertions are unchanged and still have to hold at the deadline, so a genuinely missing point still fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQ3d4ZUUUVCBYjCYonyGye
…logging-ex9acs # Conflicts: # docs/docs/advanced/01-debugging.md
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.
Records each run's NCCL configuration automatically, with no code change from the user.
What changed
collect_nccl_env()(pluto/sys.py) is now the single source of truth for the NCCL environment. It widens the previousNCCL_-only scan to the variables that actually shape NCCL behaviour:NCCL_*NCCL_DEBUG,NCCL_SOCKET_IFNAME,NCCL_IB_HCA,NCCL_ALGOTORCH_NCCL_*TORCH_NCCL_ASYNC_ERROR_HANDLING,TORCH_NCCL_BLOCKING_WAITFI_*,OFI_*FI_PROVIDER,FI_EFA_USE_DEVICE_RDMA(libfabric / aws-ofi-nccl)UCX_*UCX_TLS,UCX_NET_DEVICESTORCH_DISTRIBUTED_DEBUG,TORCH_CPP_LOG_LEVEL,TORCH_SHOW_CPP_STACKTRACES,GLOO_SOCKET_IFNAMEResults are sorted, and values whose key looks credential-bearing (
*_TOKEN,*_SECRET,*_PASSWORD,*_API_KEY,*_ACCESS_KEY, …) are replaced withMASKED_VALUEbefore anything is stored, sent, or logged.System.get_nccl_info()uses it, so the environment continues to ship insystemMetadata.nccl.nccl_envon run create — queryable through the existingsystemMetadata.filter prefix.Op._log_nccl_env()(new) emits the environment as one console line fromOp.start():It runs after
setup_logger()and the sync manager are up, so the line is captured and uploaded like any other console output.Why both sinks
They cover different ranks. Resuming ranks go through
/api/runs/resume, whose payload carries no system info (make_compat_resume_v1), so in a multi-node runsystemMetadataonly ever describes the rank that created the run. The console line is emitted per rank, which is where a misconfigured worker node actually shows up.Safety / noise
mode == 'noop'anddisable_system_metrics(backfills viapluto.migrate— the importing host's environment says nothing about the run being written).NCCL_ENV_LOG_MAX_CHARS(2048) so a host with a largeFI_*/UCX_*set cannot push a multi-KB line into the console stream. The full set still goes tosystemMetadata._is_masked_key, not_is_secret_key) follows the CodeQL note already inCLAUDE.md:py/clear-text-logging-sensitive-dataclassifies a call's result by callee name, and this result is logged.Known limitation (documented): the environment is read at
pluto.init()time, so variables exported later — e.g. by a launcher that configures NCCL immediately beforeinit_process_group()— are not recorded.Docs: this branch originally added the user-facing description to
docs/docs/advanced/01-debugging.md. #145 then deleted the Docusaurus site, so merging main produced a modify/delete conflict there. Resolved by accepting the deletion — the site is gone deliberately and live docs are Mintlify, built outside this repo — and folding the user-facing content (matched-prefix table,list_runsfilter example, the read-at-init-time limitation) into theCLAUDE.mdsection alongside the implementation notes, so nothing is lost and no dangling path reference remains. Happy to move it wherever the Mintlify content is authored instead.Also in this PR: a fix for a pre-existing race in
tests/test_fork_e2e.py::test_fork_e2e_log_metrics, which CI hit on this branch. It polled only until the metric name was queryable — which happens as soon as the first point lands — then read the series and asserted all five values were present (assert 1 == 5on 3.13, while 3.10/3.11/3.12 passed on the same commit). It now polls for the full series the way the module's parent fixture already does via_poll_max_step; the assertions are unchanged and still have to hold at the deadline.Tested (run the relevant ones):
ruff check/ruff formatclean under the pinned ruff 0.4.10;python scripts/gen_api_docs.py --checkreportsdocs-api/up to date.New/updated tests, all passing (re-run post-merge under main's new pytest 9 pin:
103 passed, 4 skippedacross the NCCL/system-info/console/fd-capture suites):tests/test_nccl_env.py(new, 8 tests) — the log line: emitted at INFO, silent when no vars are set, credentials masked, long environments truncated, suppressed underdisable_system_metricsandnoop, collection failure never raises, and the hook is actually wired intoOp.start().tests/test_system_info.py— added coverage forTORCH_NCCL_*/FI_*/UCX_*/extra-key capture, unrelated vars staying out, sorting, case-insensitive masking, explicit-mapping input, and the env reaching theget_info()payload.Manually verified against a process with
NCCL_DEBUG,NCCL_SOCKET_IFNAME,TORCH_NCCL_ASYNC_ERROR_HANDLING,FI_PROVIDERand a decoyNCCL_AUTH_TOKENset: all five appear inget_nccl_info(), the token redacted, and the startup line renders as expected.