Skip to content

fix: retry detecting discrete GPU solving boot race - #194

Open
MaEtUgR wants to merge 1 commit into
OpenGamingCollective:mainfrom
MaEtUgR:discrete-detection-boot-timing
Open

fix: retry detecting discrete GPU solving boot race#194
MaEtUgR wants to merge 1 commit into
OpenGamingCollective:mainfrom
MaEtUgR:discrete-detection-boot-timing

Conversation

@MaEtUgR

@MaEtUgR MaEtUgR commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Problem

Misclassifying nvidia discrete GPU as integrated and disabling Integrated/Smart modes.

Context

Just updated my Asus G14 2025 Ubuntu 26.04 today and built latest cardwire from source.

Sidenote: Had to run the following to get it building because of c5e8dcd:

rustup toolchain install nightly-2026-08-12 --component rust-src
cargo +nightly-2026-08-12 install --locked bpf-linker@0.10.4

After installing and rebooting the option "Integrated" which I'm using most of the time was missing from my AMD/nvidia GPU setup. Also the nvidia GPU was not listed as discrete (and blocked) anymore.

Solution

I asked Claude for a solution and it quickly found that it's a boot race condition where cardwired is started before the nvidia driver is fully initialized. And the one Vulkan/EGL probe query for the nvidia GPU being dicrete returns an error and defaults to integrated instead.

Claude implemented a 10 times retry with 500ms in between for this discrete GPU probing.

Testing

On my setup it seems to always scceed on the second try for the nvidia GPU. The AMD GPU produces the same error instead of reporting being "non-descrete", so it fails 10 times (5 seconds) before defaulting to integrated which is correct delaying the service start which has no side effect in my testing.

I had to manually set "Integrated" mode again after reboot because once cardwire fell back to "Hybrid" mode even just once it would keep that as the user selected option until "Integrated" is available and manually selected again.

Possible alternatives

  1. Delay the detection by I don't know how much time
  2. Have a robust systemd hook for when all GPUs are initialized

Not sure if these are feasible/better.

Checklist:

  • My code follows the style guidelines of this project (cargo fmt)
    Corrects many other files.
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the mdBook documentation
  • My changes generate no new warnings (clippy/clang)
  • New and existing unit tests pass locally with my changes (either use nix flake check or wait for the ci)

to resolve boot race where nvidia driver doesn't yet
report being discrete to Vulkan/EGL probes which
cardwired is already querying.

Misclassifying nvidia discrete GPU as integrated and
disabling Integrated/Smart modes.
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e0ab51ff-d743-4ba1-8d04-ad7e28ee3c3e

📥 Commits

Reviewing files that changed from the base of the PR and between 96dffa5 and 0d4e73c.

📒 Files selected for processing (1)
  • crates/cardwire-daemon/src/core/gpu/enumerator.rs

Included review availability: Your plan includes up to 2 reviews per rolling hour; 1 remains after this review.


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of discrete GPUs during startup.
    • Added automatic retries when GPU information is temporarily unavailable.
    • Avoided unnecessary display probing for devices that cannot be accessed.
    • Increased reliability of GPU classification across systems with delayed or incomplete hardware responses.

Walkthrough

GPU enumeration now uses is_discrete to classify GPUs. The helper checks cached Vulkan data, skips unavailable EGL devices, and retries fresh Vulkan and EGL probes up to 10 times with 500 ms delays.

Changes

Discrete GPU Detection

Layer / File(s) Summary
Retry-aware GPU classification
crates/cardwire-daemon/src/core/gpu/enumerator.rs
build_gpu delegates classification to is_discrete. The helper checks cached Vulkan data, skips EGL when DRM nodes are unavailable, and retries Vulkan and EGL probes before reporting failure. Duration provides the retry interval.

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

Merge Risk: ⚪ Minimal · up to 0d4e7

This change retries GPU classification to handle startup timing; no actionable merge-blocking risk remains based on the supplied evidence.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: retrying discrete-GPU detection to resolve a boot race.
Description check ✅ Passed The description explains the problem, solution, motivation, testing, alternatives, and checklist status; only the related issue reference is missing.

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.

❤️ Share

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

@luytan

luytan commented Aug 19, 2026

Copy link
Copy Markdown
Member

instead of having a retry loop, can't we wait for the device to be initialized before scanning it? drm_node_ids does it (with a retry loop that i wanted to get rid of), maybe we could just add it directly into the build_gpu() function

if !dev.is_initialized() {
continue;
}

@MaEtUgR

MaEtUgR commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

I agree, preferring not to have retry loops. I'm not very familiar enough with linux device management but I hammered Claude and apparently a straight "wait for is_initialized() then scan once" isn't enough, based on log output on my hybrid NVIDIA/AMD Asus G14 laptop:

15:29:44  DRM nodes ... attempt 6/10 → resolved            (DRM ready)
15:29:44  GB203M: EGL discrete check failed, attempt 1/10  (Vulkan/EGL still not ready)
15:29:45  → resolved via Vulkan retry on the very next loop iteration
  • is_initialized() only confirms udev finished processing the DRM node's uevent. It doesn't guarantee Vulkan can enumerate the GPU yet. On this machine there's a real ~0.5–1s gap after the node initializes before Vulkan sees it, NVIDIA's GSP firmware (Blackwell+) boots asynchronously after the node exists, AMD has a similar post-node firmware/ring init. Neither publishes a portable "ready" signal, so there's no safe way to do a single wait-then-scan across these GPUs.
  • Across every boot I tested, the EGL discrete-type query never once succeeded on either GPU, only the Vulkan retry ever resolved anything. So based on that, EGL doesn't need its own retry loop, just a single attempt.

Looking for better solutions but haven't found any yet. Possibly we could have one poll for everything to be ready 👀

@luytan
luytan self-requested a review August 20, 2026 20:44
@luytan

luytan commented Aug 20, 2026

Copy link
Copy Markdown
Member

maybe we should find a way to WAIT for the amdgpu/nvidia drivers before scanning GPUs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants