Skip to content

Fix RF multi-stream fits on non-default device - #8131

Draft
csadorf wants to merge 1 commit into
NVIDIA:mainfrom
csadorf:issue-5983-cupy-device-rf-crash
Draft

Fix RF multi-stream fits on non-default device#8131
csadorf wants to merge 1 commit into
NVIDIA:mainfrom
csadorf:issue-5983-cupy-device-rf-crash

Conversation

@csadorf

@csadorf csadorf commented May 18, 2026

Copy link
Copy Markdown
Contributor

Ensures random forest fitting sets the RAFT handle's CUDA device in both the main thread and OpenMP workers, avoiding invalid multi-stream CUDA calls when training data is created under cp.cuda.Device(1). Adds regression coverage for the reported crash and removes the n_streams=1 workaround from the FIL device-selection test.

Closes #5983

@csadorf csadorf added bug Something isn't working non-breaking Non-breaking change labels May 18, 2026
@copy-pr-bot

copy-pr-bot Bot commented May 18, 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.

@github-actions github-actions Bot added Cython / Python Cython or Python issue CUDA/C++ labels May 18, 2026
@csadorf
csadorf changed the base branch from main to release/26.06 May 18, 2026 22:50
@csadorf
csadorf force-pushed the issue-5983-cupy-device-rf-crash branch 2 times, most recently from f197b1a to 3c2352f Compare May 18, 2026 23:02
@csadorf

csadorf commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 3c2352f

@csadorf
csadorf marked this pull request as ready for review May 19, 2026 02:03
@csadorf
csadorf requested review from a team as code owners May 19, 2026 02:03
@csadorf
csadorf requested review from chyunsu3, divyegala and jcrist May 19, 2026 02:03
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

Review Change Stack

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: d4e677f7-b305-4b50-bca0-5f5f245d9a22

📥 Commits

Reviewing files that changed from the base of the PR and between 3c2352f and 7969078.

📒 Files selected for processing (3)
  • cpp/src/randomforest/randomforest.cuh
  • python/cuml/tests/test_fil.py
  • python/cuml/tests/test_random_forest.py

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved GPU device handling during Random Forest training to ensure correct device context when running on multi-GPU systems.
  • Tests

    • Added multi-GPU regression tests verifying device selection and that the CUDA device context is restored after training.
    • Added test coverage using CUDA arrays on non-default devices to validate multi-device workflows.

Walkthrough

RandomForest::fit now sets the CUDA device from the provided raft::handle_t using raft::device_setter for initial pointer validation and installs per-thread device_setter guards inside the OpenMP tree-building loop. Python tests were updated: a prior n_streams=1 workaround was removed and a multi-device CuPy test was added.

Changes

Device Context Management in RandomForest Training

Layer / File(s) Summary
Device context guard in RandomForest::fit
cpp/src/randomforest/randomforest.cuh
Adds raft/core/device_setter.hpp; RandomForest::fit extracts the device from raft::handle_t, constructs a raft::device_setter for initial GPU pointer validation, and installs per-thread raft::device_setter(handle_device) inside the OpenMP parallel tree-building loop before selecting per-thread streams.
Test updates and multi-device regression
python/cuml/tests/test_fil.py, python/cuml/tests/test_random_forest.py
Removes the n_streams=1 argument in test_device_selection, adds import cupy as cp, and introduces test_rf_fit_with_cupy_nondefault_device which fits RandomForest on CuPy arrays allocated on device 1 and verifies the original CUDA device context is restored.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 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
Title check ✅ Passed The title clearly and concisely summarizes the main change: fixing random forest multi-stream fits when training data is created under a non-default CUDA device.
Description check ✅ Passed The description is directly related to the changeset, explaining the fix for CUDA device handling in random forest fitting and mentioning test additions and workaround removal.
Linked Issues check ✅ Passed The PR addresses all objectives from issue #5983: setting RAFT handle's CUDA device in both main and worker threads, adding regression test coverage, and removing the n_streams=1 workaround.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the multi-stream CUDA device issue: the randomforest.cuh changes implement the fix, test_fil.py removes the workaround, and test_random_forest.py adds regression coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@csadorf
csadorf removed the request for review from chyunsu3 May 19, 2026 13:49

@jcrist jcrist left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One concern on correctness.

Beyond that, there are a few other places in the C++ code where we use stream pools across threads. I assume those also need this change applied?

Also, in the original issue (and last time we discussed this) we decided we didn't necessarily want to support users changing the device at runtime this way (and instead wanted users to use CUDA_VISIBLE_DEVICES). If this change doesn't result in any downsides (perf, maintainability, ...) it's probably fine, but otherwise we may want to fix this with docs (and maybe a different way of preventing runtime errors) rather than supporting this.

this->error_checking(input, labels, n_rows, n_cols, false);
const raft::handle_t& handle = user_handle;
int n_sampled_rows = 0;
int handle_device = handle.get_device();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this value cached by the handle? If it is, then it won't get the correct device id on repeated calls if cp.cuda.Device is used to change the device.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch! The device id is usually cached because the handle itself is cached thread-local. However, since by default RandomForestClassifier set the n_streams value to nonzero, it happens to not be cached.

With n_streams > 0, the handle we will be created with a new CUDA stream pool and use the per thread default stream for each thread. The device id will be set on the first call to get_device() based on whatever is the currently active device. That is all to say that this will indeed not work well if we create arrays with one device active, and then run fit with a different device active, but it will generally work for switching devices, but only incidentally because n_streams > 0.

The changes on this PR still have merit since we should generally use the device set by the handle, but we probably have to apply this in a few other cases as well.

Given that – as you correctly assert - we currently don't generally support a workflow for setting devices via cp.cuda.Device() I think we should not merge this PR as-is and instead perform a broader evaluation of this failure class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We will document the expected behavior in #8134 , so I'll just retarget this PR to 26.08 and pick it back up then.

@csadorf csadorf added the DO NOT MERGE Hold off on merging; see PR for details label May 19, 2026
@csadorf
csadorf force-pushed the issue-5983-cupy-device-rf-crash branch from 3c2352f to 7969078 Compare May 20, 2026 15:06
@csadorf
csadorf requested review from a team as code owners May 20, 2026 15:06
@csadorf
csadorf requested a review from jameslamb May 20, 2026 15:06
@csadorf
csadorf changed the base branch from release/26.06 to main May 20, 2026 15:06
@csadorf
csadorf removed request for a team and jameslamb May 20, 2026 15:07
@csadorf
csadorf marked this pull request as draft May 20, 2026 15:08
@copy-pr-bot

copy-pr-bot Bot commented May 20, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@csadorf csadorf removed the DO NOT MERGE Hold off on merging; see PR for details label May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working CUDA/C++ Cython / Python Cython or Python issue non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Encountering raft::cuda_error with cuML's RandomForestClassifier on GPU. (cp.cuda.Device(2).use())

3 participants