Parrot GPU Library

repository·main·Indexed 43 days ago

https://github.com/nvlabs/parrot

A header-only array fusion GPU library built on NVIDIA's CCCL (Thrust/CUB). Parrot provides high-performance, GPU-accelerated operations using a chainable, lazy-evaluation API to reduce code complexity. It supports fused operations, materializing operations (reductions, scans, permutations), and includes the kp (Kernel Profiler) CLI for profiling CUDA kernels via nsys.

Tokens
5.9K
Snippets
20
Records
29
Agent score
55%

What's inside Parrot

  1. What is Parrot?

    main
    Parrot is a C++ library designed for fused array operations using CUDA and NVIDIA's CCCL libraries (Thrust/CUB). It provides GPU-accelerated operations with fused evaluation semantics, which allows you to chain multiple operations together without the performance penalty of creating unnecessary intermediate arrays in memory.
  2. Key Features of Parrot

    main

    Parrot provides several core capabilities for GPU-accelerated array programming:

    • Implicit Fusion: Array operations are automatically fused to minimize memory bandwidth usage.
    • GPU Acceleration: Leverages NVIDIA's CCCL (Thrust/CUB) for high-performance execution.
    • Chainable API: Operations can be linked together in a clean, readable syntax.
    • Header-only: Easy integration via #include "parrot.hpp".
  3. How fusion_array operations work

    main

    The fusion_array class is the core of Parrot, designed for fused evaluation of array operations.

    Operations in Parrot are categorized by how they handle data:

    1. Fused Operations (Lazy): Most unary maps (like abs, log, exp), binary maps (like add, times), and reshapes are lazy. They do not compute results immediately but instead build a computation graph that can be fused into a single pass when the data is eventually accessed.
    2. Conditionally Fused Operations: Operations like filter, where, and keep depend on boolean conditions. These are part of the lazy evaluation pipeline.
    3. Materializing Operations: Certain operations require the full data to be computed and stored in memory to proceed. These include:
      • Reductions: sum, prod, max, min, etc.
      • Scans: sums, prods, maxs, etc.
      • Permutations: sort, sort_by.
      • Compactions: rle (Run-Length Encoding).
      • Masked Replication: replicate(mask_array) where the repetition pattern is variable.
  4. Generate and view documentation

    main

    To generate documentation, you need Doxygen and optionally Sphinx (requires pip install -r requirements.txt).

    1. Generate Doxygen XML documentation:
      doxygen Doxyfile
    2. Build Sphinx HTML documentation:
      cd docs
      sphinx-build -b html . build/html
    3. View the documentation: The output is located in docs/build/html/. You can open it with:
      open docs/build/html/index.html
    # Generate Doxygen
    doxygen Doxyfile
    
    # Build Sphinx HTML
    cd docs
    sphinx-build -b html . build/html
    
    # Open in browser
    open build/html/index.html
  5. Configure CUDA environment variables

    main

    To ensure the build system can find CUDA, add the following to your shell configuration file (e.g., ~/.bashrc or ~/.zshrc).

    For standard CUDA Toolkit installations:

    export CUDA_HOME=/usr/local/cuda
    export PATH=$CUDA_HOME/bin:$PATH
    export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH

    For NVIDIA HPC SDK installations:

    export CUDA_HOME=/opt/nvidia/hpc_sdk/Linux_x86_64/26.5/cuda
    export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/26.5/compilers/bin:$PATH

    After updating your config, reload it using source ~/.bashrc (or your respective config file).

    # Standard CUDA Toolkit
    export CUDA_HOME=/usr/local/cuda
    export PATH=$CUDA_HOME/bin:$PATH
    export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
    
    # Reload shell
    source ~/.bashrc
  6. Integrate Parrot into a CMake project

    main

    You can integrate Parrot into your C++ projects using CMake's FetchContent module. This method automatically downloads the Parrot library and its transitive dependencies (like CCCL) and configures the include paths.

    By linking your target against the parrot target, you automatically propagate include paths for both Parrot and CCCL, ensuring compatibility with required components like Thrust 3.2.0+.

    # Include FetchContent module for downloading dependencies
    include(FetchContent)
    
    # Fetch the official parrot library from NVlabs/parrot
    FetchContent_Declare(
      parrot
      GIT_REPOSITORY https://github.com/NVlabs/parrot.git
      GIT_TAG main
      GIT_SHALLOW TRUE
    )
    
    # Make parrot available (also fetches CCCL transitively)
    FetchContent_MakeAvailable(parrot)
    
    # Link your target against parrot — this propagates both parrot
    # and CCCL include paths automatically
    target_link_libraries(my_target parrot)
  7. Run parrot tests

    main

    The project uses doctest for unit testing. You can run tests in several ways:

    Run all tests via CTest:

    ctest

    Run the main test executable directly:

    ./parrot_tests

    Run specific test categories:

    ./test_basic
    # Run all tests
    ctest
    
    # Or run the main test binary
    ./parrot_tests
  8. Build your project with CMake

    main

    After configuring your CMakeLists.txt with the FetchContent steps, build your project using standard CMake workflows. The first build will take longer as it automatically handles downloading and building Parrot and its dependencies.

    mkdir build && cd build
    cmake ..
    make -j$(nproc)
  9. Use Sweep mode to profile across input sizes

    main

    Sweep mode allows you to profile implementations across a geometric range of input sizes (a 10x range) and generates a line chart comparing total kernel time against the input size $N$.

    Requirements:

    • The Python files being profiled must be able to accept $N$ as a command-line argument. If the argument is omitted, the script will fall back to its default value.

    Workflow:

    1. Run the command with the -n flag specifying the lower and upper bounds (e.g., 10K to 10M).
    2. kp will execute the files with $N$ values at each 10x step (e.g., 10K, 100K, 1M, 10M).
    3. Results are saved to nsys_results/sweep_results.csv. You can use the -p (plot-only) flag later to re-generate plots without re-running the expensive profiling step.
    kp -n 10K 10M max_abs_diff2
  10. Build the parrot project

    main

    Follow these steps to compile the project from the repository root:

    1. Create and enter a build directory:
      mkdir -p build
      cd build
    2. Configure the project with CMake:
      cmake ..
    3. Build the project using all available CPU cores:
      cmake --build . -j$(nproc)
    mkdir -p build && cd build
    cmake ..
    cmake --build . -j$(nproc)
  11. Prerequisites for building parrot

    main

    To build and test parrot, ensure your system meets the following requirements:

    • CMake: version 3.10 or higher
    • C++ Compiler: Must support C++20
    • NVIDIA CUDA Toolkit: version 13.0 or later
    • NVIDIA GPU: Compute capability 7.0 or higher

    Optional (for documentation generation):

  12. Quick Start with Parrot

    main

    Parrot is a header-only GPU library for array fusion. You can integrate it by including parrot.hpp. It uses a chainable API that allows you to perform complex operations on arrays without manual intermediate materialization, thanks to lazy evaluation semantics.

    To use it, create arrays using parrot::array and chain operations using standard mathematical operators.

    #include "parrot.hpp"
    
    int main() {
        // Create arrays
        auto A = parrot::array({3, 4, 0, 8, 2});
        auto B = parrot::array({6, 7, 2, 1, 8});
        auto C = parrot::array({2, 5, 7, 4, 3});
        
        // Chain operations
        (B * C + A).print();  // Output: 15 39 14 12 26
    }