Merge raft_proto into nvforest namespace - #132
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughChangesNamespace and library migration
Estimated code review effort: 4 (Complex) | ~60 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
cpp/include/nvforest/cuda_stream.hpp (1)
16-20:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPropagate CUDA synchronization failures from
nvforest::synchronize
cpp/include/nvforest/cuda_stream.hppcallscudaStreamSynchronize(stream)and drops the returnedcudaError_t, making CUDA failures silent at the API boundary (Line 19).Suggested fix
`#ifdef` NVFOREST_ENABLE_GPU `#include` <cuda_runtime_api.h> +#include <nvforest/detail/cuda_check.hpp> `#endif` @@ `#ifdef` NVFOREST_ENABLE_GPU - cudaStreamSynchronize(stream); + detail::cuda_check<device_type::gpu>(cudaStreamSynchronize(stream)); `#endif` }🤖 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/nvforest/cuda_stream.hpp` around lines 16 - 20, The synchronize function currently ignores the cudaStreamSynchronize return value, so CUDA errors are dropped; update inline void synchronize(cuda_stream stream) to capture the cudaError_t result from cudaStreamSynchronize, check it, and propagate failures (either change the signature to return cudaError_t or throw a std::runtime_error on non-success). Concretely, in synchronize call cudaError_t err = cudaStreamSynchronize(stream); if (err != cudaSuccess) throw std::runtime_error(std::string("cudaStreamSynchronize failed: ") + cudaGetErrorString(err)); — reference symbols: synchronize, cudaStreamSynchronize, cudaError_t, cudaGetErrorString.cpp/include/nvforest/detail/exceptions.hpp (1)
8-56:⚠️ Potential issue | 🟠 MajorRestore public exception names (
nvforest::bad_cuda_call, etc.) or provide aliases innvforest/exceptions.hpp.
cpp/include/nvforest/exceptions.hppdefines onlynvforest::{model_import_error,type_error,traversal_exception,runtime_error}and does not re-export/aliasnvforest::detail::{bad_cuda_call,out_of_bounds,wrong_device_type,mem_type_mismatch,wrong_device}. This makes the namespace move a downstream-breaking exception API change rather than a merge.🤖 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/nvforest/detail/exceptions.hpp` around lines 8 - 56, The public API lost symbols when exception types were moved into nvforest::detail; restore the original nvforest::* names by adding aliases in the public header (nvforest/exceptions.hpp): create using declarations that map nvforest::bad_cuda_call, out_of_bounds, wrong_device_type, mem_type_mismatch, and wrong_device to their nvforest::detail:: counterparts (e.g., using bad_cuda_call = detail::bad_cuda_call;), ensure the header includes or forward-declares nvforest::detail types so the aliases compile, and keep the original exception type names visible in the nvforest namespace to avoid breaking downstream code.cpp/include/nvforest/detail/infer/gpu.hpp (1)
13-24:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd missing
<type_traits>include forstd::enable_if_t
cpp/include/nvforest/detail/infer/gpu.hppusesstd::enable_if_tin theinfertemplate declaration but doesn’t include<type_traits>, relying on transitive includes.Proposed fix
`#include` <cstddef> `#include` <optional> +#include <type_traits>🤖 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/nvforest/detail/infer/gpu.hpp` around lines 13 - 24, The header declares the infer template using std::enable_if_t (template signature with device_type D and infer(...)) but omits the required <type_traits> include; add `#include` <type_traits> near the other includes so std::enable_if_t is defined (ensuring the declaration of template <device_type D, bool has_categorical_nodes, typename forest_t, ...> std::enable_if_t<D == device_type::gpu, void> infer(...) compiles without relying on transitive includes).cpp/include/nvforest/handle.hpp (1)
16-29:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject null GPU
raft_handle_innvforest::handle_tIn
NVFOREST_ENABLE_GPUbuilds,nvforest::handle_t’s constructor defaultshandle_ptrtonullptr, butget_next_usable_stream(),get_stream_pool_size(), andsynchronize()dereferenceraft_handle_unconditionally.forest_model::predict()callshandle.get_next_usable_stream()/handle.get_usable_stream_count()without guarding, sonvforest::handle_t{}will crash on the first inference. Tests use a realraft::handle_t, but the README showsauto handle = nvforest::handle_t{};, which is unsafe for GPU builds.Proposed fix
+#include <stdexcept> + struct handle_t { - handle_t(raft::handle_t const* handle_ptr = nullptr) : raft_handle_{handle_ptr} {} + handle_t() = delete; + explicit handle_t(raft::handle_t const* handle_ptr) : raft_handle_{handle_ptr} + { + if (handle_ptr == nullptr) { throw std::invalid_argument("handle_ptr must not be null"); } + } handle_t(raft::handle_t const& raft_handle) : raft_handle_{&raft_handle} {}Also update the public docs/README to reflect GPU builds must construct
nvforest::handle_tfrom a validraft::handle_t.🤖 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/nvforest/handle.hpp` around lines 16 - 29, The constructor handle_t(raft::handle_t const* handle_ptr = nullptr) currently allows a null raft_handle_ but methods get_next_usable_stream, get_stream_pool_size, get_usable_stream_count and synchronize dereference it unconditionally; change the ctor to reject null (e.g., remove the default nullptr and/or throw std::invalid_argument or assert when handle_ptr==nullptr) so a nvforest::handle_t must be constructed from a valid raft::handle_t, and update the public README to state GPU builds require constructing nvforest::handle_t from an existing raft::handle_t (also audit usages of nvforest::handle_t{} in tests/docs and replace with an explicit valid raft::handle_t where needed).cpp/include/nvforest/README.md (1)
46-70:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUnify parameter naming for the device-type argument.
Line 46 labels the argument as
mem_type, but Line 70 documents it asdev_type. Please use one name consistently in both the example and the argument docs.Suggested doc tweak
-**dev_type**: This argument controls where the model will be executed. If `nvforest::device_type::gpu`, then it will be executed on GPU. If `nvforest::device_type::cpu`, then it will be executed on CPU. +**mem_type**: This argument controls where the model will be executed. If `nvforest::device_type::gpu`, then it will be executed on GPU. If `nvforest::device_type::cpu`, then it will be executed on CPU.As per coding guidelines, "Consistency: Version numbers, parameter types, and terminology match 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 `@cpp/include/nvforest/README.md` around lines 46 - 70, The docs use two different names for the device argument—`mem_type` in the example call comment and `dev_type` in the parameter description—so make them consistent: pick one name (prefer `dev_type`) and update the example comment `// mem_type` to `// dev_type` and any occurrences in the descriptive section (`mem_type` -> `dev_type`), ensuring references like `nvforest::device_type::gpu` remain unchanged and the parameter description that begins "dev_type: This argument controls where the model will be executed..." matches the example and wording elsewhere.cpp/include/nvforest/treelite_importer.hpp (1)
515-529:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGuard against a null
TreeliteModelHandle.This wrapper dereferences
tl_handleunconditionally. If a caller passesnullptr, the public API segfaults instead of raising a model import error.Suggested fix
inline auto import_from_treelite_handle(TreeliteModelHandle tl_handle, tree_layout layout = preferred_tree_layout, index_type align_bytes = index_type{}, std::optional<bool> use_double_precision = std::nullopt, nvforest::device_type dev_type = nvforest::device_type::cpu, int device = 0, nvforest::cuda_stream stream = nvforest::cuda_stream{}) { + if (tl_handle == nullptr) { + throw model_import_error{"Treelite model handle must not be null"}; + } return import_from_treelite_model(*static_cast<treelite::Model*>(tl_handle), layout, align_bytes, use_double_precision, dev_type, device, stream); }🤖 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/nvforest/treelite_importer.hpp` around lines 515 - 529, The wrapper import_from_treelite_handle dereferences tl_handle without checking for nullptr; add a null check at the start of import_from_treelite_handle and if tl_handle is null throw a suitable exception (e.g. std::invalid_argument or a library-specific import error) with a clear message like "null TreeliteModelHandle"; only call import_from_treelite_model(*static_cast<treelite::Model*>(tl_handle), ...) when tl_handle is non-null to avoid segfaults.cpp/include/nvforest/buffer.hpp (1)
329-339:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winThe checked copy guard underflows when an offset is already out of range.
These comparisons subtract
size_tvalues before proving thatsrc_offset <= src.size()anddst_offset <= dst.size(). If either offset is already too large, the subtraction wraps and the check passes, turning the “checked” overloads into out-of-bounds copies.Suggested fix
if constexpr (bounds_check) { - if (src.size() - src_offset < size || dst.size() - dst_offset < size) { + if (src_offset > src.size() || dst_offset > dst.size() || + src.size() - src_offset < size || dst.size() - dst_offset < size) { throw detail::out_of_bounds("Attempted copy to or from buffer of inadequate size"); } }Apply the same guard to the rvalue-overload block below as well.
Also applies to: 361-372
🤖 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/nvforest/buffer.hpp` around lines 329 - 339, The bounds check in the checked copy path incorrectly subtracts size_t values (src.size() - src_offset and dst.size() - dst_offset) before verifying the offsets are in range, which underflows when src_offset or dst_offset > src.size()/dst.size(); update the guard in the copy(...) path to first assert src_offset <= src.size() and dst_offset <= dst.size() (or check offsets against sizes) and only then compare remaining sizes against size, and apply the identical fix to the rvalue-overload block (the subsequent copy(...) overload around the rvalue overload lines) so both checked overloads prevent underflow.cpp/include/nvforest/detail/infer/gpu.cuh (1)
153-163:⚠️ Potential issue | 🟠 Major | ⚡ Quick winHandle the zero-shared-memory path before the occupancy math.
shared_mem_per_blockcan be 0 here when output falls back to global workspace and rows are not staged in shared memory. In that caseceildiv(max_shared_mem_per_sm, shared_mem_per_block)divides by zero, and the later "divide shared mem evenly" step has the same problem.Suggested fix
- auto resident_blocks_per_sm = - min(ceildiv(max_shared_mem_per_sm, shared_mem_per_block), max_resident_blocks); + auto resident_blocks_per_sm = + (shared_mem_per_block == 0) + ? max_resident_blocks + : min(ceildiv(max_shared_mem_per_sm, shared_mem_per_block), max_resident_blocks); @@ - shared_mem_per_block = std::min( - max_overall_shared_mem, max_shared_mem_per_sm / (max_shared_mem_per_sm / shared_mem_per_block)); + if (shared_mem_per_block != 0) { + shared_mem_per_block = std::min( + max_overall_shared_mem, + max_shared_mem_per_sm / (max_shared_mem_per_sm / shared_mem_per_block)); + }🤖 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/nvforest/detail/infer/gpu.cuh` around lines 153 - 163, shared_mem_per_block can be zero (when output_workspace_size_bytes and row staging were cleared), so the occupancy math calling ceildiv(max_shared_mem_per_sm, shared_mem_per_block) and the later "divide shared mem evenly" step will divide by zero; add an early guard after computing shared_mem_per_block to detect shared_mem_per_block == 0 and handle that path explicitly (for example set resident_blocks_per_sm = max_resident_blocks or another safe default and skip any further divisions that distribute shared memory per block), and ensure any subsequent logic that divides by shared_mem_per_block or expects nonzero shared bytes checks this flag; update references around shared_mem_per_block, resident_blocks_per_sm, ceildiv, and the later "divide shared mem evenly" calculations to use this guarded path.
🧹 Nitpick comments (3)
cpp/include/nvforest/device_type.hpp (1)
7-7: ⚡ Quick winAdd Doxygen docs for the new public
device_typeenum.Line 7 introduces a public API type without a doc comment. Please add a brief Doxygen block describing valid values and intended usage.
Suggested update
namespace nvforest { +/** + * `@brief` Execution target for inference routines. + */ enum class device_type { cpu, gpu }; } // namespace nvforestAs per coding guidelines, "For public header files (C++ API): Check if new public functions/classes have documentation comments (Doxygen format)".
🤖 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/nvforest/device_type.hpp` at line 7, Add a Doxygen comment block immediately above the public enum class device_type describing that it represents the execution device for NVForest operations, listing the valid enum values (cpu and gpu) with a short description for each, and note intended usage (e.g., selecting target device for computation or resource allocation). Use brief `@enum/`@brief style tags and mention any default behavior or constraints if applicable so the public API is documented for users.cpp/include/nvforest/detail/device_setter.hpp (1)
6-10: 💤 Low valueConsider reordering includes to place dependencies first.
The include order places
device_type.hppafterdevice_setter/base.hppanddevice_setter/gpu.hpp. If these headers depend ondevice_type, it would be clearer to includedevice_type.hppfirst.♻️ Suggested include order
`#pragma` once +#include <nvforest/device_type.hpp> `#include` <nvforest/detail/device_setter/base.hpp> `#ifdef` NVFOREST_ENABLE_GPU `#include` <nvforest/detail/device_setter/gpu.hpp> `#endif` -#include <nvforest/device_type.hpp>🤖 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/nvforest/detail/device_setter.hpp` around lines 6 - 10, Reorder the includes in device_setter.hpp so that the dependency header device_type.hpp is included before device_setter/base.hpp and device_setter/gpu.hpp; specifically, move the include for nvforest/device_type.hpp above the includes for nvforest/detail/device_setter/base.hpp and (conditionally) nvforest/detail/device_setter/gpu.hpp to ensure device_type is available to the base and gpu headers (symbols: device_setter.hpp, device_setter::base, device_setter::gpu, and device_type.hpp).cpp/include/nvforest/detail/specializations/device_initialization_macros.hpp (1)
11-13: ⚡ Quick winFully qualify the generated nvforest types.
This macro now depends on the expansion site already being inside
namespace nvforest. Emitting::nvforest::device_typeand::nvforest::device_idkeeps it stable if an instantiation moves or lives at global scope.Proposed fix
`#define` NVFOREST_INITIALIZE_DEVICE(template_type, variant_index) \ - template_type void initialize_device<NVFOREST_FOREST(variant_index), device_type::gpu>( \ - device_id<device_type::gpu>); + template_type void \ + initialize_device<NVFOREST_FOREST(variant_index), ::nvforest::device_type::gpu>( \ + ::nvforest::device_id<::nvforest::device_type::gpu>);🤖 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/nvforest/detail/specializations/device_initialization_macros.hpp` around lines 11 - 13, The macro NVFOREST_INITIALIZE_DEVICE emits types like device_type and device_id without global qualification, which breaks if the expansion isn't inside namespace nvforest; update the macro so generated symbols in initialize_device<NVFOREST_FOREST(variant_index), device_type::gpu>(device_id<device_type::gpu>) are fully qualified (e.g., ::nvforest::device_type and ::nvforest::device_id and any other nvforest symbols referenced) so the instantiation is stable regardless of the expansion scope.
🤖 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/CMakeLists.txt`:
- Line 126: The exported CMake target name changed and you need to restore a
deprecated compatibility alias so downstream projects linking
nvforest::nvforest++ keep working: after NVFOREST_CPP_TARGET is set and after
the existing add_library(nvforest::${NVFOREST_CPP_TARGET} ALIAS
${NVFOREST_CPP_TARGET}) line, create a second alias target mapping
nvforest::nvforest++ to the same implementation target (i.e., add an alias
nvforest::nvforest++ that points to ${NVFOREST_CPP_TARGET}) and ensure the alias
is included in the rapids_export/GLOBAL_TARGETS (or the package config) so the
installed package exports the old name as well; keep a clear deprecation comment
and only add the alias (no API changes).
In `@cpp/include/nvforest/decision_forest.hpp`:
- Around line 460-463: The categorical index-size check in
double_indexes_required uses (detail::ceildiv(max_num_categories,
max_local_categories) + 1 * num_categorical_nodes) which computes bins_per_node
+ num_categorical_nodes instead of (bins_per_node + 1) * num_categorical_nodes;
update the expression in the double_indexes_required calculation to multiply the
entire (bins_per_node + 1) factor by num_categorical_nodes (i.e. use
(detail::ceildiv(max_num_categories, max_local_categories) + 1) *
num_categorical_nodes) so the comparison against
std::numeric_limits<small_index_t>::max() correctly reflects required index
range for categorical storage.
- Around line 149-163: The decision_forest constructor currently accepts rvalue
references (nodes, root_node_indexes, node_id_mapping, bias,
optional<vector_output>, optional<categorical_storage>) but then copies them
because the member initializer uses the parameter names as lvalues; change the
initializer to transfer ownership by moving these parameters into the members
(e.g., use std::move(nodes), std::move(root_node_indexes),
std::move(node_id_mapping), std::move(bias) and std::move on the optionals like
vector_output and categorical_storage) or switch the signature to take by value
and move from those local variables into members; update the member initializers
in the decision_forest constructor accordingly so buffers are moved, not
deep-copied.
In `@cpp/include/nvforest/detail/device_initialization/gpu.cuh`:
- Around line 40-201: The repeated cudaFuncSetAttribute calls for many
infer_kernel specializations are brittle; create a compile-time helper (e.g., a
templated helper function named set_infer_kernel_max_shared<...>) that accepts
the same template parameters as infer_kernel and calls
cudaFuncSetAttribute(infer_kernel<...>,
cudaFuncAttributeMaxDynamicSharedMemorySize, max_shared_mem_per_block); then
replace the long list with a small set of invocations of that helper (or a
constexpr list/pack of kernel-parameter tuples expanded via fold/pack expansion)
for the combinations used. Refer to infer_kernel, cudaFuncSetAttribute,
cudaFuncAttributeMaxDynamicSharedMemorySize, and max_shared_mem_per_block when
implementing the templated set_infer_kernel_max_shared helper and the pack/array
expansion so behavior remains identical.
In `@cpp/include/nvforest/detail/infer/gpu.cuh`:
- Around line 190-193: The code computes num_blocks from row_count and proceeds
to allocate global_workspace and launch kernels even when row_count == 0; add an
early return guard in the function (in gpu.cuh around the block using
num_blocks/row_output_size/global_workspace) that checks if row_count == 0 (or
num_blocks == 0) and returns immediately before any buffer<output_t> allocation
or kernel launch; apply the same guard to the later region noted (lines
~229-320) so no CUDA allocations or kernel launches occur with zero grid/block
dimensions.
In `@cpp/include/nvforest/detail/specializations/forest_macros.hpp`:
- Around line 17-18: The macro NVFOREST_SPEC expands to an unqualified
specialization_variant which causes scope-dependent failures; update the macro
definition so it references the fully-qualified type (e.g.,
::nvforest::detail::specialization_variant) instead of the bare name so
expansions work from any namespace or translation unit; locate NVFOREST_SPEC in
this header and replace the unqualified specialization_variant with the
fully-qualified symbol.
In `@python/nvforest/nvforest/detail/forest_inference.pyx`:
- Around line 105-106: Validate the incoming device string before mapping to
nvforest_device_t: only accept "gpu" or "cpu" and if it's anything else raise a
clear Python error (e.g., ValueError) that includes the actual value and the
expected options; then set dev_type = nvforest_device_t.gpu if device == "gpu"
else nvforest_device_t.cpu. Update the mapping around the dev_type variable in
forest_inference.pyx (where device and nvforest_device_t are used) so invalid
inputs fail early instead of silently falling back to CPU and causing assertions
later in predict().
---
Outside diff comments:
In `@cpp/include/nvforest/buffer.hpp`:
- Around line 329-339: The bounds check in the checked copy path incorrectly
subtracts size_t values (src.size() - src_offset and dst.size() - dst_offset)
before verifying the offsets are in range, which underflows when src_offset or
dst_offset > src.size()/dst.size(); update the guard in the copy(...) path to
first assert src_offset <= src.size() and dst_offset <= dst.size() (or check
offsets against sizes) and only then compare remaining sizes against size, and
apply the identical fix to the rvalue-overload block (the subsequent copy(...)
overload around the rvalue overload lines) so both checked overloads prevent
underflow.
In `@cpp/include/nvforest/cuda_stream.hpp`:
- Around line 16-20: The synchronize function currently ignores the
cudaStreamSynchronize return value, so CUDA errors are dropped; update inline
void synchronize(cuda_stream stream) to capture the cudaError_t result from
cudaStreamSynchronize, check it, and propagate failures (either change the
signature to return cudaError_t or throw a std::runtime_error on non-success).
Concretely, in synchronize call cudaError_t err = cudaStreamSynchronize(stream);
if (err != cudaSuccess) throw
std::runtime_error(std::string("cudaStreamSynchronize failed: ") +
cudaGetErrorString(err)); — reference symbols: synchronize,
cudaStreamSynchronize, cudaError_t, cudaGetErrorString.
In `@cpp/include/nvforest/detail/exceptions.hpp`:
- Around line 8-56: The public API lost symbols when exception types were moved
into nvforest::detail; restore the original nvforest::* names by adding aliases
in the public header (nvforest/exceptions.hpp): create using declarations that
map nvforest::bad_cuda_call, out_of_bounds, wrong_device_type,
mem_type_mismatch, and wrong_device to their nvforest::detail:: counterparts
(e.g., using bad_cuda_call = detail::bad_cuda_call;), ensure the header includes
or forward-declares nvforest::detail types so the aliases compile, and keep the
original exception type names visible in the nvforest namespace to avoid
breaking downstream code.
In `@cpp/include/nvforest/detail/infer/gpu.cuh`:
- Around line 153-163: shared_mem_per_block can be zero (when
output_workspace_size_bytes and row staging were cleared), so the occupancy math
calling ceildiv(max_shared_mem_per_sm, shared_mem_per_block) and the later
"divide shared mem evenly" step will divide by zero; add an early guard after
computing shared_mem_per_block to detect shared_mem_per_block == 0 and handle
that path explicitly (for example set resident_blocks_per_sm =
max_resident_blocks or another safe default and skip any further divisions that
distribute shared memory per block), and ensure any subsequent logic that
divides by shared_mem_per_block or expects nonzero shared bytes checks this
flag; update references around shared_mem_per_block, resident_blocks_per_sm,
ceildiv, and the later "divide shared mem evenly" calculations to use this
guarded path.
In `@cpp/include/nvforest/detail/infer/gpu.hpp`:
- Around line 13-24: The header declares the infer template using
std::enable_if_t (template signature with device_type D and infer(...)) but
omits the required <type_traits> include; add `#include` <type_traits> near the
other includes so std::enable_if_t is defined (ensuring the declaration of
template <device_type D, bool has_categorical_nodes, typename forest_t, ...>
std::enable_if_t<D == device_type::gpu, void> infer(...) compiles without
relying on transitive includes).
In `@cpp/include/nvforest/handle.hpp`:
- Around line 16-29: The constructor handle_t(raft::handle_t const* handle_ptr =
nullptr) currently allows a null raft_handle_ but methods
get_next_usable_stream, get_stream_pool_size, get_usable_stream_count and
synchronize dereference it unconditionally; change the ctor to reject null
(e.g., remove the default nullptr and/or throw std::invalid_argument or assert
when handle_ptr==nullptr) so a nvforest::handle_t must be constructed from a
valid raft::handle_t, and update the public README to state GPU builds require
constructing nvforest::handle_t from an existing raft::handle_t (also audit
usages of nvforest::handle_t{} in tests/docs and replace with an explicit valid
raft::handle_t where needed).
In `@cpp/include/nvforest/README.md`:
- Around line 46-70: The docs use two different names for the device
argument—`mem_type` in the example call comment and `dev_type` in the parameter
description—so make them consistent: pick one name (prefer `dev_type`) and
update the example comment `// mem_type` to `// dev_type` and any occurrences in
the descriptive section (`mem_type` -> `dev_type`), ensuring references like
`nvforest::device_type::gpu` remain unchanged and the parameter description that
begins "dev_type: This argument controls where the model will be executed..."
matches the example and wording elsewhere.
In `@cpp/include/nvforest/treelite_importer.hpp`:
- Around line 515-529: The wrapper import_from_treelite_handle dereferences
tl_handle without checking for nullptr; add a null check at the start of
import_from_treelite_handle and if tl_handle is null throw a suitable exception
(e.g. std::invalid_argument or a library-specific import error) with a clear
message like "null TreeliteModelHandle"; only call
import_from_treelite_model(*static_cast<treelite::Model*>(tl_handle), ...) when
tl_handle is non-null to avoid segfaults.
---
Nitpick comments:
In `@cpp/include/nvforest/detail/device_setter.hpp`:
- Around line 6-10: Reorder the includes in device_setter.hpp so that the
dependency header device_type.hpp is included before device_setter/base.hpp and
device_setter/gpu.hpp; specifically, move the include for
nvforest/device_type.hpp above the includes for
nvforest/detail/device_setter/base.hpp and (conditionally)
nvforest/detail/device_setter/gpu.hpp to ensure device_type is available to the
base and gpu headers (symbols: device_setter.hpp, device_setter::base,
device_setter::gpu, and device_type.hpp).
In
`@cpp/include/nvforest/detail/specializations/device_initialization_macros.hpp`:
- Around line 11-13: The macro NVFOREST_INITIALIZE_DEVICE emits types like
device_type and device_id without global qualification, which breaks if the
expansion isn't inside namespace nvforest; update the macro so generated symbols
in initialize_device<NVFOREST_FOREST(variant_index),
device_type::gpu>(device_id<device_type::gpu>) are fully qualified (e.g.,
::nvforest::device_type and ::nvforest::device_id and any other nvforest symbols
referenced) so the instantiation is stable regardless of the expansion scope.
In `@cpp/include/nvforest/device_type.hpp`:
- Line 7: Add a Doxygen comment block immediately above the public enum class
device_type describing that it represents the execution device for NVForest
operations, listing the valid enum values (cpu and gpu) with a short description
for each, and note intended usage (e.g., selecting target device for computation
or resource allocation). Use brief `@enum/`@brief style tags and mention any
default behavior or constraints if applicable so the public API is documented
for users.
🪄 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: 5877b175-08a8-4c41-81f5-f28cab06a27f
📒 Files selected for processing (107)
build.shci/build_wheel_nvforest.shconda/recipes/libnvforest/recipe.yamlcpp/CMakeLists.txtcpp/include/nvforest/Implementation.mdcpp/include/nvforest/README.mdcpp/include/nvforest/buffer.hppcpp/include/nvforest/cuda_stream.hppcpp/include/nvforest/decision_forest.hppcpp/include/nvforest/detail/bitset.hppcpp/include/nvforest/detail/ceildiv.hppcpp/include/nvforest/detail/const_agnostic.hppcpp/include/nvforest/detail/copy.hppcpp/include/nvforest/detail/copy/cpu.hppcpp/include/nvforest/detail/copy/gpu.hppcpp/include/nvforest/detail/cuda_check.hppcpp/include/nvforest/detail/cuda_check/base.hppcpp/include/nvforest/detail/cuda_check/gpu.hppcpp/include/nvforest/detail/decision_forest_builder.hppcpp/include/nvforest/detail/device_id.hppcpp/include/nvforest/detail/device_id/base.hppcpp/include/nvforest/detail/device_id/cpu.hppcpp/include/nvforest/detail/device_id/gpu.hppcpp/include/nvforest/detail/device_initialization.hppcpp/include/nvforest/detail/device_initialization/cpu.hppcpp/include/nvforest/detail/device_initialization/gpu.cuhcpp/include/nvforest/detail/device_initialization/gpu.hppcpp/include/nvforest/detail/device_setter.hppcpp/include/nvforest/detail/device_setter/base.hppcpp/include/nvforest/detail/device_setter/gpu.hppcpp/include/nvforest/detail/evaluate_tree.hppcpp/include/nvforest/detail/exceptions.hppcpp/include/nvforest/detail/forest.hppcpp/include/nvforest/detail/gpu_introspection.hppcpp/include/nvforest/detail/gpu_support.hppcpp/include/nvforest/detail/host_only_throw.hppcpp/include/nvforest/detail/host_only_throw/base.hppcpp/include/nvforest/detail/host_only_throw/cpu.hppcpp/include/nvforest/detail/infer.hppcpp/include/nvforest/detail/infer/cpu.hppcpp/include/nvforest/detail/infer/gpu.cuhcpp/include/nvforest/detail/infer/gpu.hppcpp/include/nvforest/detail/infer_kernel/cpu.hppcpp/include/nvforest/detail/infer_kernel/gpu.cuhcpp/include/nvforest/detail/node.hppcpp/include/nvforest/detail/non_owning_buffer.hppcpp/include/nvforest/detail/non_owning_buffer/base.hppcpp/include/nvforest/detail/owning_buffer.hppcpp/include/nvforest/detail/owning_buffer/base.hppcpp/include/nvforest/detail/owning_buffer/cpu.hppcpp/include/nvforest/detail/owning_buffer/gpu.hppcpp/include/nvforest/detail/padding.hppcpp/include/nvforest/detail/postprocessor.hppcpp/include/nvforest/detail/raft_proto/cuda_check.hppcpp/include/nvforest/detail/raft_proto/detail/const_agnostic.hppcpp/include/nvforest/detail/raft_proto/detail/host_only_throw.hppcpp/include/nvforest/detail/raft_proto/detail/non_owning_buffer.hppcpp/include/nvforest/detail/raft_proto/detail/owning_buffer.hppcpp/include/nvforest/detail/raft_proto/device_id.hppcpp/include/nvforest/detail/raft_proto/device_setter.hppcpp/include/nvforest/detail/raft_proto/device_type.hppcpp/include/nvforest/detail/specializations/device_initialization_macros.hppcpp/include/nvforest/detail/specializations/forest_macros.hppcpp/include/nvforest/detail/specializations/infer_macros.hppcpp/include/nvforest/device_type.hppcpp/include/nvforest/forest_model.hppcpp/include/nvforest/handle.hppcpp/include/nvforest/treelite_importer.hppcpp/src/infer0.cppcpp/src/infer0.cucpp/src/infer1.cppcpp/src/infer1.cucpp/src/infer10.cppcpp/src/infer10.cucpp/src/infer11.cppcpp/src/infer11.cucpp/src/infer2.cppcpp/src/infer2.cucpp/src/infer3.cppcpp/src/infer3.cucpp/src/infer4.cppcpp/src/infer4.cucpp/src/infer5.cppcpp/src/infer5.cucpp/src/infer6.cppcpp/src/infer6.cucpp/src/infer7.cppcpp/src/infer7.cucpp/src/infer8.cppcpp/src/infer8.cucpp/src/infer9.cppcpp/src/infer9.cucpp/tests/CMakeLists.txtcpp/tests/buffer/buffer.cppcpp/tests/buffer/buffer.cucpp/tests/treelite_importer.cppdocs/source/getting_started.rstpython/libnvforest/CMakeLists.txtpython/libnvforest/libnvforest/load.pypython/nvforest/CMakeLists.txtpython/nvforest/nvforest/detail/cuda_stream.pxdpython/nvforest/nvforest/detail/device_type.pxdpython/nvforest/nvforest/detail/forest_inference.pyxpython/nvforest/nvforest/detail/handle.pxdpython/nvforest/nvforest/detail/raft_proto/__init__.pypython/nvforest/nvforest/detail/raft_proto/device_type.pxdpython/nvforest/nvforest/detail/raft_proto/optional.pxd
💤 Files with no reviewable changes (11)
- cpp/include/nvforest/detail/raft_proto/cuda_check.hpp
- cpp/include/nvforest/detail/raft_proto/device_setter.hpp
- cpp/include/nvforest/detail/raft_proto/detail/host_only_throw.hpp
- cpp/include/nvforest/detail/raft_proto/detail/const_agnostic.hpp
- python/nvforest/nvforest/detail/raft_proto/device_type.pxd
- cpp/include/nvforest/detail/raft_proto/device_id.hpp
- python/nvforest/nvforest/detail/raft_proto/init.py
- cpp/include/nvforest/detail/raft_proto/detail/owning_buffer.hpp
- cpp/include/nvforest/detail/raft_proto/detail/non_owning_buffer.hpp
- python/nvforest/nvforest/detail/raft_proto/optional.pxd
- cpp/include/nvforest/detail/raft_proto/device_type.hpp
| decision_forest( | ||
| buffer<node_type>&& nodes, | ||
| buffer<index_type>&& root_node_indexes, | ||
| buffer<index_type>&& node_id_mapping, | ||
| buffer<io_type>&& bias, | ||
| index_type num_features, | ||
| index_type num_outputs = index_type{2}, | ||
| bool has_categorical_nodes = false, | ||
| std::optional<buffer<io_type>>&& vector_output = std::nullopt, | ||
| std::optional<buffer<typename node_type::index_type>>&& categorical_storage = std::nullopt, | ||
| index_type leaf_size = index_type{1}, | ||
| row_op row_postproc = row_op::disable, | ||
| element_op elem_postproc = element_op::disable, | ||
| io_type average_factor = io_type{1}, | ||
| io_type postproc_constant = io_type{1}) |
There was a problem hiding this comment.
These && buffers are still copied, not moved.
The constructor advertises transfer of ownership, but the member initializers below use the named parameters as lvalues. That deep-copies every model buffer instead of moving it, which can double import-time allocation/copy cost and OOM large GPU models.
Suggested fix
decision_forest(
buffer<node_type>&& nodes,
buffer<index_type>&& root_node_indexes,
buffer<index_type>&& node_id_mapping,
buffer<io_type>&& bias,
@@
index_type leaf_size = index_type{1},
row_op row_postproc = row_op::disable,
element_op elem_postproc = element_op::disable,
io_type average_factor = io_type{1},
io_type postproc_constant = io_type{1})
- : nodes_{nodes},
- root_node_indexes_{root_node_indexes},
- node_id_mapping_{node_id_mapping},
- bias_{bias},
- vector_output_{vector_output},
- categorical_storage_{categorical_storage},
+ : nodes_{std::move(nodes)},
+ root_node_indexes_{std::move(root_node_indexes)},
+ node_id_mapping_{std::move(node_id_mapping)},
+ bias_{std::move(bias)},
+ vector_output_{std::move(vector_output)},
+ categorical_storage_{std::move(categorical_storage)},
num_features_{num_features},
num_outputs_{num_outputs},
leaf_size_{leaf_size},🤖 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/nvforest/decision_forest.hpp` around lines 149 - 163, The
decision_forest constructor currently accepts rvalue references (nodes,
root_node_indexes, node_id_mapping, bias, optional<vector_output>,
optional<categorical_storage>) but then copies them because the member
initializer uses the parameter names as lvalues; change the initializer to
transfer ownership by moving these parameters into the members (e.g., use
std::move(nodes), std::move(root_node_indexes), std::move(node_id_mapping),
std::move(bias) and std::move on the optionals like vector_output and
categorical_storage) or switch the signature to take by value and move from
those local variables into members; update the member initializers in the
decision_forest constructor accordingly so buffers are moved, not deep-copied.
| auto double_indexes_required = | ||
| (max_num_categories > max_local_categories && | ||
| ((raft_proto::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes) > | ||
| ((detail::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes) > | ||
| std::numeric_limits<small_index_t>::max())) || |
There was a problem hiding this comment.
Fix the categorical-storage size formula.
detail::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes evaluates as bins_per_node + num_categorical_nodes, not (bins_per_node + 1) * num_categorical_nodes. That underestimates the required index range and can select the wrong forest specialization for large categorical models.
Suggested fix
- (max_num_categories > max_local_categories &&
- ((detail::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes) >
+ (max_num_categories > max_local_categories &&
+ (((detail::ceildiv(max_num_categories, max_local_categories) + 1) *
+ num_categorical_nodes) >
std::numeric_limits<small_index_t>::max())) ||📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| auto double_indexes_required = | |
| (max_num_categories > max_local_categories && | |
| ((raft_proto::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes) > | |
| ((detail::ceildiv(max_num_categories, max_local_categories) + 1 * num_categorical_nodes) > | |
| std::numeric_limits<small_index_t>::max())) || | |
| auto double_indexes_required = | |
| (max_num_categories > max_local_categories && | |
| (((detail::ceildiv(max_num_categories, max_local_categories) + 1) * | |
| num_categorical_nodes) > | |
| std::numeric_limits<small_index_t>::max())) || |
🤖 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/nvforest/decision_forest.hpp` around lines 460 - 463, The
categorical index-size check in double_indexes_required uses
(detail::ceildiv(max_num_categories, max_local_categories) + 1 *
num_categorical_nodes) which computes bins_per_node + num_categorical_nodes
instead of (bins_per_node + 1) * num_categorical_nodes; update the expression in
the double_indexes_required calculation to multiply the entire (bins_per_node +
1) factor by num_categorical_nodes (i.e. use
(detail::ceildiv(max_num_categories, max_local_categories) + 1) *
num_categorical_nodes) so the comparison against
std::numeric_limits<small_index_t>::max() correctly reflects required index
range for categorical storage.
| auto num_blocks = std::min(ceildiv(row_count, rows_per_block_iteration), MAX_BLOCKS); | ||
| if (row_output_size == 0) { | ||
| global_workspace = raft_proto::buffer<output_t>{ | ||
| output_workspace_size * num_blocks, raft_proto::device_type::gpu, device.value(), stream}; | ||
| global_workspace = buffer<output_t>{ | ||
| output_workspace_size * num_blocks, device_type::gpu, device.value(), stream}; |
There was a problem hiding this comment.
Return early for empty batches.
When row_count == 0, num_blocks becomes 0 and the kernel launches below become invalid CUDA launches. This path needs an early return before workspace allocation/launch selection.
Suggested fix
{
using output_t = typename forest_t::template raw_output_type<vector_output_t>;
+
+ if (row_count == 0) { return; }
auto sm_count = get_sm_count(device);As per coding guidelines, Kernel launch with zero blocks/threads or invalid grid/block dimensions must be validated before kernel execution.
Also applies to: 229-320
🤖 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/nvforest/detail/infer/gpu.cuh` around lines 190 - 193, The code
computes num_blocks from row_count and proceeds to allocate global_workspace and
launch kernels even when row_count == 0; add an early return guard in the
function (in gpu.cuh around the block using
num_blocks/row_output_size/global_workspace) that checks if row_count == 0 (or
num_blocks == 0) and returns immediately before any buffer<output_t> allocation
or kernel launch; apply the same guard to the later region noted (lines
~229-320) so no CUDA allocations or kernel launches occur with zero grid/block
dimensions.
| cdef nvforest_device_t dev_type | ||
| dev_type = nvforest_device_t.gpu if device == "gpu" else nvforest_device_t.cpu |
There was a problem hiding this comment.
Reject unknown device values here.
Anything other than "gpu" currently falls back to CPU, but predict() later assumes the only non-CPU value is "gpu". A typo like "cuda" therefore imports the model on CPU and fails later with an unhelpful assertion instead of a clear validation error.
Suggested fix
- dev_type = nvforest_device_t.gpu if device == "gpu" else nvforest_device_t.cpu
+ if device == "gpu":
+ dev_type = nvforest_device_t.gpu
+ elif device == "cpu":
+ dev_type = nvforest_device_t.cpu
+ else:
+ raise ValueError(f"device must be 'cpu' or 'gpu', got {device!r}")As per coding guidelines, Error messages should be helpful and include expected vs actual values.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cdef nvforest_device_t dev_type | |
| dev_type = nvforest_device_t.gpu if device == "gpu" else nvforest_device_t.cpu | |
| cdef nvforest_device_t dev_type | |
| if device == "gpu": | |
| dev_type = nvforest_device_t.gpu | |
| elif device == "cpu": | |
| dev_type = nvforest_device_t.cpu | |
| else: | |
| raise ValueError(f"device must be 'cpu' or 'gpu', got {device!r}") |
🤖 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 `@python/nvforest/nvforest/detail/forest_inference.pyx` around lines 105 - 106,
Validate the incoming device string before mapping to nvforest_device_t: only
accept "gpu" or "cpu" and if it's anything else raise a clear Python error
(e.g., ValueError) that includes the actual value and the expected options; then
set dev_type = nvforest_device_t.gpu if device == "gpu" else
nvforest_device_t.cpu. Update the mapping around the dev_type variable in
forest_inference.pyx (where device and nvforest_device_t are used) so invalid
inputs fail early instead of silently falling back to CPU and causing assertions
later in predict().
|
@coderabbitai Please create a new issue to remind us to address the unresolved comments here. |
|
Tip For best results, initiate chat on the files or code changes.
The issue captures the following items from the PR review: Critical (1)
Major (8)
Minor (2)
|
RAMitchell
left a comment
There was a problem hiding this comment.
LGTM. I think your build.rst still refers to libnvforest++
Also, do you even need raft?
nvForest currently uses |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@docs/source/build.rst`:
- Line 145: Update the numbered manual-step headings in the build instructions
to match their commands: revise step 2, which only configures libnvforest, and
step 3, which performs the build and installation. Apply the same heading
correction to the corresponding repeated section referenced by the review.
🪄 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: 1a8b85fc-fbb4-41e2-b02e-a6ea73d3907e
📒 Files selected for processing (5)
ci/build_wheel_nvforest.shcpp/CMakeLists.txtcpp/tests/CMakeLists.txtdocs/source/build.rstdocs/source/getting_started.rst
✅ Files skipped from review due to trivial changes (1)
- docs/source/getting_started.rst
🚧 Files skipped from review as they are similar to previous changes (3)
- cpp/tests/CMakeLists.txt
- ci/build_wheel_nvforest.sh
- cpp/CMakeLists.txt
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cpp/include/nvforest/decision_forest.hpp (2)
179-187: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winValidate every model buffer’s memory type and device.
Only
nodesandroot_node_indexesare checked. A mismatchedbias,node_id_mapping,vector_output, orcategorical_storagebuffer can later be passed to inference on the wrong host/device memory space.🤖 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/nvforest/decision_forest.hpp` around lines 179 - 187, Extend the validation in the forest initialization path around nodes and root_node_indexes to check every model buffer—bias, node_id_mapping, vector_output, and categorical_storage—for matching memory type and device. Reuse the existing mem_type_mismatch handling and ensure all buffers are validated before detail::initialize_device<forest_type>(nodes).
269-290: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winValidate batch dimensions before computing row counts.
input.size() / num_features_can divide by zero whennum_features_ == 0, silently truncates inputs whose size is not divisible bynum_features_, and output capacity is never checked before kernel writes. Reject invalid dimensions and verify the output buffer size before dispatch.🤖 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/nvforest/decision_forest.hpp` around lines 269 - 290, Update the prediction dispatch around the visible detail::infer calls to validate dimensions before computing the row count: reject num_features_ == 0, require input.size() to be divisible by num_features_, and verify output has capacity for the requested rows and num_outputs(predict_type). Perform these checks before any division or kernel dispatch while preserving valid prediction behavior.
🧹 Nitpick comments (1)
cpp/include/nvforest/decision_forest.hpp (1)
6-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the public namespace/type migration.
The constructor and
predictAPI now exposenvforesttypes instead ofraft_prototypes. Update public documentation and release notes with the migration path for downstream callers. As per path instructions, public API changes require corresponding documentation and migration guidance.Also applies to: 149-163, 249-253
🤖 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/nvforest/decision_forest.hpp` around lines 6 - 15, Document the public API migration from raft_proto types to nvforest types for the decision forest constructor and predict API, including the required downstream caller migration path. Update the relevant public API documentation and release notes, covering the additional affected sections noted in the review.Source: 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.
Outside diff comments:
In `@cpp/include/nvforest/decision_forest.hpp`:
- Around line 179-187: Extend the validation in the forest initialization path
around nodes and root_node_indexes to check every model buffer—bias,
node_id_mapping, vector_output, and categorical_storage—for matching memory type
and device. Reuse the existing mem_type_mismatch handling and ensure all buffers
are validated before detail::initialize_device<forest_type>(nodes).
- Around line 269-290: Update the prediction dispatch around the visible
detail::infer calls to validate dimensions before computing the row count:
reject num_features_ == 0, require input.size() to be divisible by
num_features_, and verify output has capacity for the requested rows and
num_outputs(predict_type). Perform these checks before any division or kernel
dispatch while preserving valid prediction behavior.
---
Nitpick comments:
In `@cpp/include/nvforest/decision_forest.hpp`:
- Around line 6-15: Document the public API migration from raft_proto types to
nvforest types for the decision forest constructor and predict API, including
the required downstream caller migration path. Update the relevant public API
documentation and release notes, covering the additional affected sections noted
in the review.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: f2aee95c-5d3c-4d02-a081-411157982ed1
📒 Files selected for processing (96)
build.shci/build_wheel_nvforest.shcmake/RAPIDS.cmakeconda/recipes/libnvforest/recipe.yamlcpp/CMakeLists.txtcpp/include/nvforest/buffer.hppcpp/include/nvforest/cuda_stream.hppcpp/include/nvforest/decision_forest.hppcpp/include/nvforest/detail/bitset.hppcpp/include/nvforest/detail/ceildiv.hppcpp/include/nvforest/detail/const_agnostic.hppcpp/include/nvforest/detail/copy.hppcpp/include/nvforest/detail/copy/cpu.hppcpp/include/nvforest/detail/copy/gpu.hppcpp/include/nvforest/detail/cuda_check.hppcpp/include/nvforest/detail/cuda_check/base.hppcpp/include/nvforest/detail/cuda_check/gpu.hppcpp/include/nvforest/detail/decision_forest_builder.hppcpp/include/nvforest/detail/device_id.hppcpp/include/nvforest/detail/device_id/base.hppcpp/include/nvforest/detail/device_id/cpu.hppcpp/include/nvforest/detail/device_id/gpu.hppcpp/include/nvforest/detail/device_initialization.hppcpp/include/nvforest/detail/device_initialization/cpu.hppcpp/include/nvforest/detail/device_initialization/gpu.cuhcpp/include/nvforest/detail/device_initialization/gpu.hppcpp/include/nvforest/detail/device_setter.hppcpp/include/nvforest/detail/device_setter/base.hppcpp/include/nvforest/detail/device_setter/gpu.hppcpp/include/nvforest/detail/evaluate_tree.hppcpp/include/nvforest/detail/exceptions.hppcpp/include/nvforest/detail/forest.hppcpp/include/nvforest/detail/gpu_introspection.hppcpp/include/nvforest/detail/gpu_support.hppcpp/include/nvforest/detail/host_only_throw.hppcpp/include/nvforest/detail/host_only_throw/base.hppcpp/include/nvforest/detail/host_only_throw/cpu.hppcpp/include/nvforest/detail/infer.hppcpp/include/nvforest/detail/infer/cpu.hppcpp/include/nvforest/detail/infer/gpu.cuhcpp/include/nvforest/detail/infer/gpu.hppcpp/include/nvforest/detail/infer_kernel/cpu.hppcpp/include/nvforest/detail/infer_kernel/gpu.cuhcpp/include/nvforest/detail/infer_kernel/shared_memory_buffer.cuhcpp/include/nvforest/detail/node.hppcpp/include/nvforest/detail/non_owning_buffer.hppcpp/include/nvforest/detail/non_owning_buffer/base.hppcpp/include/nvforest/detail/owning_buffer.hppcpp/include/nvforest/detail/owning_buffer/base.hppcpp/include/nvforest/detail/owning_buffer/cpu.hppcpp/include/nvforest/detail/owning_buffer/gpu.hppcpp/include/nvforest/detail/padding.hppcpp/include/nvforest/detail/postprocessor.hppcpp/include/nvforest/detail/specializations/device_initialization_macros.hppcpp/include/nvforest/detail/specializations/infer_macros.hppcpp/include/nvforest/device_type.hppcpp/include/nvforest/forest_model.hppcpp/include/nvforest/handle.hppcpp/include/nvforest/treelite_importer.hppcpp/src/infer0.cppcpp/src/infer0.cucpp/src/infer1.cppcpp/src/infer1.cucpp/src/infer10.cppcpp/src/infer10.cucpp/src/infer11.cppcpp/src/infer11.cucpp/src/infer2.cppcpp/src/infer2.cucpp/src/infer3.cppcpp/src/infer3.cucpp/src/infer4.cppcpp/src/infer4.cucpp/src/infer5.cppcpp/src/infer5.cucpp/src/infer6.cppcpp/src/infer6.cucpp/src/infer7.cppcpp/src/infer7.cucpp/src/infer8.cppcpp/src/infer8.cucpp/src/infer9.cppcpp/src/infer9.cucpp/tests/CMakeLists.txtcpp/tests/buffer/buffer.cppcpp/tests/buffer/buffer.cucpp/tests/infer_kernel/shared_memory_buffer.cucpp/tests/treelite_importer.cpppyproject.tomlpython/libnvforest/CMakeLists.txtpython/libnvforest/libnvforest/load.pypython/nvforest/CMakeLists.txtpython/nvforest/nvforest/detail/cuda_stream.pxdpython/nvforest/nvforest/detail/device_type.pxdpython/nvforest/nvforest/detail/forest_inference.pyxpython/nvforest/nvforest/detail/handle.pxd
🚧 Files skipped from review as they are similar to previous changes (90)
- cpp/src/infer2.cpp
- ci/build_wheel_nvforest.sh
- cpp/src/infer1.cpp
- cpp/include/nvforest/detail/non_owning_buffer.hpp
- cpp/include/nvforest/detail/device_setter.hpp
- cpp/src/infer9.cpp
- cpp/src/infer6.cu
- python/nvforest/CMakeLists.txt
- cpp/src/infer3.cpp
- cpp/include/nvforest/detail/owning_buffer.hpp
- cpp/src/infer5.cpp
- cpp/src/infer10.cpp
- python/nvforest/nvforest/detail/device_type.pxd
- cpp/include/nvforest/detail/host_only_throw.hpp
- cpp/src/infer5.cu
- cpp/src/infer4.cpp
- cpp/tests/CMakeLists.txt
- cpp/src/infer9.cu
- cpp/src/infer2.cu
- python/libnvforest/libnvforest/load.py
- cpp/include/nvforest/detail/device_id.hpp
- cpp/src/infer7.cpp
- cpp/src/infer6.cpp
- cpp/include/nvforest/detail/evaluate_tree.hpp
- cpp/include/nvforest/detail/const_agnostic.hpp
- build.sh
- cpp/src/infer11.cu
- cpp/src/infer1.cu
- cpp/include/nvforest/detail/cuda_check/gpu.hpp
- cpp/include/nvforest/detail/gpu_support.hpp
- cpp/src/infer8.cu
- cpp/src/infer3.cu
- cpp/include/nvforest/device_type.hpp
- cpp/include/nvforest/detail/bitset.hpp
- cpp/src/infer0.cpp
- cpp/include/nvforest/detail/specializations/device_initialization_macros.hpp
- cpp/include/nvforest/detail/owning_buffer/base.hpp
- cpp/src/infer0.cu
- cpp/src/infer8.cpp
- cpp/src/infer10.cu
- cpp/include/nvforest/detail/node.hpp
- conda/recipes/libnvforest/recipe.yaml
- cpp/include/nvforest/detail/postprocessor.hpp
- cpp/include/nvforest/detail/cuda_check.hpp
- python/nvforest/nvforest/detail/cuda_stream.pxd
- cpp/include/nvforest/detail/host_only_throw/cpu.hpp
- python/libnvforest/CMakeLists.txt
- cpp/include/nvforest/detail/infer/gpu.hpp
- cpp/include/nvforest/detail/infer_kernel/gpu.cuh
- cpp/src/infer11.cpp
- cpp/src/infer4.cu
- python/nvforest/nvforest/detail/handle.pxd
- cpp/include/nvforest/detail/non_owning_buffer/base.hpp
- cpp/include/nvforest/detail/copy/gpu.hpp
- cpp/include/nvforest/detail/forest.hpp
- cpp/include/nvforest/detail/infer.hpp
- cpp/include/nvforest/handle.hpp
- cpp/include/nvforest/detail/ceildiv.hpp
- cpp/include/nvforest/detail/device_initialization/gpu.hpp
- cpp/include/nvforest/detail/padding.hpp
- cpp/include/nvforest/detail/specializations/infer_macros.hpp
- cpp/include/nvforest/detail/host_only_throw/base.hpp
- cpp/src/infer7.cu
- cpp/include/nvforest/detail/infer/cpu.hpp
- cpp/include/nvforest/detail/device_id/base.hpp
- cpp/tests/treelite_importer.cpp
- cpp/tests/buffer/buffer.cu
- cpp/include/nvforest/detail/device_id/gpu.hpp
- cpp/include/nvforest/detail/infer_kernel/cpu.hpp
- cpp/include/nvforest/detail/device_initialization/gpu.cuh
- cpp/include/nvforest/detail/device_initialization.hpp
- cpp/include/nvforest/detail/owning_buffer/cpu.hpp
- cpp/include/nvforest/detail/device_setter/gpu.hpp
- cpp/CMakeLists.txt
- cpp/include/nvforest/detail/device_initialization/cpu.hpp
- cpp/tests/buffer/buffer.cpp
- cpp/include/nvforest/detail/exceptions.hpp
- cpp/include/nvforest/detail/device_setter/base.hpp
- cpp/include/nvforest/detail/device_id/cpu.hpp
- python/nvforest/nvforest/detail/forest_inference.pyx
- cpp/include/nvforest/cuda_stream.hpp
- cpp/include/nvforest/detail/cuda_check/base.hpp
- cpp/include/nvforest/buffer.hpp
- cpp/include/nvforest/detail/owning_buffer/gpu.hpp
- cpp/include/nvforest/detail/gpu_introspection.hpp
- cpp/include/nvforest/detail/copy.hpp
- cpp/include/nvforest/treelite_importer.hpp
- cpp/include/nvforest/detail/decision_forest_builder.hpp
- cpp/include/nvforest/detail/infer/gpu.cuh
- cpp/include/nvforest/forest_model.hpp
|
/merge |
KyleFromNVIDIA
left a comment
There was a problem hiding this comment.
git grep -E 'nvforest\+\+' shows no remaining traces of the old name. Approving.
Note that since this changes the name of the library, it is a breaking change.
Update cuML to build with 26.08 nvForest, after a breaking change (rapidsai/nvforest#132). Authors: - Philip Hyunsu Cho (https://github.com/hcho3) Approvers: - Simon Adorf (https://github.com/csadorf) - Bradley Dice (https://github.com/bdice) URL: #8388
Closes #124
Closes #129