Skip to content

fix(validator): fail fast on degraded GPU node; dedicated model-cache timeout#1866

Merged
mchmarny merged 8 commits into
NVIDIA:mainfrom
njhensley:validator/perf-nccl-gpu-census-and-cache-timeout
Jul 23, 2026
Merged

fix(validator): fail fast on degraded GPU node; dedicated model-cache timeout#1866
mchmarny merged 8 commits into
NVIDIA:mainfrom
njhensley:validator/perf-nccl-gpu-census-and-cache-timeout

Conversation

@njhensley

Copy link
Copy Markdown
Member

Summary

Two independent performance-validator fixes: nccl-all-reduce-bw now fails fast with a per-node GPU census when a target node is short of its peers (#1858), and the inference-perf model-cache populate Job gets its own timeout budget instead of sharing the 10m workload-ready deadline (#1859).

Motivation / Context

Fixes: #1858, #1859
Related: N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Component(s) Affected

  • Validator (pkg/validator)
  • Other: validators/performance (NCCL + inference-perf checks), pkg/defaults (timeout), docs/contributor

Implementation Notes

  • validator(nccl-all-reduce-bw): fail fast with diagnostic on degraded GPU node #1858 — new uniformGPUCountPerNode (mirrors the existing uniformFabricResourceCount fail-closed pattern): logs a per-node GPU census on every call, and fails fast naming the short node(s) and their count vs the peer max. A uniformly low count is not flagged (a coherent, if unusual, topology; the census still surfaces it). The diagnostic names both the transient device-plugin-rollout cause ("re-run once uniform") and a genuine hardware fault (nvidia-smi -L / dmesg NVRM/Xid).
  • validator(inference-perf): model-cache populate shares 10m budget and times out #1859 — dedicated defaults.ModelCachePopulateTimeout (13m), env-overridable via AICR_INFERENCE_PERF_MODEL_CACHE_POPULATE_TIMEOUT, resolved through a named populateJobTimeout() seam so the decoupling from the workload-ready budget stays test-guarded. Sized to keep the inference sequential worst case (5+13+10+5+5+15 = 53m) under CheckExecutionTimeout (55m). The optional HF-token secret is already wired into the populate Job; the timeout error now surfaces both remedies in-band, and the new knob is validated up front in validatePerfTuningEnvs alongside its siblings.
  • Both changes went through a multi-persona + adversarial review; the up-front validation, the decoupling test, the degraded-before-full test case, and the broadened diagnostics are results of that pass.

Testing

go test ./validators/performance/... ./pkg/defaults/... -race
golangci-lint run -c .golangci.yaml ./validators/performance/... ./pkg/defaults/...
  • All affected-package tests pass under -race; golangci-lint 0 issues; gofmt clean.
  • uniformGPUCountPerNode and populateJobTimeout at 100% coverage. Tests cover: uniform pass, single node, one-short (named), degraded-node-first (guards the "expected = max" invariant against a first-node regression), multiple-short (all named), uniformly-low (not flagged), empty, all-zero; the populate-timeout decoupling from workload-ready; and the up-front validation of the new knob.

Risk Assessment

  • Low — Isolated to two checks; fail-closed direction; well-tested; easy to revert.

Rollout notes: Behavior change — a run against a genuinely non-uniform GPU cohort now hard-fails (previously it hung or ran a non-representative degraded benchmark). Operators who had widened cache-populate via AICR_INFERENCE_PERF_WORKLOAD_READY_TIMEOUT must switch to the new ..._MODEL_CACHE_POPULATE_TIMEOUT knob (documented as a migration note). No breaking API/flag changes.

Checklist

  • Tests pass locally (-race, affected packages)
  • Linter passes (golangci-lint on affected packages)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs (new env var + migration note in docs/contributor/validator.md)
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)

… timeout

Two independent performance-validator fixes.

nccl-all-reduce-bw (NVIDIA#1858): determineGPUConfig sized whole-node workers
from the first target node's GPU count, so a node short of its peers — a
degraded GPU or driver fault, e.g. an H100 node enumerating 7 of 8 GPUs —
left one worker Pending and the launcher eventually failed with an opaque
"pod failed". Add uniformGPUCountPerNode: it logs a per-node GPU census on
every call and fails fast, naming the short node(s) and their count, when
a target node is below its peers. A uniformly low count is not flagged (a
coherent, if unusual, topology). The diagnostic names both the transient
device-plugin-rollout cause and a genuine hardware fault. Mirrors the
existing uniformFabricResourceCount fail-closed pattern.

inference-perf (NVIDIA#1859): the one-time model-cache populate Job reused the
10m DynamoGraphDeployment workload-ready budget, so a cold image pull plus
a first-ever multi-GB Hugging Face download shared one deadline and flaked
on slow/throttled nights. Give it a dedicated ModelCachePopulateTimeout
(13m, env-overridable via AICR_INFERENCE_PERF_MODEL_CACHE_POPULATE_TIMEOUT),
sized to keep the inference sequential worst case under CheckExecutionTimeout.
The optional HF-token secret (already wired into the populate Job) removes
the anonymous-download throttling; the timeout error now surfaces both
remedies in-band. The new knob is validated up front in validatePerfTuningEnvs
alongside its siblings, and its decoupling from the workload-ready budget is
test-guarded.

Fixes NVIDIA#1858
Fixes NVIDIA#1859

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
@njhensley
njhensley requested a review from a team as a code owner July 22, 2026 23:16
@njhensley njhensley added the theme/validation Constraint evaluation, health checks, and conformance evidence label Jul 22, 2026
@njhensley njhensley self-assigned this Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The inference validator now uses a dedicated, configurable timeout for the one-time model-cache populate Job, separate from workload readiness, with documentation, validation, and tests. The NCCL bandwidth validator inventories allocatable GPUs across all target nodes, logs the census, and fails fast with diagnostics when counts are non-uniform. Tests cover timeout resolution, invalid configuration, uniform GPU counts, degraded nodes, and edge cases.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: mchmarny

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the two main changes: degraded GPU-node fail-fast handling and a dedicated model-cache timeout.
Description check ✅ Passed The description is detailed and directly describes the implemented nccl and inference-perf fixes.
Linked Issues check ✅ Passed The nccl-all-reduce-bw changes add per-node GPU census, fail fast on short nodes, and test the degraded 8-vs-7 case required by #1858.
Out of Scope Changes check ✅ Passed The changes stay within the stated validator, timeout, test, and documentation objectives without unrelated scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@validators/performance/model_cache_test.go`:
- Around line 213-243: Convert TestPopulateJobTimeout in
validators/performance/model_cache_test.go (lines 213-243) into a table-driven
test with per-case environment setup covering the default, workload-ready
isolation, and dedicated override scenarios. Also update the validation cases in
validators/performance/inference_perf_test.go (lines 1171-1181) to fold the
malformed populate-timeout case into the existing table-driven list; no other
behavior changes are needed.

In `@validators/performance/nccl_all_reduce_bw_constraint.go`:
- Around line 728-733: Make the GPU census cancellable: in
validators/performance/nccl_all_reduce_bw_constraint.go lines 728-733, pass
ctx.Ctx from the validator into uniformGPUCountPerNode; in lines 764-803, accept
the context, check ctx.Done() during each node-scan loop, and return a correctly
coded wrapped cancellation error; in
validators/performance/nccl_gpu_census_test.go lines 94-112, add a
canceled-context test and check context cancellation while iterating the table
cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 80a49104-244e-4bf2-8ac8-b80f7131db9f

📥 Commits

Reviewing files that changed from the base of the PR and between c5d4ede and e2b078c.

📒 Files selected for processing (9)
  • docs/contributor/validator.md
  • pkg/defaults/timeouts.go
  • pkg/defaults/timeouts_test.go
  • validators/performance/inference_perf_constraint.go
  • validators/performance/inference_perf_test.go
  • validators/performance/model_cache.go
  • validators/performance/model_cache_test.go
  • validators/performance/nccl_all_reduce_bw_constraint.go
  • validators/performance/nccl_gpu_census_test.go

Comment thread validators/performance/model_cache_test.go
Comment thread validators/performance/nccl_all_reduce_bw_constraint.go
Address CodeRabbit review on NVIDIA#1866: convert the three populate-timeout
scenarios (default, workload-ready isolation, dedicated override) into a
table-driven test per the repo's test conventions, and restore the
TestEnsureModelCache_DisabledNoop doc comment to its function.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>

@mchmarny mchmarny left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The core GPU-census and timeout-decoupling changes look sound. One non-blocking error-propagation issue remains: the newly added timeout remediation is currently discarded. Nothing here blocks merge.

Comment thread validators/performance/model_cache.go Outdated
// triaging a red run won't be reading the env-var reference): the
// download is likely throttled anonymously — provide the HF-token secret
// — or the model is large enough to need a bigger budget.
return errors.PropagateOrWrap(werr, errors.ErrCodeInternal,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P2] Preserve the timeout remediation when propagating coded errors

WaitForJobCompletion returns a structured ErrCodeTimeout, and PropagateOrWrap returns any structured error unchanged. This formatted remediation is therefore discarded on the timeout path it is meant to improve. Return a timeout-coded error that carries this message while propagating other coded failures unchanged, and add a test asserting the timeout text.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — fixed in f189a68. Extracted wrapPopulateJobError: on the timeout path (stderrors.Is(werr, ErrCodeTimeout)) it now returns a fresh ErrCodeTimeout that carries the remediation and wraps the original error, so the message survives on exactly the path it targets; other coded failures (e.g. ErrCodeUnavailable when the watch closes) still propagate unchanged. Added TestWrapPopulateJobError asserting the timeout text is present and that non-timeout errors are propagated without it.

mchmarny
mchmarny previously approved these changes Jul 23, 2026
…path

Address @mchmarny review on NVIDIA#1866: WaitForJobCompletion returns a structured
ErrCodeTimeout and errors.PropagateOrWrap keeps coded errors unchanged, so the
actionable remediation (provide HF-token / raise the budget) was discarded on
the very timeout path it targets. Extract wrapPopulateJobError: on a timeout it
returns a fresh ErrCodeTimeout carrying the remedy and wrapping the original;
other coded failures propagate unchanged. Add TestWrapPopulateJobError.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
mchmarny
mchmarny previously approved these changes Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@validators/performance/model_cache_test.go`:
- Around line 266-289: The two independent error scenarios in the test should be
consolidated into a table-driven test. Replace the separate subtests around
wrapPopulateJobError with a []struct containing each input error and expected
assertions, then iterate with t.Run while preserving the timeout
remediation/code checks and the unavailable propagation/no-remediation checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: e6b921c9-0d62-443d-926a-8a819bb9f7e1

📥 Commits

Reviewing files that changed from the base of the PR and between 96a0f0a and f189a68.

📒 Files selected for processing (2)
  • validators/performance/model_cache.go
  • validators/performance/model_cache_test.go

Comment thread validators/performance/model_cache_test.go Outdated
Consolidate the two independent error-outcome subtests (timeout carries
remediation and stays timeout-coded; non-timeout coded error propagates
unchanged) into a single []struct loop, matching the mandatory
table-driven pattern used by the sibling parseModelCacheSize tests.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@validators/performance/model_cache_test.go`:
- Around line 280-300: The non-timeout case does not verify that
wrapPopulateJobError returns the original error instance. Update the test case
and assertion around wrapPopulateJobError to retain the input error and assert
identity for the non-timeout coded error, while preserving the existing code,
text, and remediation checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 44d7206c-e531-473a-a829-99df9b009e38

📥 Commits

Reviewing files that changed from the base of the PR and between f189a68 and 90f3ce3.

📒 Files selected for processing (1)
  • validators/performance/model_cache_test.go

Comment thread validators/performance/model_cache_test.go
njhensley and others added 2 commits July 22, 2026 18:10
Add an identity assertion (got == input) to the non-timeout case of
TestWrapPopulateJobError. The code+substring checks alone would still
pass if wrapPopulateJobError re-wrapped a coded error in a fresh coded
error; this pins the contract that PropagateOrWrap returns the exact
instance unchanged.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
@njhensley
njhensley requested a review from mchmarny July 23, 2026 01:46
@njhensley
njhensley enabled auto-merge (squash) July 23, 2026 01:46
@mchmarny
mchmarny disabled auto-merge July 23, 2026 11:53
@mchmarny
mchmarny merged commit 9724b49 into NVIDIA:main Jul 23, 2026
6 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs size/L theme/validation Constraint evaluation, health checks, and conformance evidence

Projects

None yet

2 participants