Skip to content

Reduce distinct_helpers build time - #23322

Open
PointKernel wants to merge 8 commits into
rapidsai:mainfrom
PointKernel:reduce-distinct-helpers-build-time
Open

Reduce distinct_helpers build time#23322
PointKernel wants to merge 8 commits into
rapidsai:mainfrom
PointKernel:reduce-distinct-helpers-build-time

Conversation

@PointKernel

@PointKernel PointKernel commented Jul 17, 2026

Copy link
Copy Markdown
Member

Description

Related to #21973

This PR reduces build time by splitting flat and nested row operators, NaN equality comparators, and KEEP_ANY and ordered operations into separate TUs.

For nested KEEP_ANY, this PR materializes MurmurHash values in a separate pass and uses lightweight hash lookups during cuco insertion. Ordered nested operations continue hashing inline to avoid a runtime regression.

The aggregate CUDA compile time is effectively unchanged (662s for the original TU vs 665s summed across the nine split TUs), while the longest individual compile drops from 662s to 103s. Nested LIST KEEP_ANY benchmarks improve by 18–20%, with no measurable regressions across 24 cases.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. CMake CMake build issue labels Jul 17, 2026
@PointKernel PointKernel changed the title Reduce distinct helper build time Reduce distinct_helpers build time Jul 18, 2026
@PointKernel PointKernel added non-breaking Non-breaking change improvement Improvement / enhancement to an existing function labels Jul 28, 2026
@PointKernel
PointKernel marked this pull request as ready for review July 28, 2026 18:10
@PointKernel
PointKernel requested review from a team as code owners July 28, 2026 18:10
@rapidsai rapidsai deleted a comment from copy-pr-bot Bot Jul 28, 2026
@coderabbitai

coderabbitai Bot commented Jul 28, 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: 36bef535-d4dc-4f76-8baf-ed5cd433229f

📥 Commits

Reviewing files that changed from the base of the PR and between 0db0236 and 6effd21.

📒 Files selected for processing (1)
  • cpp/CMakeLists.txt

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Improved duplicate and distinct-row handling, including support for nested data and configurable NaN equality behavior.
    • Enhanced distinct-row selection for keeping any, first, last, or no duplicates.
    • Improved hashing performance for row-based operations.
    • Added support for more efficient filtered joins across flat and nested data.

Walkthrough

Changes

Distinct reduction pipeline

Layer / File(s) Summary
Preprocessed MurmurHash3 hashing
cpp/src/hash/murmurhash3_x86_32.cu
Hashing now preprocesses table input and supports hashing from an existing preprocessed table.
Specialized distinct reduction helpers
cpp/src/stream_compaction/distinct_helpers.*
Reduction dispatch now separates keep-any from keep-first/last/none paths, with explicit result initialization and output copying.
Distinct index hashing and dispatch
cpp/src/stream_compaction/distinct.cu
Nested keep-any inputs use precomputed MurmurHash3 values; other paths provide explicit row hashers and reduction functions.
Comparator specializations and build wiring
cpp/src/stream_compaction/distinct_helpers_*, cpp/CMakeLists.txt
Flat and nested NaN-equal or NaN-unequal CUDA variants are added to the cudf target.

Filtered join source split

Layer / File(s) Summary
Filtered join implementation sources
cpp/CMakeLists.txt, cpp/src/join/filtered_join/*
The CMake source list replaces the single filtered join translation unit with split base, flat, nested, nested-query, and primitive sources.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • rapidsai/cudf#22765: Changes the same MurmurHash3 implementation used by the new preprocessed hashing path.
  • rapidsai/cudf#23320: Also splits filtered join CUDA sources and overlaps with nested hashing changes.

Suggested reviewers: vuule, pmattione-nvidia, bdice, davidwendt

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% 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 matches the PR’s main goal of reducing distinct_helpers build time.
Description check ✅ Passed The description directly describes splitting distinct_helpers into separate TUs to reduce build time.
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 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

🧹 Nitpick comments (3)
cpp/src/stream_compaction/distinct_helpers.cu (1)

17-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing direct include for thrust::uninitialized_fill.

Line 29 calls thrust::uninitialized_fill, but only <thrust/fill.h> is included (line 20); thrust::uninitialized_fill is declared in <thrust/uninitialized_fill.h>. This likely compiles only via a transitive include today, which is fragile against unrelated header changes elsewhere.

As per coding guidelines, "include headers directly for every used symbol without unused or incorrectly styled includes."

📝 Proposed fix
 `#include` <cuda/functional>
 `#include` <cuda/iterator>
 `#include` <cuda/std/iterator>
-#include <thrust/fill.h>
+#include <thrust/uninitialized_fill.h>
🤖 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/src/stream_compaction/distinct_helpers.cu` around lines 17 - 33, Add the
direct <thrust/uninitialized_fill.h> include in the file containing
initialize_reduction_results, and remove or retain <thrust/fill.h> based on
whether another symbol uses it. Ensure thrust::uninitialized_fill is declared by
its own header rather than relying on transitive includes.

Source: Coding guidelines

cpp/src/stream_compaction/distinct_helpers.hpp (1)

114-139: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doxygen doc block now only covers reduce_by_row_keep_any.

The comment at lines 86-113 was written for a single reduction function and is now only adjacent to reduce_by_row_keep_any. reduce_by_row_keep_first_last_none (120-126) and reduce_by_row (128-139) are left without their own doc comments, so doxygen output/linting will treat them as undocumented.

As per coding guidelines, "Use doxygen as a documentation generator and linter for C++ and CUDA code."

📝 Proposed fix
+/**
+ * `@copydoc` cudf::detail::reduce_by_row_keep_any
+ */
 template <typename Set>
 rmm::device_uvector<size_type> reduce_by_row_keep_first_last_none(
   Set& set,
   size_type num_rows,
   duplicate_keep_option keep,
   rmm::cuda_stream_view stream,
   rmm::device_async_resource_ref mr);

+/**
+ * `@copydoc` cudf::detail::reduce_by_row_keep_any
+ */
 template <typename Set>
 rmm::device_uvector<size_type> reduce_by_row(Set& set, ...);
🤖 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/src/stream_compaction/distinct_helpers.hpp` around lines 114 - 139, Add
Doxygen documentation for reduce_by_row_keep_first_last_none and reduce_by_row
in distinct_helpers.hpp, ensuring each function’s parameters, behavior, and
return value are documented. Keep the existing documentation scoped to
reduce_by_row_keep_any and align the new comments with the project’s Doxygen
conventions.

Source: Coding guidelines

cpp/src/stream_compaction/distinct_helpers.cuh (1)

55-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare the device lambda’s return type explicitly.

Proposed fix
-                   [set_ref, keep, reduction_results = reduction_results.begin()] __device__(
-                     size_type const idx) mutable {
+                   [set_ref, keep, reduction_results = reduction_results.begin()] __device__(
+                     size_type const idx) mutable -> void {

As per coding guidelines, “Declare explicit return types for extended device lambdas passed to device algorithms.”

🤖 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/src/stream_compaction/distinct_helpers.cuh` around lines 55 - 74, Update
the device lambda passed to thrust::for_each in the distinct compaction logic to
declare an explicit void return type, while preserving its existing capture
list, mutability, and body behavior.

Source: Coding guidelines

🤖 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/src/stream_compaction/distinct_helpers.cuh`:
- Around line 49-51: Update the reduction_results allocation in the distinct
compaction flow to use cudf::get_current_device_resource_ref() instead of the
caller-provided mr, while keeping output_indices allocated with mr. Leave
initialize_reduction_results and the surrounding stream behavior unchanged.

---

Nitpick comments:
In `@cpp/src/stream_compaction/distinct_helpers.cu`:
- Around line 17-33: Add the direct <thrust/uninitialized_fill.h> include in the
file containing initialize_reduction_results, and remove or retain
<thrust/fill.h> based on whether another symbol uses it. Ensure
thrust::uninitialized_fill is declared by its own header rather than relying on
transitive includes.

In `@cpp/src/stream_compaction/distinct_helpers.cuh`:
- Around line 55-74: Update the device lambda passed to thrust::for_each in the
distinct compaction logic to declare an explicit void return type, while
preserving its existing capture list, mutability, and body behavior.

In `@cpp/src/stream_compaction/distinct_helpers.hpp`:
- Around line 114-139: Add Doxygen documentation for
reduce_by_row_keep_first_last_none and reduce_by_row in distinct_helpers.hpp,
ensuring each function’s parameters, behavior, and return value are documented.
Keep the existing documentation scoped to reduce_by_row_keep_any and align the
new comments with the project’s Doxygen conventions.
🪄 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: fb962803-9e5f-4ba7-8243-3dda1deacc3d

📥 Commits

Reviewing files that changed from the base of the PR and between 16f187b and ecbf165.

📒 Files selected for processing (15)
  • cpp/CMakeLists.txt
  • cpp/src/hash/murmurhash3_x86_32.cu
  • cpp/src/hash/murmurhash3_x86_32.cuh
  • cpp/src/stream_compaction/distinct.cu
  • cpp/src/stream_compaction/distinct_helpers.cu
  • cpp/src/stream_compaction/distinct_helpers.cuh
  • cpp/src/stream_compaction/distinct_helpers.hpp
  • cpp/src/stream_compaction/distinct_helpers_flat_nan_equal_any.cu
  • cpp/src/stream_compaction/distinct_helpers_flat_nan_equal_ordered.cu
  • cpp/src/stream_compaction/distinct_helpers_flat_nan_unequal_any.cu
  • cpp/src/stream_compaction/distinct_helpers_flat_nan_unequal_ordered.cu
  • cpp/src/stream_compaction/distinct_helpers_nested_nan_equal_any.cu
  • cpp/src/stream_compaction/distinct_helpers_nested_nan_equal_ordered.cu
  • cpp/src/stream_compaction/distinct_helpers_nested_nan_unequal_any.cu
  • cpp/src/stream_compaction/distinct_helpers_nested_nan_unequal_ordered.cu

Comment thread cpp/src/stream_compaction/distinct_helpers.cuh Outdated

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

Nice. All this makes sense.

thrust::for_each(rmm::exec_policy_nosync(stream, cudf::get_current_device_resource_ref()),
cuda::counting_iterator<cudf::size_type>{0},
cuda::counting_iterator{num_rows},
[set_ref, keep, reduction_results = reduction_results.begin()] __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.

Device lambdas should declare trailing return types, but I am unsure if that also applies when void. We typically discover these requirements when we update compilers or CCCL, not from cuDF source changes...

@davidwendt

Copy link
Copy Markdown
Contributor

I would be curious to know how the aggregate build time compares to the original single .cu build time.

@coderabbitai coderabbitai Bot mentioned this pull request Jul 28, 2026
3 tasks
@PointKernel

PointKernel commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@davidwendt I reran both sides from empty build directories with identical Release/SM100/CUDA 13.0 settings and all compiler caches disabled (no sccache/ccache launcher):

  • Compile time: 340.916 s for the original single TU vs. 359.458 s summed across the nine split TUs (+18.542 s / +5.44%).
  • Longest individual compile: 340.916 s vs. 52.257 s (84.7% lower).
  • TU object size: 2.095 MiB for the original distinct_helpers.cu.o vs. 4.659 MiB summed across the nine split objects (2.224x / +122.4%).

I couldn't find the original Slack discussion, but with sccache we effectively have unlimited parallelism, so what really matters is the build time of the longest single TU. That's why similar optimization efforts are all evaluated based on the longest TU build time before and after the change.

@PointKernel PointKernel added the DO NOT MERGE Hold off on merging; see PR for details label Jul 28, 2026
@PointKernel

Copy link
Copy Markdown
Member Author

One concern is that this doubles the binary size. Reviewers, do you think we should put this on hold or merge it as is?

@davidwendt

Copy link
Copy Markdown
Contributor

One concern is that this doubles the binary size. Reviewers, do you think we should put this on hold or merge it as is?

I assume this is the .o sizes. How does it affect the libcudf.so size?

@PointKernel

Copy link
Copy Markdown
Member Author

One concern is that this doubles the binary size. Reviewers, do you think we should put this on hold or merge it as is?

I assume this is the .o sizes. How does it affect the libcudf.so size?

Yes, it's just the TU .o size:

TU object size: 2.095 MiB for the original distinct_helpers.cu.o vs. 4.659 MiB summed across the nine split objects (2.224x / +122.4%).

I had the agent running all day yesterday. The best result it found without increasing binary size was using the custom dispatcher and custom kernel, which reduced the build time from 662s to around 400s. That said, for build-time-critical TUs, increasing the TU size by 2 MB seems like a reasonable tradeoff given the amount of build time it saves. For non-build-time-critical TUs, though, we should avoid increasing the .o size as much as possible.

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

Labels

CMake CMake build issue improvement Improvement / enhancement to an existing function libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants