Skip to content

Restore tracked device resources on their original GPU#3077

Open
fallintoplace wants to merge 4 commits into
NVIDIA:mainfrom
fallintoplace:agent/restore-memory-resource-device
Open

Restore tracked device resources on their original GPU#3077
fallintoplace wants to merge 4 commits into
NVIDIA:mainfrom
fallintoplace:agent/restore-memory-resource-device

Conversation

@fallintoplace

Copy link
Copy Markdown

Summary

  • restore memory_stats_resources and memory_tracking_resources device memory resources to the CUDA device they wrapped at construction time
  • switch the destructor restore path to rmm::mr::set_per_device_resource(...) using the captured device id
  • add guarded 2-GPU regressions that destroy each wrapper while a different CUDA device is current

Why

Both wrappers used rmm::mr::set_current_device_resource(...) during teardown. In multi-GPU flows that writes the saved resource into whichever CUDA device is current at destruction time, which can leave the construction device pointing at the tracking adaptor and install the wrong resource on another GPU.

Impact

This keeps per-device RMM state stable across wrapper teardown and closes a nasty multi-GPU correctness hole that could otherwise lead to wrong-device allocators being reused.

Validation

  • git diff --check
  • attempted PARALLEL_LEVEL=8 ./build.sh tests -n --limit-tests=CORE_TEST
  • local build is currently blocked by missing nvcc / CUDAToolkit_ROOT, so the new tests were not run here

@copy-pr-bot

copy-pr-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved GPU memory resource snapshot/restore to use explicit per-device state (instead of “current device”), ensuring the correct resource is reinstalled for each CUDA device after construction/destruction.
  • Tests
    • Added/updated multi-GPU coverage for both memory stats and memory tracking to verify behavior across device boundaries, including proper preservation/restoration when switching between device 0 and device 1.

Walkthrough

memory_stats_resources and memory_tracking_resources now use an explicit CUDA device ID to snapshot and restore the RMM memory resource for that device. New tests add per-device restore guards and validate the behavior across two CUDA devices.

Changes

Per-device resource restoration

Layer / File(s) Summary
memory_stats_resources per-device restore
cpp/include/raft/core/memory_stats_resources.hpp
Adds device ID lookup and changes constructor, destructor, and initialization resource handling to use per-device RMM access for the identified device.
memory_tracking_resources per-device restore
cpp/include/raft/core/memory_tracking_resources.hpp
Adds device ID lookup and changes constructor, destructor, and initialization resource handling to use per-device resource access and restoration for the identified CUDA device.
Multi-device restoration tests
cpp/tests/core/memory_stats_resources.cpp, cpp/tests/core/monitor_resources.cu
Adds RAII helpers that restore per-device resources and new GoogleTest cases that scope execution to device 0, then verify device-specific resource types after destruction on devices 0 and 1.

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

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% 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
Title check ✅ Passed The title clearly summarizes the main multi-GPU device-resource restore change.
Description check ✅ Passed The description is directly related to the per-device resource restore fix and added regression tests.
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

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

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

Thank you for uncovering this! The memory tracking/statistics APIs are rather new and haven't been properly tested in multi-gpu environment yet.

In the context of raft::resources handle we already have access to a "device id" resource (core/resource/device_id.hpp) stored per resources handle. Therefore, there's no need for an extra member variable duplicating this information (see below). Please adjust both files to use this resource instead.

{
mr::set_default_host_resource(old_host_);
rmm::mr::set_current_device_resource(std::move(old_device_));
rmm::mr::set_per_device_resource(rmm::cuda_device_id{device_id_}, std::move(old_device_));

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.

core/resource/device_id.hpp is the source of truth for the GPU device associated with the handle:

Suggested change
rmm::mr::set_per_device_resource(rmm::cuda_device_id{device_id_}, std::move(old_device_));
rmm::mr::set_per_device_resource(resource::get_device_id(*this), std::move(old_device_));

: resources(existing),
device_id_(device_setter::get_current_device()),
old_host_(mr::get_default_host_resource()),
old_device_(rmm::mr::get_current_device_resource_ref())

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.

Calling resource::get_device_id() on the current handle ensures the device id resource is instantiated and won't mutate until the resource is destroyed.

Suggested change
old_device_(rmm::mr::get_current_device_resource_ref())
old_device_(rmm::mr::get_per_device_resource_ref(resource::get_device_id(existing)))

@achirkin achirkin self-assigned this Jul 9, 2026
@achirkin achirkin added bug Something isn't working non-breaking Non-breaking change labels Jul 9, 2026
@achirkin

achirkin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

/ok to test b0ddd70

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cpp/include/raft/core/memory_tracking_resources.hpp (1)

108-114: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Install the tracking MR on the handle’s device id
init() still uses rmm::mr::set_current_device_resource(*device_adaptor_), so a copied resources handle can install the adaptor on the wrong GPU while capture/restore is keyed off resource::get_device_id(*this). Use set_per_device_resource(rmm::cuda_device_id{resource::get_device_id(*this)}, *device_adaptor_) here too.

🤖 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 `@cpp/include/raft/core/memory_tracking_resources.hpp` around lines 108 - 114,
The destructor in memory_tracking_resources currently restores the per-device
resource using the tracked device id, but the corresponding installation path in
init() still uses the current device instead of the handle’s device id. Update
the resource installation logic in memory_tracking_resources::init() to use
rmm::mr::set_per_device_resource with
rmm::cuda_device_id{resource::get_device_id(*this)} and the device adaptor,
matching the handle’s device binding used elsewhere.

Sources: Coding guidelines, Path instructions

🤖 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 `@cpp/include/raft/core/memory_stats_resources.hpp`:
- Around line 81-91: The device-specific resource management in
memory_stats_resources is using resource::get_device_id(*this) for restore while
set_current_device_resource() installs on the active CUDA device, so they can
target different GPUs. Update memory_stats_resources so the same device id is
used consistently for both installation and restoration, and keep the
save/restore logic aligned with the device captured in the constructor and
destructor.

---

Outside diff comments:
In `@cpp/include/raft/core/memory_tracking_resources.hpp`:
- Around line 108-114: The destructor in memory_tracking_resources currently
restores the per-device resource using the tracked device id, but the
corresponding installation path in init() still uses the current device instead
of the handle’s device id. Update the resource installation logic in
memory_tracking_resources::init() to use rmm::mr::set_per_device_resource with
rmm::cuda_device_id{resource::get_device_id(*this)} and the device adaptor,
matching the handle’s device binding used elsewhere.
🪄 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: CHILL

Plan: Enterprise

Run ID: 113e8e7c-4498-49d5-bd87-7c71dd889a4c

📥 Commits

Reviewing files that changed from the base of the PR and between b0ddd70 and 7980f7c.

📒 Files selected for processing (2)
  • cpp/include/raft/core/memory_stats_resources.hpp
  • cpp/include/raft/core/memory_tracking_resources.hpp

Comment thread cpp/include/raft/core/memory_stats_resources.hpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
cpp/tests/core/memory_stats_resources.cpp (1)

37-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated test helper code across two files.

current_device_uses_pool_resource()/current_device_uses_default_cuda_resource() and the device_resource_restore_guard struct (lines 27-48) are duplicated verbatim in cpp/tests/core/monitor_resources.cu. Consider extracting these into a shared test utility header (e.g., cpp/tests/core/device_resource_test_utils.hpp) to avoid future divergence between the two test files.

🤖 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 `@cpp/tests/core/memory_stats_resources.cpp` around lines 37 - 48, The helper
functions current_device_uses_pool_resource(),
current_device_uses_default_cuda_resource(), and the
device_resource_restore_guard in this test file are duplicated in
monitor_resources.cu, so extract them into a shared test utility header (for
example, device_resource_test_utils.hpp) and update both test files to include
and use the shared helpers instead of maintaining separate copies. Keep the
existing behavior intact by moving the duplicated device resource checks and
guard logic into the common utility.
🤖 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 `@cpp/tests/core/memory_stats_resources.cpp`:
- Around line 37-48: The helper functions current_device_uses_pool_resource(),
current_device_uses_default_cuda_resource(), and the
device_resource_restore_guard in this test file are duplicated in
monitor_resources.cu, so extract them into a shared test utility header (for
example, device_resource_test_utils.hpp) and update both test files to include
and use the shared helpers instead of maintaining separate copies. Keep the
existing behavior intact by moving the duplicated device resource checks and
guard logic into the common utility.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0f5967f3-e6ac-4fd2-bde8-da3e92e49405

📥 Commits

Reviewing files that changed from the base of the PR and between 7980f7c and 381f2d1.

📒 Files selected for processing (4)
  • cpp/include/raft/core/memory_stats_resources.hpp
  • cpp/include/raft/core/memory_tracking_resources.hpp
  • cpp/tests/core/memory_stats_resources.cpp
  • cpp/tests/core/monitor_resources.cu
🚧 Files skipped from review as they are similar to previous changes (2)
  • cpp/include/raft/core/memory_tracking_resources.hpp
  • cpp/include/raft/core/memory_stats_resources.hpp

@achirkin

achirkin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

/ok to test

@copy-pr-bot

copy-pr-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

/ok to test

@achirkin, there was an error processing your request: E1

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/1/

@fallintoplace

Copy link
Copy Markdown
Author

If something comes up, let me know.

@achirkin

Copy link
Copy Markdown
Contributor

/ok to test 381f2d1

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

Thanks for the updates! LGTM

@achirkin

Copy link
Copy Markdown
Contributor

/ok to test 3242e55

@achirkin

Copy link
Copy Markdown
Contributor

@fallintoplace could you please apply the style fixes? pre-commit run --all-files

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

Labels

bug Something isn't working non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants