Open source. Open to your next idea. Explore EveryO 0.2.0

ADVANCED / COMPLETE GUIDE v0.2.0 source snapshot

CUDA & devices.

Build the optional CUDA extension, understand fallback and strict mode, inspect kernels, and distinguish host-backed tensors from resident buffers.

READ WITH CONTEXT

Complete upstream referenceAll source sections are preserved below, with added explanations and local guide links.

Some snippets require earlier definitions or optional integrations. Start with the complete CPU quickstart for a runnable baseline.

Back to the quickstart →
READ THE FULL STORY

Source: EveryO 6c05a06. This page preserves the reviewed upstream guide and adds learning context. Version-specific headings and historical wording remain visible; boundary notes explain newer APIs separately.

BEFORE YOU BEGIN

Know where computation runs.

Start with a working CPU installation. Add the native extension only when compatible NVIDIA hardware and the build toolchain are available.

A device tag is not a resident training tensor

The standard Tensor(device="cuda") path dispatches supported operations while keeping host-backed tensor data. The separate resident-buffer API uploads data once for supported inference operations. It has no autograd nodes. Neither path has GPU runtime validation in project CI.

CUDA is optional. EveryO runs fully on the CPU and every GPU feature degrades gracefully when the hardware or toolchain is absent.

Status

Component State
Kernel sources (cuda/src) Available
pybind11 bindings Available
CMake build Available
Automatic CPU fallback Available
Kernels used by tensors on a cuda device Available (add, multiply, matmul, relu, sum)
GPU-resident inference tensors (no per-call transfer) Available
Fused kernels, mixed precision Planned

Checking availability

Python · reference snippet
import everyo as eo

eo.cuda.is_available()  # True only with a built extension AND a device
eo.cuda.device_count()
eo.cuda.unavailable_reason()  # a sentence explaining why, or None
eo.cuda.runtime_info()  # full details, including device properties

None of these raise. On a CPU-only machine everyo doctor prints the reason.

Building the extension

Requirements: an NVIDIA GPU, the CUDA Toolkit (nvcc), CMake 3.18+ and pybind11. CUDA is supported only on NVIDIA's own supported platforms and toolchains — there is no CUDA path on machines without NVIDIA hardware, and EveryO does not pretend otherwise.

Terminal
pip install -e ".[cuda]"     # installs pybind11
./scripts/build_cuda.sh

Or with CMake directly:

Terminal
cmake -S cuda -B build/cuda -DCMAKE_BUILD_TYPE=Release
cmake --build build/cuda --parallel

The build copies _everyo_cuda*.so next to the Python package so import everyo._everyo_cuda resolves.

A build host without a GPU is fine: the kernels compile and the extension imports, EveryO simply reports CUDA as unavailable until it runs on a machine with a device. scripts/build_cuda.sh says so explicitly rather than treating it as a failure. To target a specific compute capability:

Terminal
./scripts/build_cuda.sh --arch=86

Clean up with ./scripts/build_cuda.sh --clean.

Using it

Python · reference snippet
import everyo as eo

x = eo.tensor([[1.0, 2.0], [3.0, 4.0]], device="cuda")
y = eo.tensor([[5.0, 6.0], [7.0, 8.0]], device="cuda")

z = eo.matmul(x, y)  # runs the tiled CUDA kernel when available

eo.device("auto") picks CUDA when it is usable and CPU otherwise.

Fallback rules

Core operations select an OperatorBackend through everyo.backends.backend_for(). A dispatch returns the requested backend, the backend that actually executed, and a reason whenever CUDA falls back. This makes unsupported dtypes, ranks, and broadcast shapes testable instead of silently hiding the decision. Host/device conversion is represented by the backend's from_host() and to_host() boundary; the current native extension still performs a transfer for each kernel call.

Situation Behaviour
eo.device("cuda"), no CUDA Returns the CPU device, logs a warning
eo.device("cuda", strict=True), no CUDA Raises EveryOCudaError
eo.tensor(..., device="cuda"), no CUDA Tensor is created on the CPU
eo.cuda.relu(x), no CUDA Computes with NumPy
eo.cuda.relu(x, strict=True), no CUDA Raises EveryOCudaError
EVERYO_DISABLE_CUDA=1 CUDA is treated as unavailable even when built

Nothing crashes because CUDA is missing. The only way to get an error is to ask for one with strict=True.

The kernels

Source Kernel Notes
vector_add.cu VectorAdd, VectorMultiply One thread per element, bounds-checked
relu.cu Relu One thread per element
matmul.cu MatMul 16x16 shared-memory tiling
reduction.cu Sum Block-level tree reduction, host-side final sum
device.cu Device queries Never raises when no driver is present

All of them use EVERYO_CUDA_CHECK, which turns a CUDA error code into a C++ exception carrying the file, line and failing call. EVERYO_CUDA_CHECK_KERNEL also synchronises, so an asynchronous kernel fault surfaces at the launch site instead of at some unrelated call later. Device memory is owned by an RAII DeviceBuffer, so it is released even when a later call throws.

Performance

Do not assume the GPU is faster. Each kernel call copies its inputs to the device and the result back; for small problems that transfer dominates and the CPU wins. Measure on your own hardware:

Terminal
python benchmarks/benchmark_matmul.py --sizes 128 512 1024 2048

Removing per-call transfers by keeping tensors resident on the device is the main optimisation for chained supported operations. Use eo.cuda.to_device() to upload float32 data once; addition, multiplication, ReLU, 2-D matrix multiplication and sum then use device-owned buffers. Call .numpy() for an explicit download. The resident API is inference-only and does not yet attach EveryO autograd nodes.

Verifying correctness

Kernel output is compared against the NumPy backend in tests/test_devices.py::TestCudaKernels. Those tests skip automatically without a GPU, and run for real with one:

Terminal
pytest tests/test_devices.py -v

Original guide reproduced under the project’s MIT license. Upstream source remains authoritative.

View the reviewed source on GitHub ↗

Search documentation

Enter opens the first result · Tab moves through links · Esc closes