Expand description
CUDA Occupancy Calculator (CPU-side, analytical).
This module implements the standard NVIDIA occupancy model: given a
kernel’s per-thread/per-block resource usage and the architectural limits of
a streaming multiprocessor (SM), it computes how many thread blocks and warps
can be co-resident on a single SM, the resulting occupancy (the ratio of
resident warps to the hardware maximum), and which resource is the binding
constraint. It also provides an optimal_block_size search analogous to
cudaOccupancyMaxPotentialBlockSize.
Nothing here queries a GPU — every value is derived from documented architectural constants and integer arithmetic, so the calculator is deterministic and works on any host.
§Model
For a block of threads_per_block threads on an SM with warp_size threads
per warp:
warps_per_block = ceil(threads_per_block / warp_size)
blocks_by_warps = max_warps_per_sm / warps_per_block
blocks_by_registers = registers_per_sm
/ round_up(registers_per_thread * threads_per_block,
register_alloc_granularity)
blocks_by_shared_mem = shared_mem_per_sm / shared_mem_per_block
blocks_by_cap = max_blocks_per_sm
active_blocks = min(blocks_by_warps, blocks_by_registers,
blocks_by_shared_mem, blocks_by_cap)
active_warps = active_blocks * warps_per_block
occupancy = active_warps / max_warps_per_smThe register term uses a per-block allocation rounded up to
register_alloc_granularity (256 32-bit registers on every architecture
modelled here). This is a deliberately simple approximation of the hardware’s
per-warp register allocation; for block sizes that are whole multiples of the
warp size (the common case) it coincides with the per-warp model.
A registers_per_thread of 0 is treated as “no register pressure”
(unlimited), and a shared_mem_per_block of 0 is treated as “no shared
memory pressure” (unlimited), so those resources never bound occupancy.
§Example
use optirs_gpu::{calculate_occupancy, KernelResourceUsage, SmResourceLimits};
let limits = SmResourceLimits::sm_80();
let usage = KernelResourceUsage::new(32, 0, 256);
let result = calculate_occupancy(&usage, &limits).expect("valid configuration");
assert_eq!(result.active_blocks_per_sm, 8);
assert!((result.occupancy - 1.0).abs() < 1e-9);Structs§
- Kernel
Resource Usage - Per-kernel resource usage that drives the occupancy calculation.
- Occupancy
Result - Result of an occupancy calculation for a single SM.
- SmResource
Limits - Architectural per-SM resource limits for a streaming multiprocessor.
Enums§
- Occupancy
Limiter - The resource that bounds occupancy for a given kernel/SM combination.
Functions§
- calculate_
occupancy - Compute SM occupancy for a kernel with the given resource usage.
- occupancy_
for_ launch - Convenience wrapper computing occupancy for a
crate::backends::LaunchConfig. - optimal_
block_ size - Search for the block size that maximises occupancy (à la
cudaOccupancyMaxPotentialBlockSize).