Skip to content

Repository files navigation

Warpline

Warpline is a measured GPU performance project for three Triton kernels on an NVIDIA Blackwell laptop GPU. It combines explicit numerical contracts, fair PyTorch baselines, CUDA-event benchmarking, an empirical roofline, and Nsight Compute evidence. Performance claims come from versioned JSON artifacts and checksummed manifests rather than product-sheet peaks or one-off timings.

The accepted run is rtx-pro-3000-20260812. Its validator covers 120 benchmark artifacts, four plots, six K1 shapes, six K2 shapes, and two K3 shapes in both cold headline and warm diagnostic lanes. The accepted Nsight run is 20260812-blackwell-ncu-2026.2.1; its manifest is complete and its checksums pass.

What was built

K1: fused residual add and RMSNorm

One Triton program handles one row. It adds the input and residual in FP32, rounds that sum once to the input dtype, computes the RMS reduction in FP32, applies the weight, and writes the final FP16 or BF16 result. Fusion removes a materialized residual tensor. At batch 64 and hidden size 8192, the analytical model removes 2,097,152 requested intermediate bytes.

K2: resident and online softmax

Rows up to 8192 columns use a resident one-pass path. Wider rows use a stable online max and sum recurrence in 1024-element chunks, followed by a second pass that normalizes and writes the output. Both paths keep reduction state in FP32 and support masked irregular widths.

K3: signed INT4 g128 dequantization plus GEMV

Weights use symmetric signed INT4 with one BF16 scale per 128 values along K. Two two's-complement values are packed into each byte in group-major layout. The monolithic kernel decodes, scales, and accumulates four output rows in FP32. A deterministic split-K fallback writes FP32 partials and reduces them in a fixed order without atomics.

See kernel design for the numerical and byte-model contracts.

Fair baselines

Every provider for a shape receives the same seeded inputs and must pass the same reference check before timing starts.

  • K1 eager and compiled providers execute the same low-precision residual rounding semantics as Triton.
  • K2 eager and compiled providers call row-wise PyTorch softmax with explicit FP32 computation and one cast to the input dtype. The reference computes in FP64 before that final cast.
  • K3 dense providers use a BF16 matrix dequantized from the same packed values and scales as the INT4 providers. Dense eager uses torch.mv; compiled lanes compile that same operation. The unfused INT4 lane materializes BF16 weights before torch.mv.
  • Compiled results include torch.compile with Inductor, mode="max-autotune", plus a sensitivity lane using mode="max-autotune-no-cudagraphs".
  • Compilation and Triton autotuning finish before measured samples.

Tested platform

These values are recorded in ceilings.json and the Nsight compatibility record.

Component Recorded value
GPU NVIDIA RTX PRO 3000 Blackwell Generation Laptop GPU
Architecture Compute capability 12.0 (sm_120), 46 SMs
Device memory 12,227 MiB reported by nvidia-smi; 12,820,480,000 bytes reported by PyTorch
Memory terminology GDDR7 device DRAM
Driver 595.79
Host WSL2, Linux 6.6.114.1-microsoft-standard-WSL2, x86_64
Python 3.12.13
PyTorch 2.12.0+cu130, package version 2.12.0
Torch-bundled CUDA 13.0
cuDNN Runtime-reported integer 92000
Triton 3.7.0
Nsight Compute 2026.2.1.0, build 38283040

The benchmark environment did not find nvcc or ncu on PATH. Profiling later used the explicit executable /opt/nvidia/nsight-compute/2026.2.1/ncu.

Benchmark and correctness method

The accepted suite uses BF16 inputs, seed 2026, 10 warmups, and 100 timed samples per provider and shape. Providers are interleaved with a rotating order to reduce fixed ordering bias. Each sample uses CUDA events and stores the raw latency plus median, p10, p90, MAD, minimum, and maximum.

Correctness is checked before warmup or timing:

abs(actual - reference) <= atol + rtol * abs(reference)

The harness also records maximum absolute error and thresholded relative error so values near zero do not produce meaningless relative-error claims.

Kernel BF16 atol BF16 rtol Accepted artifacts
K1 RMSNorm plus residual 0.02 0.02 48 of 48 passed
K2 softmax 0.004 0.004 48 of 48 passed
K3 INT4 GEMV 0.5 0.02 24 of 24 passed

Cold is the headline lane. Before each timed provider call, the accepted run touches a 256 MiB device buffer outside the event interval. Warm is a diagnostic lane with no flush hook. These labels describe harness policy; they do not prove that every transaction missed or hit a particular cache.

More detail is in benchmark methodology and artifacts and data model.

Cold-cache results

All latencies below are timing.statistics.median_ms. Speedup is the lowest same-shape PyTorch median divided by the Triton median, so values above 1 mean Triton was faster. "No graphs" is the compiled sensitivity lane. The evidence-gated analysis carries the full interpretation and claim record.

K1 results

Batch x hidden Eager ms Compiled ms No graphs ms Triton ms Triton vs best PyTorch
1 x 1024 0.14656 0.01331 0.00778 0.00794 0.98x
8 x 1024 0.14704 0.01834 0.00960 0.00952 1.01x
16 x 2048 0.17282 0.02208 0.01019 0.00979 1.04x
32 x 4096 0.16517 0.02883 0.01206 0.00994 1.21x
64 x 4096 0.17998 0.03094 0.01382 0.01040 1.33x
64 x 8192 0.17150 0.03693 0.01814 0.01197 1.52x

At the largest shape, Triton was 14.33x faster than eager and 1.52x faster than the best PyTorch lane. The byte saving is analytical requested traffic, not a physical DRAM claim.

K2 results

Rows x columns Path Eager ms Compiled ms No graphs ms Triton ms Triton vs best PyTorch
128 x 1024 Resident 0.02614 0.03488 0.01022 0.01003 1.02x
64 x 4096 Resident 0.03011 0.03099 0.01406 0.01030 1.36x
32 x 8192 Resident 0.02837 0.03294 0.01603 0.01181 1.36x
16 x 8193 Online 0.02797 0.03347 0.01682 0.02062 0.82x
8 x 16384 Online 0.03040 0.03941 0.02235 0.02656 0.84x
4 x 32768 Online 0.03824 0.05200 0.03486 0.04757 0.73x

The resident path won at all three tested widths. The online path remained correct at 8193 and larger columns, but its second input pass did not beat the best PyTorch lane in these shapes.

K3 results

Square shape Dense eager ms Dense compiled ms No graphs ms Unfused INT4 ms Triton ms Split-K ms Triton vs best PyTorch
4096 0.12395 0.26802 0.10856 2.61342 0.08930 0.09755 1.22x
8192 0.40390 1.11203 0.40763 11.08125 0.27590 0.29646 1.46x

The monolithic kernel beat the best PyTorch lane at both shapes and beat the deterministic split-K fallback by 1.09x at 4096 and 1.07x at 8192. It was 29.27x and 40.16x faster than materializing BF16 weights in the unfused INT4 lane.

The artifacts model 33,570,816 dense compulsory bytes versus 8,667,136 fused INT4 bytes at 4096, a 3.873346x reduction. At 8192 the corresponding values are 134,250,496 and 34,635,776 bytes, a 3.876064x reduction. These ratios include weights, scales, input, and output. They are not measured DRAM ratios.

Measured ceilings and roofline

Warpline calibrates candidates, selects on calibration data, then reports the median and range of seven independent confirmation-run medians.

Ceiling Median Seven-run minimum Seven-run maximum Selected candidate
Measured GDDR7 device-memory bandwidth 381.53 GB/s 345.02 GB/s 384.27 GB/s 512 MiB payload, block 512, 8 warps
Measured BF16 torch.mm tensor throughput 26.49 TFLOP/s 23.53 TFLOP/s 29.64 TFLOP/s 4096 x 4096 x 4096

The median BF16 ridge point is 69.4232 FLOP per requested byte. K2 does not use that compute coordinate. Its work model counts scalar operations, including exponentials, comparisons, and divisions. The BF16 tensor roof is device context only, not a scalar, reduction, reciprocal-square-root, exponential, or SFU roof.

Largest cold Triton point Intensity Useful throughput Memory branch Model-relative fraction
K1, 64 x 8192 0.6250 FLOP/requested byte 0.2190 TFLOP/s 0.2385 TFLOP/s 91.9%
K2, 4 x 32768 1.1672 ops/requested byte 0.0193 TOP/s 0.4453 TOP/s 4.3%
K3, 8192 square 3.8751 FLOP/requested byte 0.4865 TFLOP/s 1.4785 TFLOP/s 32.9%

These fractions use each provider's analytical requested-byte convention. They are not measured DRAM-bandwidth utilization.

Warpline empirical roofline

See roofline methodology for the ceiling selection and work conventions.

Nsight Compute findings

Nsight Compute 2026.2.1 profiled one exact function launch per logical kernel with kernel replay, cache control all, and clock control none.

Profile target Occupancy Overall throughput DRAM throughput L2 throughput Observed SM clock Leading warp stall
K1 _rmsnorm_residual_kernel 8.26% 4.30% 4.30% 1.30% 2.7645 GHz Long scoreboard, 67.45%
K2 _online_softmax_kernel 8.05% 0.87% 0.87% 0.41% 2.7741 GHz Long scoreboard, 36.27%
K3 _int4_gemv_kernel 86.95% 73.50% 32.54% 17.82% 1.3908 GHz Long scoreboard, 49.26%

The captured targets were the K1 2 x 8192 FP16 test, the K2 2 x 16381 FP16 online test, and the K3 4096-square BF16 test. K3 reported 8,663,296 DRAM read bytes. Its analytical read-side model is 8,658,944 bytes, so the observed value was 0.05% higher for that launch. No dense K3 profile was captured, so an observed dense-to-INT4 DRAM ratio is not available. See the profiling workflow for metric discovery, capture policy, commands, and interpretation boundaries.

Cache, clocks, and provenance

The benchmark artifacts record clocks.locked: null with the note not probed by the environment snapshot. No clock lock is claimed. The largest-shape cold snapshots alone show different states: K1 recorded P4 at 1357 MHz SM, K2 recorded P4 at 1350 MHz, and K3 recorded P1 at 2190 MHz. Nsight used --clock-control none.

Telemetry is a point-in-time snapshot, not a continuous trace. Laptop power, temperature, and performance state can change between shapes. This also means the warm lane is a cache diagnostic, not a controlled cache-only comparison.

The run environment records branch main, no resolved commit, and a dirty initial tree. The manifest and checksums identify the artifacts, but the run cannot be attributed to a committed source revision.

Reproduce in WSL2

Prerequisites are WSL2, a Windows NVIDIA driver that exposes CUDA to WSL, and uv. From the repository root:

bash scripts/setup_wsl.sh

The script verifies WSL2, installs Python 3.12 through uv, syncs uv.lock without updating it, and runs eager CUDA, Triton, and torch.compile preflight checks for sm_120.

Equivalent manual commands:

uv python install 3.12
uv sync --locked
uv run --no-sync python scripts/preflight.py \
  --require-wsl \
  --require-gpu \
  --require-sm120

For an optional Windows-host clock probe and lock attempt, run the suite through the PowerShell wrapper. Omit the clock arguments to probe support and record telemetry without requesting a lock:

.\scripts\run_locked.ps1 `
  -GraphicsClockMHz <supported-sm-clock> `
  -MemoryClockMHz <supported-memory-clock> `
  -WslCommand "uv run --no-sync python scripts/run_roofline.py suite --run-id <new-run-id> --config configs/roofline.json --results-root results --repository-root ." `
  -Output ".preflight/<new-run-id>-host-clocks.json"

The wrapper records every host command and its exit code, always attempts to reset each requested clock in finally, and reports lock_state: false when a request fails. It never substitutes a synthetic clock value.

Run the full ceiling and benchmark suite with a new ID:

uv run --no-sync python scripts/run_roofline.py suite \
  --run-id <new-run-id> \
  --config configs/roofline.json \
  --results-root results \
  --repository-root .

uv run --no-sync python scripts/validate_roofline_results.py \
  results/<new-run-id>

Regenerate plots without a GPU rerun:

uv run --no-sync python scripts/run_roofline.py plot-run \
  --run-directory results/<run-id>

Run tests and static checks:

uv run --no-sync pytest tests/cpu
uv run --no-sync pytest tests/unit
uv run --no-sync pytest tests/gpu
uv run --no-sync ruff check .
uv run --no-sync ruff format --check .

Reproduce the three profile targets with a new profile ID:

export NCU_BIN=/opt/nvidia/nsight-compute/2026.2.1/ncu

bash scripts/profile.sh \
  --run-id <new-profile-run-id> \
  --kernel rmsnorm_residual \
  --kernel-filter _rmsnorm_residual_kernel \
  -- .venv/bin/python -m pytest \
  tests/gpu/test_rmsnorm_residual.py -k 8192 -q

bash scripts/profile.sh \
  --run-id <new-profile-run-id> \
  --kernel softmax \
  --kernel-filter _online_softmax_kernel \
  -- .venv/bin/python -m pytest \
  tests/gpu/test_softmax.py -k shape3 -q

bash scripts/profile.sh \
  --run-id <new-profile-run-id> \
  --kernel int4_gemv \
  --kernel-filter _int4_gemv_kernel \
  -- .venv/bin/python -m pytest \
  tests/gpu/test_int4_gemv.py -k primary_4096 -q

Repository map

  • warpline/kernels/: Triton kernels and public work models.
  • warpline/baselines/: references, eager providers, and compiled providers.
  • warpline/bench/: correctness gates, provider preparation, CUDA-event timing, and statistics.
  • warpline/roofline/: ceiling measurement, point adapters, CLI, and plotting.
  • warpline/quantization.py: signed INT4 packing, dequantization, and byte models.
  • warpline/artifacts.py and warpline/environment.py: schema validation, atomic writes, provenance, and environment capture.
  • configs/roofline.json: accepted suite coverage and measurement counts.
  • scripts/: setup, preflight, suite, validation, plotting, and profiling entry points.
  • tests/: CPU harness tests, quantization unit tests, and GPU kernel tests.
  • results/: benchmark, ceiling, and roofline artifacts.
  • profiles/: Nsight reports, extracted summaries, commands, and checksums.
  • docs/: design and methodology documentation.

CI scope

GitHub Actions runs on Ubuntu 24.04 for pushes and pull requests. It installs Python 3.12 with uv, grants read-only repository contents permission, and runs uv lock --check before installing the project and development group with uv sync --locked --group dev. It then runs:

  1. ruff check .
  2. ruff format --check .
  3. pytest tests/cpu
  4. pytest tests/unit
  5. pytest tests/gpu, which must skip cleanly without CUDA
  6. the checked-in roofline validator and profile checksum verification
  7. python scripts/preflight.py --cpu-only

Hosted CI does not run GPU kernels or Nsight profiling. It also does not enforce Markdown style or link checks.

Limitations

  • Results apply to the recorded RTX PRO 3000 laptop GPU, driver, WSL kernel, software stack, shapes, BF16 benchmark dtype, and observed power states.
  • Clock-lock state was not probed, no lock is claimed, and telemetry was not continuously monitored.
  • Cold and warm cache labels are harness policies, not cache hit-rate measurements.
  • Analytical requested bytes are not physical DRAM traffic. Only matching profiler counters can support a physical traffic statement.
  • The BF16 matrix-multiply ceiling is not an applicable compute roof for these scalar, reduction, and SFU-heavy kernels.
  • Nsight profiles cover one function launch per kernel, not every provider, shape, or K2 and K3 variant.
  • The run has no source commit and records a dirty tree.
  • No end-to-end model latency, model quality, production readiness, or cross-GPU generalization is claimed.

The complete claim policy is in limitations and claims.

Documentation

License

Apache-2.0. See LICENSE.

About

Three hand-written Triton kernels for LLM inference (fused RMSNorm plus residual, online softmax, INT4 g128 GEMV) benchmarked on NVIDIA Blackwell against PyTorch eager and torch.compile, with every raw CUDA-event sample, measured device ceiling, and Nsight Compute report committed and CI-verified.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages