Skip to content

Build libcudf_streaming comm benchmarks with partial MPI/UCXX availability - #22860

Merged
rapids-bot[bot] merged 9 commits into
NVIDIA:mainfrom
pentschev:libcudf-streaming-optional-mpi-ucxx-build
Jun 12, 2026
Merged

Build libcudf_streaming comm benchmarks with partial MPI/UCXX availability#22860
rapids-bot[bot] merged 9 commits into
NVIDIA:mainfrom
pentschev:libcudf-streaming-optional-mpi-ucxx-build

Conversation

@pentschev

Copy link
Copy Markdown
Contributor

This updates libcudf_streaming so communication-dependent examples and benchmarks no longer require both MPI and UCXX to be present at configure time.

Changes:

  • Add centralized optional MPI/UCXX detection for libcudf_streaming.
  • Propagate independent MPI/UCXX support into the RapidsMPF CPM configuration.
  • Add shared optional communication link/compile definitions for downstream targets.
  • Build shuffle benchmarks when at least one of MPI or UCXX is available.
  • Skip shuffle benchmarks when neither MPI nor UCXX is available.
  • Keep NDSH benchmarks buildable without MPI/UCXX because they support single communicator.
  • Skip MPI-only example_shuffle when MPI is unavailable.
  • Fix example_shuffle CUDA compilation by adding the required extended-lambda flag.

@pentschev pentschev self-assigned this Jun 11, 2026
@pentschev
pentschev requested review from a team as code owners June 11, 2026 21:06
@pentschev pentschev added 3 - Ready for Review Ready for review by team improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Jun 11, 2026
@coderabbitai

coderabbitai Bot commented Jun 11, 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
📝 Walkthrough

Walkthrough

This PR makes MPI and UCXX optional for libcudf_streaming: it adds a CMake module that detects available backends and exports an interface target, introduces communicator availability helpers, gates benchmark/example targets on those detections, and adds compile-time guards plus runtime validation in benchmark and NDSH code.

Changes

Optional Communicator Support Refactoring

Layer / File(s) Summary
CMake foundation for optional communication
cpp/libcudf_streaming/cmake/ConfigureOptionalCommunication.cmake, cpp/libcudf_streaming/CMakeLists.txt, cpp/libcudf_streaming/cmake/thirdparty/get_rapidsmpf.cmake
Add a CMake module that detects MPI/UCXX when benchmarks/examples are enabled, defines CUDF_STREAMING_FOUND_* and CUDF_STREAMING_HAVE_* flags, creates cudf_streaming::optional_communication INTERFACE target, provides cudf_streaming_skip_optional_target(), and pass MPI/UCXX support options to rapidsmpf.
Communicator availability utilities
cpp/libcudf_streaming/benchmarks/utils/comm.hpp
New inline helpers report available communicators and a default communicator string based on compile-time feature macros.
Benchmark and examples CMake target configuration
cpp/libcudf_streaming/benchmarks/CMakeLists.txt, cpp/libcudf_streaming/benchmarks/streaming/CMakeLists.txt, cpp/libcudf_streaming/benchmarks/streaming/ndsh/CMakeLists.txt, cpp/libcudf_streaming/examples/CMakeLists.txt
Conditionally build or skip benchmark/example targets based on CUDF_STREAMING_HAVE_COMM / CUDF_STREAMING_HAVE_MPI, and link targets to cudf_streaming::optional_communication instead of direct MPI::MPI_CXX/ucxx::ucxx.
bench_shuffle.cpp implementation with compile-time guards
cpp/libcudf_streaming/benchmarks/bench_shuffle.cpp
Introduce conditional includes and guarded runtime code via CUDF_STREAMING_HAVE_MPI/CUDF_STREAMING_HAVE_UCXX, add unified abort_or_exit, validate communicator availability, use dynamic default communicator, and guard MPI/UCXX init/barrier/finalize.
bench_streaming_shuffle.cpp implementation
cpp/libcudf_streaming/benchmarks/streaming/bench_streaming_shuffle.cpp
Apply the same guarded includes, unified error handling, dynamic communicator defaults, and conditional initialization/barrier/finalize as bench_shuffle.
NDSH utils.hpp: communicator helpers and API
cpp/libcudf_streaming/benchmarks/streaming/ndsh/utils.hpp
Declare comm-type name/availability/parsing helpers, change ProgramOptions::comm_type compile-time default selection, and move FinalizeMPI destructor to an out-of-line declaration.
NDSH utils.cpp: communicator detection and initialization
cpp/libcudf_streaming/benchmarks/streaming/ndsh/utils.cpp
Implement comm-type availability, available-types string, and parsing helpers; gate MPI/UCXX includes and create_context initialization on build flags; validate --comm-type at runtime; implement FinalizeMPI::~FinalizeMPI() with MPI guards.
NDSH query file include cleanup
cpp/libcudf_streaming/benchmarks/streaming/ndsh/q01.cpp, q03.cpp, q04.cpp, q09.cpp
Remove direct mpi.h and rapidsmpf/communicator/mpi.hpp includes and keep rapidsmpf/communicator/communicator.hpp for abstract communicator access.
NDSH bench_read.cpp argument parsing updates
cpp/libcudf_streaming/benchmarks/streaming/ndsh/bench_read.cpp
Use rapidsmpf helpers for comm-type names, parsing, and availability checks; derive default comm_type from embedded ProgramOptions instead of a hardcoded value.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • rapidsai/cudf#22853: Overlapping changes to libcudf_streaming benchmark CMake wiring and optional communication support.

Suggested reviewers

  • KyleFromNVIDIA
  • bdice
  • mroeschke
  • davidwendt
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% 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 PR title accurately summarizes the main change: enabling partial MPI/UCXX availability for building libcudf_streaming benchmarks, which is the core objective of this changeset.
Description check ✅ Passed The PR description is directly related to the changeset and provides clear details about the motivation and implementation approach for allowing partial MPI/UCXX availability.
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.

✏️ 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.

@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. CMake CMake build issue labels Jun 11, 2026

@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/libcudf_streaming/benchmarks/streaming/bench_streaming_shuffle.cpp (1)

388-394: 💤 Low value

Consider using RAPIDSMPF_EXPECTS for consistency with bench_shuffle.cpp.

The null check pattern here differs from bench_shuffle.cpp (lines 246-249) which uses RAPIDSMPF_EXPECTS. While both approaches work correctly, using the same pattern would improve consistency across the benchmark codebase.

♻️ Suggested change for consistency
 `#ifdef` CUDF_STREAMING_HAVE_UCXX
     auto ucxx = std::dynamic_pointer_cast<rapidsmpf::ucxx::UCXX>(comm);
-    if (ucxx == nullptr) {
-      log.print("Expected UCXX communicator when using bootstrap mode");
-      throw std::runtime_error{"Expected UCXX communicator when using bootstrap mode"};
-    }
+    RAPIDSMPF_EXPECTS(
+      ucxx != nullptr, "Expected UCXX communicator when using bootstrap mode", std::runtime_error);
     ucxx->barrier();
🤖 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/libcudf_streaming/benchmarks/streaming/bench_streaming_shuffle.cpp`
around lines 388 - 394, Replace the manual null-check and throw in the bootstrap
UCXX communicator block with the RAPIDSMPF_EXPECTS macro for consistency: locate
the dynamic_pointer_cast to rapidsmpf::ucxx::UCXX (variable ucxx) and the
subsequent null-check/throw, and change it to use RAPIDSMPF_EXPECTS(ucxx !=
nullptr, "Expected UCXX communicator when using bootstrap mode") (or equivalent
macro signature used in bench_shuffle.cpp) and then call ucxx->barrier(); so
behavior remains identical but matches the pattern used in bench_shuffle.cpp.
🤖 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/libcudf_streaming/benchmarks/streaming/bench_streaming_shuffle.cpp`:
- Around line 388-394: Replace the manual null-check and throw in the bootstrap
UCXX communicator block with the RAPIDSMPF_EXPECTS macro for consistency: locate
the dynamic_pointer_cast to rapidsmpf::ucxx::UCXX (variable ucxx) and the
subsequent null-check/throw, and change it to use RAPIDSMPF_EXPECTS(ucxx !=
nullptr, "Expected UCXX communicator when using bootstrap mode") (or equivalent
macro signature used in bench_shuffle.cpp) and then call ucxx->barrier(); so
behavior remains identical but matches the pattern used in bench_shuffle.cpp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 09cb6ce0-6734-416f-b107-f3a9cae7028e

📥 Commits

Reviewing files that changed from the base of the PR and between a643d62 and 0ee5725.

📒 Files selected for processing (17)
  • cpp/libcudf_streaming/CMakeLists.txt
  • cpp/libcudf_streaming/benchmarks/CMakeLists.txt
  • cpp/libcudf_streaming/benchmarks/bench_shuffle.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/CMakeLists.txt
  • cpp/libcudf_streaming/benchmarks/streaming/bench_streaming_shuffle.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/CMakeLists.txt
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/bench_read.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q01.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q03.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q04.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q09.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/utils.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/utils.hpp
  • cpp/libcudf_streaming/benchmarks/utils/comm.hpp
  • cpp/libcudf_streaming/cmake/ConfigureOptionalCommunication.cmake
  • cpp/libcudf_streaming/cmake/thirdparty/get_rapidsmpf.cmake
  • cpp/libcudf_streaming/examples/CMakeLists.txt
💤 Files with no reviewable changes (4)
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q09.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q01.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q04.cpp
  • cpp/libcudf_streaming/benchmarks/streaming/ndsh/q03.cpp

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

Had some comments and questions

Comment on lines +137 to +144
std::optional<CommType> parse_comm_type(std::string_view name)
{
auto const names = comm_type_names();
for (std::size_t i = 0; i < names.size(); ++i) {
if (name == names[i]) { return static_cast<CommType>(i); }
}
return std::nullopt;
}

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.

nit. optional is not really needed it seems.

Suggested change
std::optional<CommType> parse_comm_type(std::string_view name)
{
auto const names = comm_type_names();
for (std::size_t i = 0; i < names.size(); ++i) {
if (name == names[i]) { return static_cast<CommType>(i); }
}
return std::nullopt;
}
CommType parse_comm_type(std::string_view name)
{
auto const names = comm_type_names();
auto it = std::ranges::find(names, name);
return static_cast<CommType>(std::distance(names.begin(), it));
}

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.

It is used to catch cases where the CommType is invalid, e.g., return (name == a_valid_name) ? name : std::nullopt;.

Comment on lines +103 to +120
bool is_comm_type_available(CommType comm_type)
{
switch (comm_type) {
case CommType::SINGLE: return true;
#ifdef CUDF_STREAMING_HAVE_MPI
case CommType::MPI: return true;
#else
case CommType::MPI: return false;
#endif
#ifdef CUDF_STREAMING_HAVE_UCXX
case CommType::UCXX: return true;
#else
case CommType::UCXX: return false;
#endif
case CommType::MAX: return false;
}
return false;
}

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.

Nit. Bit clunky.

Suggested change
bool is_comm_type_available(CommType comm_type)
{
switch (comm_type) {
case CommType::SINGLE: return true;
#ifdef CUDF_STREAMING_HAVE_MPI
case CommType::MPI: return true;
#else
case CommType::MPI: return false;
#endif
#ifdef CUDF_STREAMING_HAVE_UCXX
case CommType::UCXX: return true;
#else
case CommType::UCXX: return false;
#endif
case CommType::MAX: return false;
}
return false;
}
bool is_comm_type_available(CommType comm_type)
{
switch (comm_type) {
case CommType::SINGLE:
return true;
case CommType::MPI:
#ifdef CUDF_STREAMING_HAVE_MPI
return true;
#endif
break;
case CommType::UCXX:
#ifdef CUDF_STREAMING_HAVE_UCXX
return true;
#endif
break;
case CommType::MAX:
break;
}
return false; // Universal fallback
}

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.

Done.

Comment on lines +126 to +133
bool first = true;
for (std::size_t i = 0; i < static_cast<std::size_t>(CommType::MAX); ++i) {
auto const comm_type = static_cast<CommType>(i);
if (!is_comm_type_available(comm_type)) { continue; }
if (!first) { out << ", "; }
out << names[i];
first = false;
}

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.

Nit.

Suggested change
bool first = true;
for (std::size_t i = 0; i < static_cast<std::size_t>(CommType::MAX); ++i) {
auto const comm_type = static_cast<CommType>(i);
if (!is_comm_type_available(comm_type)) { continue; }
if (!first) { out << ", "; }
out << names[i];
first = false;
}
for (std::size_t i = 0; i < static_cast<std::size_t>(CommType::MAX); ++i) {
auto const comm_type = static_cast<CommType>(i);
if (!is_comm_type_available(comm_type)) { continue; }
out << names[i] << ", ";
}

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.

This would then return something like "mpi, ucxx, ". No reason to make that sloppy-looking to save 3 lines of code.

Comment on lines +39 to +45
#ifdef CUDF_STREAMING_HAVE_MPI
return "mpi";
#elif defined(CUDF_STREAMING_HAVE_UCXX)
return "ucxx";
#else
return {};
#endif

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.

What if CUDF_STREAMING_HAVE_MPI & CUDF_STREAMING_HAVE_UCXX both true? This defaults to mpi, but I feel like it should be,

Suggested change
#ifdef CUDF_STREAMING_HAVE_MPI
return "mpi";
#elif defined(CUDF_STREAMING_HAVE_UCXX)
return "ucxx";
#else
return {};
#endif
#ifdef CUDF_STREAMING_HAVE_MPI
#ifdef CUDF_STREAMING_HAVE_UCXX
return "ucxx";
#else
return "mpi";
#endif
#endif
return {};

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.

I'd agree, because UCXX is our main use case. However, I chose to keep the status quo for now because we may have scripts relying on the default communicator to mean mpi. I think it's best to punt this to another PR if we want to make changes to defaults.

Comment on lines +27 to +28
OPTIONS "BUILD_MPI_SUPPORT ${rapidsmpf_build_mpi_support}"
"BUILD_UCXX_SUPPORT ${rapidsmpf_build_ucxx_support}"

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.

If the cmake variables dont match with the released rapidsmpf distribution, would this build rapidsmpf locally?

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.

I don't understand the question, we are just matching what the RapidsMPF distribution delivers. Why would we rebuild?

…ptional-mpi-ucxx-build

# Conflicts:
#	cpp/libcudf_streaming/CMakeLists.txt
#	cpp/libcudf_streaming/benchmarks/CMakeLists.txt
#	cpp/libcudf_streaming/benchmarks/streaming/CMakeLists.txt

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

Seems fine to me. Thanks!

@nirandaperera

Copy link
Copy Markdown
Contributor

/merge

@rapids-bot
rapids-bot Bot merged commit 0b8ef6a into NVIDIA:main Jun 12, 2026
133 of 134 checks passed
@pentschev
pentschev deleted the libcudf-streaming-optional-mpi-ucxx-build branch June 16, 2026 19:07
rapids-bot Bot pushed a commit that referenced this pull request Jun 23, 2026
Adds multi-rank C++ test executables for `cudf_streaming` that exercise the test suite under MPI and UCXX communicators, mirroring rapidsmpf's `mpi_tests`/`ucxx_tests`.

### Changes

- **`cmake/ConfigureOptionalCommunication.cmake`**: Enable MPI/UCXX detection under `BUILD_TESTS` (previously only `BUILD_BENCHMARKS`/`BUILD_EXAMPLES`), so `CUDF_STREAMING_HAVE_MPI`/`CUDF_STREAMING_HAVE_UCXX` are set for test builds.
- **`cmake/thirdparty/get_cudf.cmake`**: Request cudf's optional `testing` component when `BUILD_TESTS` is on, so `cudf::cudftestutil{,_impl}` resolve from the installed (conda) cudf package without a local cudf build.
- **`tests/environment.hpp`**: Refactor `Environment` into an abstract base exposing a polymorphic communicator interface; add `MPI`/`UCXX` to `TestEnvironmentType`. Communicator-specific state (e.g. `mpi_comm_`) moves into the concrete subclasses.
- **`tests/main/mpi.cpp`** (new): `MPIEnvironment` that initializes MPI, builds a `rapidsmpf::MPI` communicator, and provides `barrier()`/`split_comm()`.
- **`tests/main/ucxx.cpp`** (new): `UCXXEnvironment` that bootstraps UCXX over MPI (`init_using_mpi`) with the required CUDA-context/thread-level setup.
- **`tests/main/single.cpp`**: Convert to a `SingleEnvironment` subclass of the new abstract base.
- **`tests/CMakeLists.txt`**: Add a `cudf_streaming_mpirun_test_add` helper and build `cudf_streaming_mpi_tests`/`cudf_streaming_ucxx_tests` (gated on `CUDF_STREAMING_HAVE_MPI`/`UCXX`), registering per-rank `mpirun` ctest cases; apply `CUDF_CUDA_FLAGS` to the shared test sources so the injected cudf testutil `.cu` files compile.

depends on #22860

Authors:
  - Niranda Perera (https://github.com/nirandaperera)
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - Vyas Ramasubramani (https://github.com/vyasr)
  - Peter Andreas Entschev (https://github.com/pentschev)

URL: #22864
@coderabbitai coderabbitai Bot mentioned this pull request Jun 24, 2026
3 tasks
mhaseeb123 pushed a commit to mhaseeb123/cudf that referenced this pull request Jun 24, 2026
Adds multi-rank C++ test executables for `cudf_streaming` that exercise the test suite under MPI and UCXX communicators, mirroring rapidsmpf's `mpi_tests`/`ucxx_tests`.

### Changes

- **`cmake/ConfigureOptionalCommunication.cmake`**: Enable MPI/UCXX detection under `BUILD_TESTS` (previously only `BUILD_BENCHMARKS`/`BUILD_EXAMPLES`), so `CUDF_STREAMING_HAVE_MPI`/`CUDF_STREAMING_HAVE_UCXX` are set for test builds.
- **`cmake/thirdparty/get_cudf.cmake`**: Request cudf's optional `testing` component when `BUILD_TESTS` is on, so `cudf::cudftestutil{,_impl}` resolve from the installed (conda) cudf package without a local cudf build.
- **`tests/environment.hpp`**: Refactor `Environment` into an abstract base exposing a polymorphic communicator interface; add `MPI`/`UCXX` to `TestEnvironmentType`. Communicator-specific state (e.g. `mpi_comm_`) moves into the concrete subclasses.
- **`tests/main/mpi.cpp`** (new): `MPIEnvironment` that initializes MPI, builds a `rapidsmpf::MPI` communicator, and provides `barrier()`/`split_comm()`.
- **`tests/main/ucxx.cpp`** (new): `UCXXEnvironment` that bootstraps UCXX over MPI (`init_using_mpi`) with the required CUDA-context/thread-level setup.
- **`tests/main/single.cpp`**: Convert to a `SingleEnvironment` subclass of the new abstract base.
- **`tests/CMakeLists.txt`**: Add a `cudf_streaming_mpirun_test_add` helper and build `cudf_streaming_mpi_tests`/`cudf_streaming_ucxx_tests` (gated on `CUDF_STREAMING_HAVE_MPI`/`UCXX`), registering per-rank `mpirun` ctest cases; apply `CUDF_CUDA_FLAGS` to the shared test sources so the injected cudf testutil `.cu` files compile.

depends on NVIDIA#22860

Authors:
  - Niranda Perera (https://github.com/nirandaperera)
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - Vyas Ramasubramani (https://github.com/vyasr)
  - Peter Andreas Entschev (https://github.com/pentschev)

URL: NVIDIA#22864
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3 - Ready for Review Ready for review by team 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.

3 participants