Skip to content

[cuda] fix: align visible mask prefix parsing - #221

Merged
Wangmerlyn merged 1 commit into
mainfrom
codex/cuda-visible-prefix-mask-parity
Jul 1, 2026
Merged

[cuda] fix: align visible mask prefix parsing#221
Wangmerlyn merged 1 commit into
mainfrom
codex/cuda-visible-prefix-mask-parity

Conversation

@Wangmerlyn

@Wangmerlyn Wangmerlyn commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • Align CUDA visibility parsing with CUDA runtime behavior by accepting unique GPU UUID prefixes and truncating CUDA_VISIBLE_DEVICES at -1 after any valid prefix.
  • Centralize NVML UUID text/handle resolution in cuda_visibility.py and share it across GPU listing and utilization telemetry.
  • Keep ambiguous, malformed, unresolved, duplicate, unsupported, and out-of-range masks fail-closed so eco-safe backoff applies instead of guessing a physical GPU.
  • Update AGENTS.md and published docs for CLI, Python API, MCP, architecture, and API reference behavior.

Local Review

  • CUDA/NVML correctness review: no Critical, Important, or Minor findings; ready for PR.
  • Docs/tests small-repo review: initial docs consistency blocker fixed; follow-up review reported no Critical, Important, or Minor findings; ready for PR.

Test Plan

  • RED before implementation: new UUID-prefix and -1 truncation tests failed as expected.
  • PYTHONPATH=$PWD/src pytest tests/utilities/test_gpu_info.py tests/utilities/test_gpu_monitor.py -q -> 83 passed, 1 skipped
  • PYTHONPATH=$PWD/src pytest -q -> 842 passed, 11 skipped
  • pre-commit run --all-files --show-diff-on-failure -> passed
  • PYTHONPATH=$PWD/src mkdocs build --strict -> passed with the known Material for MkDocs 2.0 warning
  • git diff --check -> passed

Summary by CodeRabbit

  • New Features

    • CUDA visibility handling now supports unique UUID prefixes and stops parsing at -1 after valid entries.
    • Documentation was expanded to explain how GPU telemetry is resolved across CUDA and ROCm environments.
  • Bug Fixes

    • Ambiguous, malformed, duplicate, or out-of-range device masks now fail safely instead of guessing a GPU.
    • Telemetry behavior now more consistently matches the devices shown to users, improving accuracy for GPU listing and monitoring.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Wangmerlyn, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3de4e975-182d-47d7-b628-af73d124996d

📥 Commits

Reviewing files that changed from the base of the PR and between 9436a1b and 4e3b222.

📒 Files selected for processing (13)
  • AGENTS.md
  • docs/concepts/architecture.md
  • docs/getting-started.md
  • docs/guides/mcp.md
  • docs/guides/python.md
  • docs/plans/cuda-visible-prefix-mask-parity.md
  • docs/reference/api.md
  • docs/reference/cli.md
  • src/keep_gpu/utilities/cuda_visibility.py
  • src/keep_gpu/utilities/gpu_info.py
  • src/keep_gpu/utilities/gpu_monitor.py
  • tests/utilities/test_gpu_info.py
  • tests/utilities/test_gpu_monitor.py
📝 Walkthrough

Walkthrough

This PR changes CUDA_VISIBLE_DEVICES mask parsing to accept unique UUID prefixes and stop parsing at -1, adds shared NVML UUID-lookup helper functions in cuda_visibility.py, wires them into gpu_info.py and gpu_monitor.py replacing duplicated local helpers, adds corresponding tests, and updates documentation across multiple files plus a new planning document.

Changes

CUDA UUID-prefix and -1 truncation parity

Layer / File(s) Summary
Mask parsing and NVML UUID helpers
src/keep_gpu/utilities/cuda_visibility.py
Token parsing stops at first -1 token; new decode_nvml_text, lookup_nvml_uuid_handle, lookup_nvml_uuid_prefix_handle functions added and exported.
Wiring into gpu_info and gpu_monitor
src/keep_gpu/utilities/gpu_info.py, src/keep_gpu/utilities/gpu_monitor.py
Local duplicate UUID decode/lookup helpers removed; both modules now import and use the shared cuda_visibility helpers for NVML UUID resolution.
Tests for UUID-prefix and -1 truncation
tests/utilities/test_gpu_info.py, tests/utilities/test_gpu_monitor.py
Mock NVML classes gain uuid_by_index and nvmlDeviceGetUUID; new/updated tests cover unique/ambiguous UUID-prefix masks and -1 truncation behavior.
Documentation updates
AGENTS.md, docs/concepts/architecture.md, docs/getting-started.md, docs/guides/mcp.md, docs/guides/python.md, docs/reference/api.md, docs/reference/cli.md, docs/plans/cuda-visible-prefix-mask-parity.md
Docs updated to describe UUID-prefix acceptance, -1 stop behavior, and fail-closed (unavailable telemetry) outcomes for malformed/ambiguous masks; new plan document added.

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

Sequence Diagram(s)

sequenceDiagram
  participant NVMLMonitor
  participant lookup_nvml_uuid_handle
  participant NVML
  participant lookup_nvml_uuid_prefix_handle

  NVMLMonitor->>lookup_nvml_uuid_handle: resolve token from CUDA_VISIBLE_DEVICES
  lookup_nvml_uuid_handle->>NVML: nvmlDeviceGetHandleByUUID(token)
  alt direct match found
    NVML-->>lookup_nvml_uuid_handle: handle
  else lookup unsupported/failed
    lookup_nvml_uuid_handle->>lookup_nvml_uuid_prefix_handle: fallback with token
    lookup_nvml_uuid_prefix_handle->>NVML: enumerate device UUIDs
    NVML-->>lookup_nvml_uuid_prefix_handle: UUID list
    alt exactly one prefix match
      lookup_nvml_uuid_prefix_handle-->>lookup_nvml_uuid_handle: handle
    else zero or multiple matches
      lookup_nvml_uuid_prefix_handle-->>lookup_nvml_uuid_handle: None
    end
  end
  lookup_nvml_uuid_handle-->>NVMLMonitor: handle or None (unavailable telemetry)
Loading

Possibly related PRs

  • Wangmerlyn/KeepGPU#110: Both PRs implement fail-closed CUDA_VISIBLE_DEVICES telemetry behavior rejecting malformed/ambiguous UUID-prefix masks with shared NVML UUID-handle lookup logic.
  • Wangmerlyn/KeepGPU#135: Both PRs modify CUDA telemetry resolution in src/keep_gpu/utilities/gpu_info.py around NVML-visible ordinal enumeration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: aligning CUDA visible mask prefix parsing.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cuda-visible-prefix-mask-parity

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.

@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.

🧹 Nitpick comments (2)
src/keep_gpu/utilities/gpu_info.py (1)

115-157: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant try/except around lookup_nvml_uuid_handle call.

lookup_nvml_uuid_handle(pynvml, token) is called without should_reraise, so internally it never re-raises (all internal exceptions are swallowed and it returns None). The wrapping try/except Exception: handle = None at Line 122-125 is therefore effectively dead code.

🤖 Prompt for 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.

In `@src/keep_gpu/utilities/gpu_info.py` around lines 115 - 157, The try/except
around lookup_nvml_uuid_handle in _resolve_nvml_visible_handles is redundant
because that helper already swallows internal failures and returns None when
should_reraise is not set. Remove the dead exception handling and keep the
existing None check/early return flow, leaving the rest of the handle resolution
logic unchanged.
tests/utilities/test_gpu_monitor.py (1)

424-477: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Repeated list(range(8)) magic literal across assertions.

dummy.queried_indexes == list(range(8)) appears at lines 318, 430, and 488, hardcoding the DummyNVML default count=8. Deriving it from dummy.count would keep the assertions correct if the default ever changes.

♻️ Example
-    assert dummy.queried_indexes == list(range(8))
+    assert dummy.queried_indexes == list(range(dummy.count))
🤖 Prompt for 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.

In `@tests/utilities/test_gpu_monitor.py` around lines 424 - 477, The repeated
hardcoded queried-index assertion in the NVML monitor tests should be derived
from the dummy’s configured count instead of assuming eight. Update the
assertions in the affected test cases under test_gpu_monitor.py to use the
DummyNVML instance’s count (or an equivalent shared value) when checking
NVMLMonitor.get_gpu_utilization behavior, so the expectation stays aligned with
the DummyNVML default and any future count changes. Use the existing DummyNVML
and NVMLMonitor symbols to locate and adjust the repeated assertions.
🤖 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.

Nitpick comments:
In `@src/keep_gpu/utilities/gpu_info.py`:
- Around line 115-157: The try/except around lookup_nvml_uuid_handle in
_resolve_nvml_visible_handles is redundant because that helper already swallows
internal failures and returns None when should_reraise is not set. Remove the
dead exception handling and keep the existing None check/early return flow,
leaving the rest of the handle resolution logic unchanged.

In `@tests/utilities/test_gpu_monitor.py`:
- Around line 424-477: The repeated hardcoded queried-index assertion in the
NVML monitor tests should be derived from the dummy’s configured count instead
of assuming eight. Update the assertions in the affected test cases under
test_gpu_monitor.py to use the DummyNVML instance’s count (or an equivalent
shared value) when checking NVMLMonitor.get_gpu_utilization behavior, so the
expectation stays aligned with the DummyNVML default and any future count
changes. Use the existing DummyNVML and NVMLMonitor symbols to locate and adjust
the repeated assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a2db652-3829-47f8-86c5-166532deba00

📥 Commits

Reviewing files that changed from the base of the PR and between f346258 and 9436a1b.

📒 Files selected for processing (13)
  • AGENTS.md
  • docs/concepts/architecture.md
  • docs/getting-started.md
  • docs/guides/mcp.md
  • docs/guides/python.md
  • docs/plans/cuda-visible-prefix-mask-parity.md
  • docs/reference/api.md
  • docs/reference/cli.md
  • src/keep_gpu/utilities/cuda_visibility.py
  • src/keep_gpu/utilities/gpu_info.py
  • src/keep_gpu/utilities/gpu_monitor.py
  • tests/utilities/test_gpu_info.py
  • tests/utilities/test_gpu_monitor.py

@Wangmerlyn
Wangmerlyn force-pushed the codex/cuda-visible-prefix-mask-parity branch from 9436a1b to 4e3b222 Compare July 1, 2026 03:47
@Wangmerlyn
Wangmerlyn merged commit d179883 into main Jul 1, 2026
6 checks passed
@Wangmerlyn
Wangmerlyn deleted the codex/cuda-visible-prefix-mask-parity branch July 1, 2026 03:51
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.

1 participant