Skip to content

Latest commit

 

History

History
234 lines (185 loc) · 7.38 KB

AGENTS.md

File metadata and controls

234 lines (185 loc) · 7.38 KB

AGENTS.md - RMM Development Guide

RMM is a library for CUDA memory management.

Safety Rules for Agents

  • Minimal diffs: Change only what's necessary; avoid drive-by refactors.
  • No mass reformatting: Don't run formatters over unrelated code.
  • No API invention: Align with existing RMM patterns and documented APIs.
  • Don't bypass CI: Don't suggest skipping checks or using --no-verify.
  • CUDA/GPU hygiene: Keep operations stream-ordered, use RMM allocators (never use raw cudaMalloc or other CUDA APIs for device memory, except in the implementation of an RMM memory resource).

Before Finalizing a Change

Ask yourself:

  • What scenarios must be covered? (happy path, edge cases, failure modes)
  • What's the expected behavior contract? (inputs/outputs, errors)
  • Where should tests live? (C++ gtests under cpp/tests/, Python pytest under python/rmm/rmm/tests/)

Code Review Guidelines

For AI-assisted code review (CodeRabbit), see language-specific review guidelines:

  • C++/CUDA: cpp/REVIEW_GUIDELINES.md
  • Python: python/REVIEW_GUIDELINES.md

Build Commands

Devcontainer (username: coder)

build-rmm-cpp -j0      # Build C++ library, accepts CMake flags (-D...)
build-rmm-python -j0   # Build Python package
build-rmm -j0          # Build both C++ and Python, accepts CMake flags (-D...)

Standard Environment (requires conda env from conda/environments/)

./build.sh librmm              # Build and install C++ library
./build.sh librmm -g           # Debug build
./build.sh librmm tests        # Build with tests
./build.sh librmm benchmarks   # Build with benchmarks
./build.sh clean librmm        # Clean rebuild
./build.sh rmm                 # Build and install Python package
./build.sh librmm rmm          # Build both C++ and Python

CMake Direct

cmake -S cpp -B cpp/build -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build cpp/build -j$(nproc)

Test Commands

Devcontainer (username: coder)

test-rmm-cpp      # Run all C++ tests, accepts ctest flags
test-rmm-python   # Run all Python tests, accepts pytest flags

C++ Tests (GoogleTest)

# Run all C++ tests
ctest --test-dir cpp/build --output-on-failure

# Run single test by name pattern
ctest --test-dir cpp/build -R device_uvector

# Run specific test executable directly
./cpp/build/gtests/DEVICE_UVECTOR_TEST

# Run specific test case within executable
./cpp/build/gtests/DEVICE_UVECTOR_TEST --gtest_filter="TypedUVectorTest.*"
./cpp/build/gtests/DEVICE_UVECTOR_TEST --gtest_filter="*ZeroSizeConstructor"

Python Tests (pytest)

# Run all Python tests
pytest python/rmm/rmm/tests/ -v

# Run single test file
pytest python/rmm/rmm/tests/test_rmm.py -v

# Run single test function
pytest python/rmm/rmm/tests/test_rmm.py::test_reinitialize -v

# Run with coverage
pytest python/rmm/rmm/tests/ --cov=rmm --cov-report=xml

Lint and Format

Always use pre-commit to run linters and formatters:

pre-commit run --all-files     # Run all hooks (recommended)
pre-commit run clang-format --all-files  # C++ formatting only
pre-commit run ruff-check --all-files    # Python linting only
pre-commit run ruff-format --all-files   # Python formatting only

Code Style Guidelines

Use pre-commit run --all-files to run linter and style checks. It will call clang-format, ruff, and other tools.

Naming Conventions

  • C++ classes: snake_case (e.g., device_buffer)
  • C++ functions/methods: snake_case
  • C++ constants/macros: SCREAMING_SNAKE_CASE
  • C++ template params: PascalCase with T suffix (e.g., OffsetT)
  • Python: snake_case for functions, variables; PascalCase for classes

Error Handling

  • C++: Use RMM exception types from <rmm/error.hpp>
    • rmm::bad_alloc for allocation failures
    • rmm::logic_error for programming errors
    • Use RMM_EXPECTS() macro for precondition checks
    • Use RMM_CUDA_TRY() for CUDA API calls
  • Python: Use RMMError or standard Python exceptions

File Headers (SPDX format, required)

C++ and CUDA:

/*
 * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

Python:

# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

Documentation

  • C++: Doxygen comments for public APIs (/** ... */)
  • Python: NumPy-style docstrings
  • All public functions must be documented

Project Structure

cpp/                    # C++ source code
├── include/rmm/        # Public headers (header-only library)
├── src/                # Implementation files
├── tests/              # GoogleTest tests
└── benchmarks/         # Google Benchmark benchmarks
python/rmm/             # Python package
├── rmm/                # Main module
│   ├── pylibrmm/       # Cython bindings
│   └── tests/          # pytest tests
ci/                     # CI scripts

PR Requirements

  • All tests must pass
  • Pre-commit checks must pass
  • Update documentation for API changes
  • Add tests for new functionality

Common Patterns

Memory Resource Usage (C++)

#include <rmm/mr/cuda_async_memory_resource.hpp>
#include <rmm/mr/per_device_resource.hpp>

// Create a memory resource and set it as current
rmm::mr::cuda_async_memory_resource mr{};
rmm::mr::set_current_device_resource_ref(mr);

auto ref = rmm::mr::get_current_device_resource_ref();
rmm::device_buffer buf(size, stream, ref);

Allocate/Deallocate (C++)

// Stream-ordered (async) allocation - preferred for performance
void* ptr = mr.allocate(stream, bytes);
mr.deallocate(stream, ptr, bytes);

// Synchronous allocation - blocks until memory is ready on all streams
void* ptr = mr.allocate_sync(bytes);
mr.deallocate_sync(ptr, bytes);

Stream Usage (C++)

#include <cuda/stream>
void func(cuda::stream_ref stream) {
  // Use stream for async operations
}

Python Memory Resource

import rmm

# Create a memory resource and set it as current
mr = rmm.mr.CudaAsyncMemoryResource()
rmm.mr.set_current_device_resource(mr)

ref = rmm.mr.get_current_device_resource()
buf = rmm.DeviceBuffer(size=size)

Memory Management Guidelines

  • Never use raw CUDA memory APIs for device memory - use memory resources (except in memory resource implementations)
  • Prefer rmm::device_uvector<T> for typed device memory
  • Prefer rmm::device_buffer for untyped device memory
  • All operations should be stream-ordered - accept cuda::stream_ref from <cuda/stream>
  • Views (*_view suffix) are non-owning - don't manage their lifetime

Key Files Reference

Purpose Location
Main build script (never used in devcontainers) build.sh
CMake configuration cpp/CMakeLists.txt
C++ public headers cpp/include/rmm/
Memory resources cpp/include/rmm/mr/
Device containers cpp/include/rmm/device_uvector.hpp, device_buffer.hpp
Stream utilities <cuda/stream>, cpp/include/rmm/cuda_stream.hpp
Error handling cpp/include/rmm/error.hpp
Python bindings python/rmm/rmm/
C++ tests cpp/tests/
Python tests python/rmm/rmm/tests/
CI configuration ci/

Resources