Repository navigation
fix(examine): report an AMD GPU in --json on WSL when the Windows host has one - #870
Conversation
…t has one On WSL the hardware probes that set has_amd_gpu are skipped, so rocm examine --json said has_amd_gpu: false, with an empty gpus list, beside a summary naming a gfx target and a text report saying an AMD GPU was detected. The text report and summary.detected_gfx_target read the Windows-side detection; the field now follows that same value, taken from the summary the JSON path already gathers, so there is no second PowerShell query and the two forms cannot disagree. gpus stays empty on WSL and status is unchanged (compute_status answers wsl first). Off WSL nothing changes. The examination-08 scenario (examine-both-forms-agree-on-gpu) covers this and now runs on WSL2 hosts, so its expected-failure row (EAI-7998) is removed in the same change; the test that pinned the row now guards against it coming back. docs/wsl.md and the model_fit.rs doc comment no longer say the field is always false on WSL. Refs ROCm#346. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues block approval of the WSL GPU-presence reporting change.
No open issues 🎉
What changed in this PR
Fixes the has_amd_gpu portion of #346 by making rocm examine --json use the same detected GPU target as the text report on WSL. The GPU list remains empty, and usable-memory reporting is unchanged.
Changes:
- Derives WSL GPU presence from the existing summary without another Windows probe; preserves non-WSL behavior.
- Adds unit coverage and removes the expected-failure entry for the existing JSON/text agreement scenario.
- Updates documentation and comments to distinguish host GPU presence from ROCm device visibility.
| File | Description |
|---|---|
tests/e2e-cucumber/src/expectation.rs |
Guards against restoring the WSL agreement expected failure. |
tests/e2e-cucumber/features/examine.feature |
Updates scenario comments to describe the WSL fix. |
tests/e2e-cucumber/expectations.toml |
Removes the GPU-report disagreement expected failure. |
docs/wsl.md |
Documents the revised WSL JSON field semantics. |
crates/rocm-core/src/examine.rs |
Adds the WSL GPU-presence helper, documentation, and unit tests. |
apps/rocm/src/model_fit.rs |
Clarifies comments about probe results and ROCm visibility; behavior is unchanged. |
apps/rocm/src/examine_cmd.rs |
Applies the detected GPU target to the WSL JSON examination. |
Review effort: Balanced
nowycondro
left a comment
There was a problem hiding this comment.
🤖 Automated review (Claude Code) · 91d3055
This automation never files a GitHub approval, so no approving review will appear here whatever the outcome — the merge decision stays with a human reviewer.
Review — no blocking findings
Full review of the whole change (08235c5…91d3055, single commit). Implements the has_amd_gpu portion of GitHub issue #346 (text/JSON disagreement on WSL GPU presence) and of Jira ROCMAI-411 (formerly EAI-7998)'s remaining WSL2 scope; explicitly refs rather than closes #346 (the gpus-list and usable-memory-figure asks are left out, and said so). ROCMAI-411 is already marked Done in Jira, though its own "Done when" list also names Instinct-side probe-failure handling and an e2e-harness switch to reading --json directly that this PR does not touch — the PR never claims to close either ticket, so this is informational only, not a mismatch.
Blocking
None
Non-blocking
None
Decisions for the author
- Deriving
has_amd_gpufrom the Windows-sidedetected_gfx_targetrather than fromrocm_sees_gpu— tradeoff. The chosen source reuses a value already gathered for the human report (no second PowerShell probe, no added timeout risk) and keeps the two report forms in lockstep by construction. The cost: on WSL,has_amd_gpunow means "a display adapter exists," not "ROCm can enumerate it" — narrower than its bare-metal meaning, and callers wanting the latter must readwsl.rocm_sees_gpuinstead. This is already reasoned out at length in the method's doc comment anddocs/wsl.md; noting it only so the choice is visibly confirmed rather than assumed.
Positive signals
- The two new unit tests (
wsl_has_amd_gpu_follows_the_windows_side_gfx_target,adopting_a_host_gpu_does_nothing_off_wsl) are built to catch specific mutations (no-op, always-true, droppedis_wslguard), not just the happy path. - The PR is precise about scope: it refs rather than closes GitHub #346, names exactly what it leaves out, and cites the existing e2e scenario (
examine-08,@id:examine-both-forms-agree-on-gpu) that now covers the fix instead of adding a redundant one. - Doc comments touched by this change (
examine.rs,model_fit.rs,docs/wsl.md) were sysematically swept for the old "always false on WSL" claim; an independent repo-wide grep found no stale copies left anywhere else.
Deployment notes
- Breaking JSON-contract change on WSL:
rocm examine --json'shas_amd_gpuis no longer unconditionallyfalseon WSL hosts — it now follows the Windows-side detected gfx target, matching the human report. External tooling that treated "always false on WSL" as an invariant needs updating;gpusstays empty andstatusstayswslunchanged.
What this covered
Full diff and surrounding code read completely, by three independent workers plus the driver: the core-logic group (crates/rocm-core/src/examine.rs, apps/rocm/src/examine_cmd.rs, apps/rocm/src/model_fit.rs, cross-checked against diagnose.rs, diagnose_cmd.rs, host_gpu.rs, host_gpu/wsl.rs, host_gpu/windows_inventory.rs, examine_report_text.rs), the tests/docs group (tests/e2e-cucumber/expectations.toml, tests/e2e-cucumber/features/examine.feature, tests/e2e-cucumber/src/expectation.rs, docs/wsl.md), plus a repo-wide impact-analysis / agent-instruction-adherence / history pass (grepped has_amd_gpu, adopt_wsl_host_gpu, detected_gfx_target, rocm_sees_gpu, EAI-7998, #346 across the tree; checked against AGENTS.md §3/§5/§6; walked git log on the touched files). Commits reviewed: 08235c55c137f1620f2afeb34ceb8ac7810d5133…91d305502862896c33b068864a065bc9dcaa1160.
Did not run: the prior-changes pass (review comments on earlier changes to these files) — the worker's GitHub search access was unauthorized in its environment, so this could not be completed. CI was read live: 30 of 32 checks completed successfully (clippy, build-and-test, affected-crate tests, CodeQL, docs/link/license/signing checks, and E2E across Strix Halo WSL2/Windows/Ubuntu-nightly/Ubuntu-release); 2 remained queued (E2E MI300X, E2E W7900) at review time, neither failing. The PR's mergeable_state reads blocked, consistent with its one requested human reviewer not yet having reviewed, not with any red check.
Not reconciled against any discussion here — the only existing review on this PR is an automated Copilot summary at the same head commit, not a human discussion thread.
🤖 Generated with Claude Code
juhovainio
left a comment
There was a problem hiding this comment.
Looks good to me. Reusing the already-gathered detected_gfx_target rather than a second PowerShell probe keeps the human and JSON forms in agreement by construction, and the set / clear / off-WSL unit tests plus the examine-08 scenario cover the change. CI is green on the lanes that have finished.
A few non-blocking observations, two of them inline:
- The adoption is opt-in and only
examine_cmd.rscalls it, so otherExaminationconsumers on WSL still seehas_amd_gpu=false. The PR text namesdiagnose.rsandmodel_fit.rs; listing the full set of consumers would help. - On WSL the JSON now has
has_amd_gpu=truenext tohas_apu/has_discrete_amd=falseandgpus=[]. Worth documenting on the field. - The call wiring is only guarded by e2e
examine-08on the WSL2 lane; there is no unit-level guard that the call exists. adopt_wsl_host_gputakes a gfx string only to testis_some; a bool would state the intent more directly.
Scope note: this covers the WSL2 half of the linked ticket's done-when. The Instinct/MI300X case, failed-probe-as-failure, and the harness reading --json remain, which fits the PR using "Refs" rather than "Closes".
| // `detected_gfx_target`; WSL skips the probes that would set | ||
| // `has_amd_gpu`, so take it from here rather than leave the two forms | ||
| // to disagree on a healthy host. | ||
| examination.adopt_wsl_host_gpu(host.detected_gfx_target.as_deref()); |
There was a problem hiding this comment.
Only this call site adopts the Windows-side GPU; other consumers of Examination on WSL still see has_amd_gpu=false. Worth listing all consumers in the PR text, or deriving it in one place. Also has_apu/has_discrete_amd stay false beside has_amd_gpu=true on WSL.
There was a problem hiding this comment.
Checked the other consumers. On WSL nothing else reads has_amd_gpu, has_apu or has_discrete_amd in a way that depends on them: the failure-catalog checks that read them are scoped to linux and windows (fix-9 is explicitly not wsl, since WSL2 exposes no per-device topology to collide over; fix-13 is Windows only), the WSL checks use wsl.rocm_sees_gpu, and model_fit.rs already takes rocm_sees_gpu on WSL. So rocm examine --json is the one place that needs the adoption, and there is no second call site to keep in step. Deriving it inside the probe would need the Windows-side PowerShell query a second time, which is why the caller passes the value it already holds.
e6e35c5 records this on the field's doc comment and in docs/wsl.md, and the PR body's "Consumers checked" section now lists them. It also says that has_amd_gpu: true beside has_apu and has_discrete_amd both false is the expected WSL shape: a gfx target does not say which kind of part it is, so those two are left at their probe values rather than guessed. The unit test now asserts that too.
| /// (`compute_status` answers `wsl` before it asks about a GPU). | ||
| pub const fn adopt_wsl_host_gpu(&mut self, detected_gfx_target: Option<&str>) { | ||
| if self.is_wsl { | ||
| self.has_amd_gpu = detected_gfx_target.is_some(); |
There was a problem hiding this comment.
has_amd_gpu is set from "a gfx target string exists" while has_apu/has_discrete_amd/gpus stay at their probe values on WSL. Consider documenting that on the field, or taking a bool so the intent is explicit.
There was a problem hiding this comment.
Done in e6e35c5, both ways: adopt_wsl_host_gpu now takes a bool (the call site passes detected_gfx_target.is_some(), so the one claim it makes is explicit), and the has_amd_gpu field doc says that gpus, has_apu and has_discrete_amd stay at their probe values on WSL and why. docs/wsl.md says the same. The unit test also asserts that adopting a host GPU leaves has_apu and has_discrete_amd alone; making the method set has_apu turns it red.
A review of the WSL has_amd_gpu change asked whether other consumers still see false, and why has_apu and has_discrete_amd stay false beside a true has_amd_gpu. Document both on the field and in docs/wsl.md: the Windows side reports a gfx target, not a listing that distinguishes an APU from a discrete part, and the checks that read these fields are scoped to linux and windows or use wsl.rocm_sees_gpu. adopt_wsl_host_gpu now takes a bool rather than the target string, so the call site states the one claim it makes, and a test pins that has_apu and has_discrete_amd are left alone. Signed-off-by: Jussi Elo <jussi.elo@amd.com>
nowycondro
left a comment
There was a problem hiding this comment.
🤖 Automated review (Claude Code) · e6e35c5
This automation never files a GitHub approval, so no approving review will appear here whatever the outcome — the merge decision stays with a human reviewer.
Review — no blocking findings
Full review of the whole change (base 8479e6a…head e6e35c5, 2 commits). Fixes the has_amd_gpu portion of GitHub issue #346, refs rather than closes it (the gpus-list and usable-memory-figure asks are explicitly left out). The second commit (e6e35c5) is a genuine follow-up answering juhovainio's review on the first commit, not a no-op: it changes adopt_wsl_host_gpu's parameter from a gfx-target-shaped value to a plain bool, documents that has_apu/has_discrete_amd/gpus stay at their probe values on WSL, and adds a test pinning that — confirmed by diffing 91d3055...e6e35c5 directly rather than taking the commit message's word for it. Separately, this also resolves the WSL2 half of Jira ROCMAI-411 (formerly EAI-7998, confirmed by direct lookup)'s "Done when" list (GPU-presence agreement on WSL2; xfail row removed, not widened); that ticket's Instinct-half and "harness reads --json" items remain untouched, and the PR never claims otherwise — informational only, not a mismatch. (ROCMAI-411 already shows status "Done" in Jira ahead of this PR merging — a Jira/GitHub tracking lag, not a claim this PR makes.)
Blocking
None
Non-blocking
- Regression-guard test doesn't cover all the WSL host shapes its own claim implies —
tests/e2e-cucumber/src/expectation.rs:2067-2075(gpu_report_agreement_has_no_xfail_on_wsl).
fn cap()(same file, ~697-800) defines threeis_wsl: truefixtures:"wsl2"(gfx_target: Some(..),has_amd_gpu: true),"wsl"(gfx_target: None,has_amd_gpu: false),"wsl-no-passthrough"(gfx_target: Some(..),has_amd_gpu: false). The test only asserts!is_xfail(..)for"wsl-no-passthrough"and"wsl", never"wsl2".Condition.has_amd_gpu: Option<bool>is a real, already-used scoping key elsewhere inexpectations.toml(an unrelated existing row keys onhas_amd_gpu = true), so a future xfail row re-added for this scenario scoped by, say,is_wsl = true, has_amd_gpu = truewould match"wsl2"and pass this guard silently — contrary to the test's own doc comment, which says re-adding the row "has to be a deliberate decision." (I confirmed this isn't a live bug today: the product's hardware probes are categorically skipped on all WSL per the platform constraint recorded in ROCMAI-411 — KFD/DRM nodes don't exist on WSL regardless of passthrough — so there's no scenario whereadopt_wsl_host_gpuclobbers an already-correct probe value. This is purely a gap in the regression guard's own completeness.)
Confidence 78 · logic · Fix: add acap("wsl2")assertion to the test, or narrow the doc comment's claim to the two scopings it actually checks.
Decisions for the author
- Deriving
has_amd_gpufrom the Windows-sidedetected_gfx_targetrather than fromrocm_sees_gpu— tradeoff. Reuses an already-gathered value (no second PowerShell probe, no added timeout risk) and keeps the two report forms in lockstep by construction. Cost: on WSL,has_amd_gpunow means "a display adapter exists," not "ROCm can enumerate it" — narrower than its bare-metal meaning; callers wanting the latter needwsl.rocm_sees_gpu. Already reasoned out at length in the method's doc comment anddocs/wsl.md; noting it so the choice is visibly confirmed. - No unit-level test guards that
examine_cmd.rsactually callsadopt_wsl_host_gpu— non-blocking-improvement, still open.juhovainio's first-commit review raised four points; the second commit answered three (bool signature,has_apu/has_discrete_amddocs + test, full consumer list) but this one — only the e2eexamine-08scenario on the WSL2 lane guards the call-site wiring itself — remains unaddressed. This matches a recurring pattern in this repo (PR #680 drew the same kind of comment from the same reviewers, about similarly-shaped "two probes feed one output" wiring with no unit-level guard that the call exists).
Positive signals
- The two new unit tests (
wsl_has_amd_gpu_follows_the_windows_side_gfx_target,adopting_a_host_gpu_does_nothing_off_wsl) are built to catch specific mutations (droppedis_wslguard, always-true, OR-based assignment), not just the happy path — verified by hand-tracing each against a few plausible buggy implementations. - The removed
EAI-7998xfail row's history (viagit logonexpectations.toml) shows this exact row has been added/removed twice before, each time driven by a concrete measurement rather than guesswork; nothing institutionally useful is lost by deleting it now, since the historical MI300X case it also referenced is independently still documented attests/e2e-cucumber/src/capability.rsand in the scenario's own comment. - Old "
has_amd_gpuis always false on WSL" claims were swept from every doc comment anddocs/wsl.mdin the same change; an independent repo-wide grep found no stale copies left behind.
Deployment notes
- Breaking JSON-contract change on WSL:
rocm examine --json'shas_amd_gpuis no longer unconditionallyfalsethere — it now follows the Windows-side detected gfx target, matching the human report.gpusstays empty andstatusstayswsl, unchanged. External tooling that treated "always false on WSL" as an invariant needs updating.
What this covered
Full diff and surrounding code read completely, by four independent workers plus the driver: core logic (crates/rocm-core/src/examine.rs, apps/rocm/src/examine_cmd.rs, apps/rocm/src/model_fit.rs, cross-checked against diagnose.rs and a repo-wide grep for every other reader of has_amd_gpu/has_apu/has_discrete_amd/rocm_sees_gpu); tests/docs (tests/e2e-cucumber/expectations.toml, features/examine.feature, src/expectation.rs, docs/wsl.md); an AGENTS.md adherence + code-comment pass; and a history (git log/git blame) + prior-changes pass (traced the EAI-7998 row's full history, and PR #680 as repo precedent). The driver independently re-verified the test-coverage finding above against the raw file content (not just the worker's claim) and re-confirmed CI live (gh pr view --json statusCheckRollup: 25 success, 1 skipped, 0 failing) at head e6e35c58ef13c5705e31f69636833b7e26ae8144, and independently looked up ROCMAI-411/EAI-7998 and GitHub issue #346 directly rather than trusting either PR text or the prior nowycondro review's characterization of them.
Did not run: a local cargo test/clippy reproduction (relied on the green CI run plus manual code tracing instead); the design-review step (Step 7) was done by driver reasoning across the fan-out results rather than a dedicated fifth worker, for budget reasons — it covered the WSL2-passthrough-overwrite scenario (ruled out), the test-coverage gap above, and the JSON-contract break (see Deployment notes).
This PR's head moved since the existing nowycondro review (pinned to commit 91d30550, now superseded); this review is fresh against the current head and not a re-publication of that one. The prior review's and juhovainio's review paths (which files/points they covered) were used only to scope what was new — specifically, to confirm the second commit was substantive and to check whether juhovainio's four review points were addressed — never their conclusions; all findings above were independently re-derived from the code. Not reconciled against any further discussion beyond that.
🤖 Generated with Claude Code
Summary
On WSL2,
rocm examine --jsonreportshas_amd_gpu: falseand an emptygpuslist on a machine whose ownsummary.detected_gfx_targetnames a GPU (for examplegfx1151) and whose text report says "AMD GPU detected". Anything reading the JSON, including the e2e harness, concludes there is no GPU on a healthy host. This fixes thehas_amd_gpupart of #346.The cause is that WSL reaches the GPU through the Windows host driver, so the hardware probes that set
has_amd_gpuare skipped there, while the text report andsummary.detected_gfx_targetread the Windows-side detection. The two forms were fed by different sources and disagreed every time on such a host. It was deterministic, not a flake.Change
Examination::adopt_wsl_host_gpusetshas_amd_gpuon a WSL host from whether the Windows side detected a GPU, and the--jsonpath calls it withdetected_gfx_target.is_some()of the summary it already gathers. The text report reads that same value, so the two forms cannot disagree by construction, and there is no second PowerShell query (the Windows probe has its own timeout). Off WSL it does nothing and the probes keep owning the field.What does not change:
gpusstays empty on WSL (there is no PCI listing to build entries from),has_apuandhas_discrete_amdstayfalse(a gfx target does not say whether the part is an APU or a discrete card, sohas_amd_gpu: truebeside bothfalseis the expected WSL shape, as it already is for the kernel-topology fallback on Linux), andstatusstayswsl(compute_statusanswerswslbefore it asks about a GPU). The field now says a display adapter exists on the Windows side, not that ROCm can enumerate it from inside the distro;wsl.rocm_sees_gpustill answers that.This changes the JSON contract on WSL:
has_amd_gpuis no longer always false there.docs/wsl.mdand the doc comments (examine.rs,model_fit.rs) are updated to match.Scenario and lanes
Existing scenario
@id:examine-both-forms-agree-on-gpu(examine-08) covers this and now passes on WSL2, so I did not add another. Its expected-failure row is removed in the same PR: leaving it would turn a passing scenario into a stale unexpected pass on the Strix Halo WSL2 lane, which is the lane that exercises it. The unit test that pinned the row now guards against it being re-added. The removed row's comment also recorded a second-hand report of the same disagreement on MI300X; with the row gone that case would fail visibly on that lane instead of being hidden.Consumers checked
apps/rocm/src/model_fit.rsreads the probe directly and usesrocm_sees_gpuon WSL, so its behavior is unchanged (only its doc comment was wrong after this).crates/rocm-core/src/diagnose.rs: the checks that readhas_amd_gpu(fix-13, Windows only) orhas_apu/has_discrete_amd(fix-9, scoped tolinuxandwindowsin the catalog, with a comment that WSL2 has no per-device topology to collide over) never run on WSL, and the WSL checks usewsl.rocm_sees_gpu.rocm diagnoseon WSL therefore does not depend on the adopted value.rocm examine --jsonadopts the Windows-side value; no otherExaminationconsumer readshas_amd_gpuon WSL, so there is no second call site to keep in step. The field's doc comment anddocs/wsl.mdnow say so.Testing
powershell.exeonPATHthat prints one 8060S display adapter line. Before: JSONhas_amd_gpu: falsebesidedetected_gfx_target: gfx1151, text report "AMD GPU detected". After:true,gpusempty,statuswsl. With no stand-in both forms still agree on no GPU.json has_amd_gpu=false, human detected a gfx target=true) when the call inexamine_cmd.rsis removed.cargo testforrocm-core(lib),rocm(model_fit,examine) ande2e-cucumber(lib);cargo clippy -p rocm-core -p rocm -p e2e-cucumber --all-targets -- -D warnings;cargo fmt --check.cargo test --workspace --all-targets(excludinge2e-cucumber), which passed.python scripts/smoke_local.py.Refs #346 rather than closing it: the issue also asks for the reachable GPU in the
gpuslist and for a usable-memory figure on WSL, and this change does neither.