QA and Testing Framework
Relevant source files
The following files were used as context for generating this wiki page:
The QA and Testing Framework for gr-cuda is a comprehensive system designed to validate the functional correctness, performance, and stability of GPU-accelerated GNU Radio blocks. It leverages the gnuradio.gr_unittest framework, Python's unittest library, and CMake's CTest utility to execute a wide variety of tests ranging from simple block instantiation to long-duration stress tests involving complex fan-in/fan-out topologies.
The framework ensures that both C++ CUDA implementations and Python-based CuPy blocks behave identically to their CPU counterparts. It covers data type variations (float32, complex64, int32), vector lengths, and specific CUDA-related behaviors such as buffer management, stream synchronization, and automated host-to-device transfers.
Test Infrastructure and Configuration
The testing suite is integrated into the build system via CMake and configured for Python-based test runners.
CMake Integration
The root CMakeLists.txt enables testing using enable_testing(). The python/cuda/CMakeLists.txt file defines the registration of individual Python QA scripts using the GR_ADD_TEST macro. This allows developers to run the entire suite using the ninja test or ctest commands.
Sources: CMakeLists.txt:23, python/cuda/CMakeLists.txt:46-130
Python Test Environment
The project uses pytest for test discovery and ruff for linting, as defined in pyproject.toml. The configuration ensures that files matching qa_*.py are treated as test modules.
Sources: pyproject.toml:1-10
Architecture and Test Flow
Tests typically follow a standard pattern: generating reference data on the CPU, passing data through a "Device Under Test" (DUT) block within a GNU Radio top_block, and comparing the result against an expected output using numpy.testing.
The diagram shows the standard lifecycle of a QA test case in the gr-cuda framework.
Sources: python/cuda/qa_add.py:20-43, python/cuda/qa_cupy_math.py:19-35
Functional Validation
Math and Signal Processing Blocks
Functional tests validate that CUDA/CuPy implementations produce results within acceptable tolerances (usually rtol=1e-5) compared to standard NumPy or CPU-based GNU Radio blocks.
| Feature Tested | Relevant Source File | Description |
|---|---|---|
| Arithmetic | qa_add.py, qa_add_cupy.py | Validates add_ff, add_cc, and add_ii for multiple streams and vector lengths. |
| Math Ops | qa_cupy_math.py | Tests magnitude, magnitude squared, and log10 operations using CuPy. |
| FFT | qa_fft.py | Compares CUDA and CuPy FFT results against gnuradio.fft for various sizes and windows. |
| Const Ops | qa_multiply_const.py | Validates scalar multiplication across different data types. |
Sources: python/cuda/qa_add.py:14-105, python/cuda/qa_cupy_math.py:14-150, python/cuda/qa_fft.py:75-135
Base Class Testing
The qa_cuda_block.py file contains comprehensive tests for different CUDA block types, ensuring that the inheritance and work / general_work mechanisms function correctly for GPU-specific buffers.
- sync_block: Tested for simple 1:1 input/output mapping.
- decim_block: Validates downsampling behavior on the GPU.
- interp_block: Validates upsampling/interpolation.
- basic_block: Tests the
general_workandforecastmechanisms, includingconsume_each.
Sources: python/cuda/qa_cuda_block.py:12-160
Stress and Race Condition Testing
The framework includes specialized tests for long-duration execution and synchronization across multiple GPU streams.
Long Race Stress Tests
qa_long_race_stress.py implements a complex topology to detect synchronization issues in the cuda_buffer logic. It uses environment variables to control test intensity:
GR_CUDA_LONG_STRESS: Enables the test (default is skipped).GR_CUDA_STRESS_SECONDS: Test duration.GR_CUDA_STRESS_CHAIN: Number of sequential GPU blocks.GR_CUDA_STRESS_FANOUT: Degree of parallel branching.
This sequence illustrates the stress test flow designed to catch buffer sync issues during high-throughput fan-in/fan-out operations.
Synchronization and Timing
Tests such as qa_stress_sync.py verify that long chains of CuPy blocks (e.g., 100 blocks) correctly manage synchronization between their respective CUDA streams without data corruption.
Sources: python/cuda/qa_stress_sync.py:24-65
Custom Sink/Source Components for Testing
The framework utilizes custom Python blocks to facilitate complex validations within flowgraphs:
| Class Name | File | Purpose |
|---|---|---|
wrap_check_sink | qa_long_race_stress.py | Validates a repeating known sequence and tracks mismatch counts to find buffer sync issues. |
_const_source_f32 | qa_cuda_block.py | A CUDA-based source block producing constant values directly into GPU memory. |
_sum_sink_f32 | qa_cuda_block.py | A CUDA-based sink that performs accumulation on the GPU to verify device-to-device transfers. |
Sources: python/cuda/qa_long_race_stress.py:20-55, python/cuda/qa_cuda_block.py:136-160
Summary
The QA and Testing Framework in gr-cuda provides a robust validation layer that ensures GPU acceleration does not compromise the reliability of signal processing. By combining standard unit tests with intensive stress testing and cross-platform (CPU/GPU) reference checks, the framework maintains the integrity of the zero-copy GPU pipeline and the automated buffer management system.