Skip to content

Restore tracked device resources on their original GPU - #3077

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

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

Conversation

@fallintoplace

Copy link
Copy Markdown
Contributor

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

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9954d5fc-b311-4e35-ad25-8a828840378b

📥 Commits

Reviewing files that changed from the base of the PR and between 7c41eaa and 38ca3a2.

📒 Files selected for processing (5)
  • 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
  • cpp/tests/core/test_memory_resource.hpp

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved GPU memory resource snapshot/restore to be explicitly scoped per CUDA device, ensuring the correct RMM memory resource is reinstalled and restored for each device during construction and destruction.
    • Added safer error handling when restoring per-device resources, with failures now logged instead of propagating.
  • Tests
    • Expanded and updated multi-device unit tests for both memory stats and memory tracking to verify correct per-device preservation/restoration when switching between devices.

Walkthrough

memory_stats_resources and memory_tracking_resources now use explicit CUDA device IDs to snapshot and restore per-device RMM memory resources. Shared test utilities and multi-device tests validate installation and restoration 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
Captures, installs, and restores the device resource through per-device RMM APIs keyed by the resource’s CUDA device ID, logging restoration failures.
memory_tracking_resources per-device restore
cpp/include/raft/core/memory_tracking_resources.hpp
Captures and restores the previous resource and installs the tracked adaptor for the resource’s CUDA device, with exception-safe logging.
Shared multi-device test utilities and coverage
cpp/tests/core/test_memory_resource.hpp, cpp/tests/core/memory_stats_resources.cpp, cpp/tests/core/monitor_resources.cu
Adds reusable per-device resource guards and type checks, then uses them in multi-device tests covering installation and restoration for both wrappers.

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

Suggested reviewers: achirkin, cjnolet

🚥 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 change: restoring tracked resources on the GPU they were created on.
Description check ✅ Passed The description matches the code changes and explains the multi-GPU teardown 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 Outdated

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

@fallintoplace
fallintoplace force-pushed the agent/restore-memory-resource-device branch from 9c78a19 to 7c41eaa Compare July 30, 2026 00:03
@fallintoplace

Copy link
Copy Markdown
Contributor Author

@achirkin Sorry, can you please check again?

@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: 3

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

27-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated test helpers across two translation units. device_resource_restore_guard, current_device_uses_pool_resource, and current_device_uses_default_cuda_resource are defined identically in both files.

  • cpp/tests/core/memory_stats_resources.cpp#L27-L47: move these into a shared test-utility header included by both files.
  • cpp/tests/core/monitor_resources.cu#L28-L48: remove the duplicate definitions and include the shared header instead.
🤖 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 27 - 47, Move
device_resource_restore_guard, current_device_uses_pool_resource, and
current_device_uses_default_cuda_resource from
cpp/tests/core/memory_stats_resources.cpp:27-47 into a shared test-utility
header, then include that header there. Remove the identical definitions from
cpp/tests/core/monitor_resources.cu:28-48 and include the shared header instead,
preserving the existing behavior and symbols.
🤖 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 87-92: Guard the rmm::mr::set_per_device_resource restore call in
both memory_stats_resources::~memory_stats_resources and
memory_tracking_resources::~memory_tracking_resources using RAFT’s no-throw
handling, ensuring exceptions cannot escape either destructor during teardown.
Apply the change in cpp/include/raft/core/memory_stats_resources.hpp lines 87-92
and cpp/include/raft/core/memory_tracking_resources.hpp lines 108-114.

In `@cpp/tests/core/memory_stats_resources.cpp`:
- Around line 176-183: Update the device0 setup around the device0_guard lambda
so the pool_memory_resource and raft::mr::device_resource objects outlive
device0_guard and remain valid while the test uses the restored resource. Store
these resource objects in appropriately scoped variables before calling
set_current_device_resource, matching the lifetime fix used for the analogous
setup near the earlier test block.

In `@cpp/tests/core/monitor_resources.cu`:
- Around line 136-143: Fix the dangling temporary in the device0_guard
initializer by ensuring the pool_memory_resource and raft::mr::device_resource
objects outlive the device_resource_restore_guard, matching the safe lifetime
pattern used around the earlier guard setup. Update the surrounding setup rather
than returning guards that reference temporaries.

---

Nitpick comments:
In `@cpp/tests/core/memory_stats_resources.cpp`:
- Around line 27-47: Move device_resource_restore_guard,
current_device_uses_pool_resource, and current_device_uses_default_cuda_resource
from cpp/tests/core/memory_stats_resources.cpp:27-47 into a shared test-utility
header, then include that header there. Remove the identical definitions from
cpp/tests/core/monitor_resources.cu:28-48 and include the shared header instead,
preserving the existing behavior and symbols.
🪄 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: 8cc561f3-0568-4ed5-8878-7059177b802a

📥 Commits

Reviewing files that changed from the base of the PR and between 381f2d1 and 7c41eaa.

📒 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

Comment thread cpp/include/raft/core/memory_stats_resources.hpp
Comment thread cpp/tests/core/memory_stats_resources.cpp Outdated
Comment thread cpp/tests/core/monitor_resources.cu Outdated
@divyegala

Copy link
Copy Markdown
Contributor

/ok to test 38ca3a2

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.

3 participants