Skip to content
KernelIndex
Search⌘K

submission 510383

KernelAgent · python · License unknown

Use it

Vendorable · source mirrored · license unknownView source →

No package. Vendor the mirrored source: 202 lines, June 9 Researcher Reciprocity License v1.0.

prefixsum_v2_H100_claude-opus-4.5_ka_submission.py
curl "https://kernelindex.com/api/v1/implementations/kernelbot-prefixsum-v2-510383?include=source"
interfacepython
Compatibility
measured onNVIDIA H100
declared hardwareNVIDIA H100
architecturessm_90
dtypesfp32

Benchmark evidence

1 measurement across 1 GPU, fastest first.

Operation / workload
Hardware
Latency
Rank
Observed
Inclusive prefix sumsuite of 11 cases
NVIDIA H100
1.98ms
#21 of 23
2026-02-27

Reported · How evidence levels are derived →

Source and license

sourceavailable
revision digestsha256:861fe6185bce528b67d22c004e9a90da375ac0f462adc0d7f05820a87e78fb5d
license declaredunknown
license concludedunknown
authorsKernelAgent
imported2026-08-15

Kernel source

prefixsum_v2_H100_claude-opus-4.5_ka_submission.py202 lines
import triton
import triton.language as tl
import torch


@triton.jit
def _prefix_sum_single_block_kernel(
    input_ptr,
    output_ptr,
    n_elements,
    BLOCK_SIZE: tl.constexpr,
):
    """
    Single-block inclusive prefix sum using a work-efficient parallel scan.
    This kernel handles arrays that fit within a single block.
    """
    # Load all elements into shared memory
    offsets = tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_elements
    
    # Load input values
    x = tl.load(input_ptr + offsets, mask=mask, other=0.0)
    
    # Perform inclusive scan using Hillis-Steele algorithm
    # This is a simple parallel prefix sum that works well for moderate sizes
    stride = 1
    while stride < BLOCK_SIZE:
        # Get value from 'stride' positions before
        shifted_offsets = offsets - stride
        shifted_mask = shifted_offsets >= 0
        
        # Load the shifted values (from the same array x)
        x_shifted = tl.where(shifted_mask, 
                             tl.load(input_ptr + shifted_offsets, mask=shifted_mask & (shifted_offsets < n_elements), other=0.0),
                             0.0)
        
        # This approach won't work directly - we need to be more careful
        stride *= 2
    
    # Store results
    tl.store(output_ptr + offsets, x, mask=mask)


@triton.jit
def _local_scan_kernel(
    input_ptr,
    output_ptr,
    block_sums_ptr,
    n_elements,
    BLOCK_SIZE: tl.constexpr,
):
    """
    First pass: compute local prefix sums within each block and store block totals.
    """
    pid = tl.program_id(0)
    block_start = pid * BLOCK_SIZE
    offsets = block_start + tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_elements
    
    # Load input values
    x = tl.load(input_ptr + offsets, mask=mask, other=0.0)
    
    # Compute inclusive prefix sum within block using cumsum
    # Triton doesn't have built-in cumsum, so we use associative scan
    result = tl.cumsum(x, axis=0)
    
    # Store local prefix sums
    tl.store(output_ptr + offsets, result, mask=mask)
    
    # Store the block total (last valid element's prefix sum)
    # We need the sum of all elements in this block
    block_sum = tl.sum(x, axis=0)
    tl.store(block_sums_ptr + pid, block_sum)


@triton.jit  
def _add_block_prefix_kernel(
    output_ptr,
    block_prefix_ptr,
    n_elements,
    BLOCK_SIZE: tl.constexpr,
):
    """
    Third pass: add the prefix sum of previous blocks to each element.
    """
    pid = tl.program_id(0)
    
    # Skip first block - it doesn't need adjustment
    if pid == 0:
        return
    
    block_start = pid * BLOCK_SIZE
    offsets = block_start + tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_elements
    
    # Load the prefix sum of all previous blocks
    prefix = tl.load(block_prefix_ptr + pid - 1)
    
    # Load current values and add prefix
    current = tl.load(output_ptr + offsets, mask=mask, other=0.0)
    result = current + prefix
    
    # Store updated values
    tl.store(output_ptr + offsets, result, mask=mask)


def kernel_function(data: torch.Tensor, output: torch.Tensor) -> torch.Tensor:
    """
    Computes inclusive prefix sum (cumulative sum) of the input tensor.
    
    This is a fused multi-pass implementation:
    1. Local scan within blocks + compute block totals
    2. Scan of block totals (done sequentially for small number of blocks)
    3. Add block prefixes to local results
    
    Args:
        data: Input 1D tensor
        output: Output tensor (pre-allocated)
    
    Returns:
        Output tensor containing inclusive prefix sum
    """
    n_elements = data.numel()
    
    # Choose block size
    BLOCK_SIZE = 1024
    
    # Number of blocks needed
    n_blocks = triton.cdiv(n_elements, BLOCK_SIZE)
    
    # Allocate temporary storage for block sums
    block_sums = torch.empty(n_blocks, device=data.device, dtype=torch.float32)
    
    # Pass 1: Local prefix sums within each block
    grid = (n_blocks,)
    _local_scan_kernel[grid](
        data, output, block_sums,
        n_elements,
        BLOCK_SIZE=BLOCK_SIZE,
    )
    
    # Pass 2: Compute prefix sum of block sums
    # For small number of blocks, we can do this with a single block
    if n_blocks > 1:
        block_prefix = torch.empty(n_blocks, device=data.device, dtype=torch.float32)
        
        # Use a simple kernel to compute prefix sum of block sums
        _compute_block_prefix[(1,)](
            block_sums, block_prefix, n_blocks, 
            BLOCK_SIZE=triton.next_power_of_2(n_blocks),
        )
        
        # Pass 3: Add block prefixes to local results
        _add_block_prefix_kernel[grid](
            output, block_prefix,
            n_elements,
            BLOCK_SIZE=BLOCK_SIZE,
        )
    
    return output


@triton.jit
def _compute_block_prefix(
    block_sums_ptr,
    block_prefix_ptr,
    n_blocks,
    BLOCK_SIZE: tl.constexpr,
):
    """
    Compute inclusive prefix sum of block sums.
    Single block kernel for small arrays.
    """
    offsets = tl.arange(0, BLOCK_SIZE)
    mask = offsets < n_blocks
    
    # Load block sums
    x = tl.load(block_sums_ptr + offsets, mask=mask, other=0.0)
    
    # Compute inclusive prefix sum
    result = tl.cumsum(x, axis=0)
    
    # Store results
    tl.store(block_prefix_ptr + offsets, result, mask=mask)

import inspect

def custom_kernel(input):
    sig = inspect.signature(kernel_function)
    num_params = len(sig.parameters)

    if len(input) == num_params:
        return kernel_function(*input)
    return kernel_function(input)


# Ensure deterministic cuBLAS.
import os
if os.environ.get("CUBLAS_WORKSPACE_CONFIG", "") not in (":4096:8", ":16:8"):
    os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"

scrolls · 202 lines total

Source code from GPU Mode and the KernelBot dataset · June 9 Researcher Reciprocity License v1.0

Best evidence level for this revision: reported

JSON