OOT Module Integration
Relevant source files
The following files were used as context for generating this wiki page:
The gr-cuda project provides a framework for integrating GPU-accelerated Out-Of-Tree (OOT) modules into GNU Radio 3.10+. It streamlines the process of moving data between the host (CPU) and device (GPU) using a specialized cuda_buffer system, allowing developers to focus on kernel implementation rather than manual memory management.
Integration supports two primary development paths: high-performance C++ blocks using the CUDA Toolkit and rapid-prototyping Python blocks using CuPy. Both paths leverage a zero-copy pipeline where data remains on the GPU between successive blocks, significantly reducing PCIe overhead.
Sources: README.md:1-25, lib/CMakeLists.txt:46-60
Architecture and Data Flow
The core of the OOT integration is the cuda_buffer, which implements circular buffers on the GPU using Virtual Memory Management (VMM). This allows GPU kernels to access data via device pointers directly within the work() function.
Zero-Copy Pipeline Flow
The following diagram illustrates how data flows through an OOT module using the gr-cuda infrastructure.
The cuda_buffer handles host-to-device (H2D) and device-to-host (D2H) transfers automatically when a GPU block is connected to a standard CPU block.
Sources: README.md:18-24, include/gnuradio/cuda/cuda_block_helper.h:20-40
C++ Block Integration
C++ OOT blocks must inherit from the cuda_block base class. This provides a managed CUDA stream and access to synchronization helpers that ensure data integrity across the asynchronous GPU execution pipeline.
Synchronization Logic
C++ implementations require explicit synchronization calls to manage the state of input and output buffers.
wait_for_work(): Called before kernel launch. It ensures input data is ready on the device and output buffers are safe to overwrite.mark_work_done(): Called after kernel launch. It signals to downstream blocks that new data is available and tells upstream blocks that input data has been consumed.
Python/CuPy Block Integration
The framework enables writing GPU blocks in Python by inheriting from specialized cuda base classes. Input and output items are provided as CuPy arrays, which reside directly in GPU memory.
Supported Python Base Classes
| Class Name | Usage | Sources |
|---|---|---|
cuda.sync_block | For 1:1 input-to-output rate blocks. | python/cuda/qa_cuda_block.py:22 |
cuda.decim_block | For blocks that decrease the sample rate. | python/cuda/qa_cuda_block.py:75 |
cuda.interp_block | For blocks that increase the sample rate. | python/cuda/qa_cuda_block.py:89 |
cuda.basic_block | For general work blocks with flexible rates. | python/cuda/qa_cuda_block.py:103 |
Python Implementation Example
import cupy as cp
from gnuradio import cuda
class my_oot_block(cuda.sync_block):
def __init__(self):
cuda.sync_block.__init__(self, "my_oot_block", [np.complex64], [np.complex64])
def work(self, input_items, output_items):
# input_items[0] is a CuPy array on the GPU
cp.multiply(input_items[0], 2.0, out=output_items[0])
return len(output_items[0])
Sources: README.md:71-85, python/cuda/qa_cuda_block.py:22-45
Build System and Tooling
Integrating an OOT module requires specific CMake configurations and binding tools to bridge C++ and Python.
CMake Configuration
OOT modules must link against the gnuradio-cuda library and the CUDA Toolkit.
target_link_libraries(
your_oot_module
PUBLIC
gnuradio::gnuradio-runtime
gnuradio::gnuradio-cuda
CUDA::cudart
)
Sources: lib/CMakeLists.txt:46-55, CMakeLists.txt:135-145
Binding Generation
The project includes a binding tool (bind_oot_file.py) that uses pybind11 to create Python interfaces for C++ OOT headers. It specifically manages namespaces and inclusion roots for the gr-cuda environment.
Sources: python/cuda/bindings/bind_oot_file.py:53-75, python/cuda/bindings/CMakeLists.txt:38-40
Header Hash Verification
To prevent synchronization issues between C++ headers and Python bindings, the project uses a pre-commit hook that verifies MD5 hashes recorded in the *_python.cc files.
- Metadata: Binding files contain
BINDTOOL_HEADER_FILE_HASH. - Verification: The script
check_bindtool_header_hashes.pycompares this to the actual header file on disk.
Sources: scripts/check_bindtool_header_hashes.py:35-115
Summary
OOT Module Integration in gr-cuda relies on the cuda_buffer for transparent memory management and the cuda_block / cuda.sync_block base classes for implementation. By utilizing the provided synchronization helpers and build system macros, developers can create GPU-accelerated blocks that seamlessly interoperate with both CPU and other GPU blocks in a GNU Radio flowgraph.