Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions ucxx_cudf_example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cmake_minimum_required(VERSION 3.26 FATAL_ERROR)

# C++ only - no CUDA compiler needed, just CUDA runtime
project(ucxx_cudf_example VERSION 1.0.0 LANGUAGES C CXX)

###################################################################################################
# - Conda environment -----------------------------------------------------------------------------

if(DEFINED ENV{CONDA_PREFIX})
set(CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX};${CMAKE_PREFIX_PATH}")
set(CONDA_INCLUDE_DIRS "$ENV{CONDA_PREFIX}/include")
set(CONDA_LINK_DIRS "$ENV{CONDA_PREFIX}/lib")
# Point CUDAToolkit to conda environment
set(CUDAToolkit_ROOT "$ENV{CONDA_PREFIX}")
message(STATUS "Conda environment detected, CMAKE_PREFIX_PATH set to: ${CMAKE_PREFIX_PATH}")
endif()

###################################################################################################
# - Build type ------------------------------------------------------------------------------------

set(DEFAULT_BUILD_TYPE "Release")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
endif()

###################################################################################################
# - Compiler options ------------------------------------------------------------------------------

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif()

###################################################################################################
# - Find dependencies -----------------------------------------------------------------------------

# Find CUDA Toolkit (modern CMake way, provides CUDA::cudart target)
find_package(CUDAToolkit REQUIRED)
message(STATUS "Found CUDA Toolkit: ${CUDAToolkit_VERSION}")

# Find cudf (installed via conda)
find_package(cudf REQUIRED)
message(STATUS "Found cudf: ${cudf_VERSION}")

# Find ucxx (installed via conda)
find_package(ucxx REQUIRED)
message(STATUS "Found ucxx: ${ucxx_VERSION}")

# Find rmm (installed via conda)
find_package(rmm REQUIRED)
message(STATUS "Found rmm: ${rmm_VERSION}")

###################################################################################################
# - Build executable ------------------------------------------------------------------------------

add_executable(ucxx_cudf_example src/ucxx_cudf_example.cpp)

# Add conda paths if available
if(CONDA_INCLUDE_DIRS)
target_include_directories(ucxx_cudf_example PRIVATE "${CONDA_INCLUDE_DIRS}")
endif()

if(CONDA_LINK_DIRS)
target_link_directories(ucxx_cudf_example PRIVATE "${CONDA_LINK_DIRS}")
endif()

target_link_libraries(ucxx_cudf_example PRIVATE
cudf::cudf
ucxx::ucxx
rmm::rmm
CUDA::cudart # CUDA runtime library
)

###################################################################################################
# - Install targets -------------------------------------------------------------------------------

include(GNUInstallDirs)

install(TARGETS ucxx_cudf_example
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
56 changes: 56 additions & 0 deletions ucxx_cudf_example/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# UCXX cuDF Example - Dockerfile
# This Dockerfile creates an environment for building and running
# an example that sends cuDF columns via UCXX communication library.

ARG CUDA_VERSION=12.6.3
ARG LINUX_VERSION=ubuntu22.04

FROM nvidia/cuda:${CUDA_VERSION}-base-${LINUX_VERSION}

ARG DEBIAN_FRONTEND=noninteractive
ARG PARALLEL_LEVEL=8
ENV PARALLEL_LEVEL=${PARALLEL_LEVEL}

# Install basic dependencies
RUN apt-get update -y && apt-get install -y \
build-essential \
git \
wget \
curl \
ca-certificates \
libssl-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install Miniforge (uses conda-forge by default, no ToS acceptance required)
RUN wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O /tmp/miniforge.sh \
&& bash /tmp/miniforge.sh -b -p /opt/conda \
&& rm /tmp/miniforge.sh

ENV PATH="/opt/conda/bin:${PATH}"
ENV CONDA_PREFIX="/opt/conda"

# Enable conda in bash
SHELL ["/bin/bash", "-c"]

# Copy the project files
COPY . /rapids/ucxx_cudf_example

WORKDIR /rapids/ucxx_cudf_example

# Create the conda environment with libcudf and libucxx from conda
RUN conda env create -f /rapids/ucxx_cudf_example/conda/ucxx_cudf_example.yml

# Configure and build the example
RUN source activate ucxx_cudf_example \
&& cmake \
-DCMAKE_BUILD_TYPE=Release \
-S /rapids/ucxx_cudf_example \
-B /rapids/ucxx_cudf_example/build \
&& cmake --build /rapids/ucxx_cudf_example/build -j${PARALLEL_LEVEL}

# Set up entrypoint to activate conda environment
RUN echo "source activate ucxx_cudf_example" >> ~/.bashrc

SHELL ["/bin/bash", "-l"]
CMD ["/bin/bash", "-l"]
177 changes: 177 additions & 0 deletions ucxx_cudf_example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# UCXX cuDF Example

This example demonstrates how to create a cuDF integer column using `cudf::sequence` and transfer it between endpoints using the UCXX communication library.

## Overview

The example:
1. Creates a cuDF column with integer sequence `[0, 1, 2, ..., N-1]` using `cudf::sequence`
2. Sets up a UCXX listener and client endpoint (loopback connection)
3. Sends the column data from the listener endpoint to the client endpoint
4. Verifies the received data matches the original sequence
5. Reconstructs a new cuDF column from the received data

This demonstrates a pattern useful for distributed GPU computing where cuDF DataFrames/columns need to be transferred between nodes.

## Dependencies

All dependencies are installed via conda (no source compilation required):
- **libcudf** (>=25.08) - RAPIDS cuDF library (requires C++20)
- **libucxx** (>=0.40) - UCX C++ bindings
- **rmm** (>=25.08) - RAPIDS Memory Manager
- **cuda-nvcc** - NVIDIA CUDA compiler (>=12.0)

## Quick Start

### Option 1: Build with Conda (Local)

```bash
./build_with_conda.sh
```

Then run:
```bash
conda activate ucxx_cudf_example
./build/ucxx_cudf_example
```

### Option 2: Build with Docker

```bash
./build_with_docker.sh
```

Then run:
```bash
docker run --gpus all --rm -it ucxx_cudf_example ./build/ucxx_cudf_example
```

## Usage

```
Usage: ucxx_cudf_example [parameters]

Creates a cuDF integer sequence column and sends it between endpoints
using UCXX communication library.

Parameters:
-p <port> Port number to listen at (default: 12345)
-s <size> Number of elements in the sequence (default: 1000)
-h Print this help
```

## Testing

### Basic Test
Run with default parameters (1000 elements):
```bash
./build/ucxx_cudf_example
```

### Test with Larger Data
```bash
# 100,000 elements (~400KB)
./build/ucxx_cudf_example -s 100000

# 1 million elements (~4MB)
./build/ucxx_cudf_example -s 1000000
```

### Test with Docker
```bash
# Basic test
docker run --gpus all --rm -it ucxx_cudf_example ./build/ucxx_cudf_example

# Test with 100K elements
docker run --gpus all --rm -it ucxx_cudf_example ./build/ucxx_cudf_example -s 100000

# Interactive shell for debugging
docker run --gpus all --rm -it ucxx_cudf_example bash
```

### Expected Output

A successful run produces output like:
```
=== UCXX cuDF Example ===
Port: 12345
Sequence size: 1000

Created cuDF sequence column with 1000 elements [0, 1, 2, ..., 999]
Column data size: 4000 bytes
Sender Column preview: [0, 1, 2, 3, 4, ..., 995, 996, 997, 998, 999]

Setting up UCXX communication...
Waiting for connection...
Server received connection request from 127.0.0.1:xxxxx
Connection established!

Performing wireup exchange...
Wireup complete!

Sending cuDF column data...
Transfer complete!

Receiver Column preview: [0, 1, 2, 3, 4, ..., 995, 996, 997, 998, 999]

Verifying received data...
Verification PASSED! All 1000 elements match.

Creating new cuDF column from received data...
Created new cuDF column with 1000 elements

=== Example completed successfully ===
```

The key indicators of success:
- `Verification PASSED!` - Data was transferred correctly
- `Example completed successfully` - All steps completed without errors

## Key Concepts

### cudf::sequence

Creates a column filled with a sequence of values:
```cpp
cudf::numeric_scalar<int32_t> init_scalar(0, true, stream); // Start at 0
cudf::numeric_scalar<int32_t> step_scalar(1, true, stream); // Step by 1
auto column = cudf::sequence(size, init_scalar, step_scalar);
```

### UCXX Tag Send/Receive

Tag-based messaging for point-to-point communication:
```cpp
// Send data
endpoint->tagSend(data_ptr, size, ucxx::Tag{tag_value});

// Receive data
endpoint->tagRecv(buffer_ptr, size, ucxx::Tag{tag_value}, ucxx::TagMaskFull);
```

## Extending This Example

To send more complex cuDF data structures:

1. **DataFrames**: Serialize column-by-column, sending metadata first (column names, types, sizes)
2. **Strings columns**: Use `cudf::strings_column_view` to access the offsets and char data separately
3. **Nullable columns**: Also transfer the null bitmask

## Project Structure

```
ucxx_cudf_example/
├── build_with_conda.sh # Build script using conda
├── build_with_docker.sh # Build script using Docker
├── CMakeLists.txt # CMake build configuration
├── Dockerfile # Docker image definition
├── README.md # This file
├── conda/
│ └── ucxx_cudf_example.yml # Conda environment specification
└── src/
└── ucxx_cudf_example.cpp # Main example source code
```

## License

Apache-2.0
Loading