Performance

July 16, 2026 · View on GitHub

This report freezes the optimized 2026-07-16 comparison of candle-einops against equivalent direct Candle 0.11 operations. It contains 39 wins, 171 ties, and 2 losses across 212 executed provider/scenario combinations.

Negative percentages and durations mean candle-einops is faster. W, T, and L mean classified win, statistical tie, and classified loss; means the GPU construction-only scenario was skipped because a view enqueues no accelerator work.

Stacked outcome counts

Complete outcome heatmap

Snapshot

ProviderDeviceWinsTiesLossesSkipped
CPU baselineCPU (baseline)94710
CPU AccelerateCPU (Accelerate)94800
MetalApple M4 Max113718
CUDANVIDIA GeForce RTX 4070103908

Classified losses

  • repeat/broadcast/single-axis/consume on CPU baseline: +11.6% and +424.00 us.
  • repeat/broadcast/single-axis/consume on Metal: +16.9% and +107.50 us.

Both losses are the same deliberate repeat-view tradeoff. Direct Candle eagerly materializes Tensor::repeat; candle-einops returns a storage-sharing zero-stride view. Eager materialization is faster when this single leading repeat is immediately forced contiguous on baseline CPU or Metal, but it would discard the nearly allocation-free construction wins, the two-axis consumption wins, and the CUDA single-axis win. Callers that know they require an immediate contiguous result should benchmark direct Tensor::repeat for that path.

Largest classified wins

  • repeat/broadcast/single-axis/construct on CPU baseline: -100.0% and -3881.75 us.
  • repeat/broadcast/two-axis/construct on CPU baseline: -100.0% and -9006.50 us.
  • repeat/broadcast/two-axis/construct on CPU Accelerate: -100.0% and -13997.96 us.
  • repeat/broadcast/single-axis/construct on CPU Accelerate: -100.0% and -4953.58 us.
  • layout/permute-compose/n-hw-c/construct on CPU baseline: -99.6% and -105.75 us.
  • layout/permute-compose/n-hw-c/construct on CPU Accelerate: -99.6% and -127.79 us.
  • layout/extended-compose/runtime-ellipsis/construct on CPU baseline: -99.4% and -111.67 us.
  • layout/extended-compose/runtime-ellipsis/construct on CPU Accelerate: -99.4% and -141.62 us.
  • spike/broadcast-gemm/both-broadcast on CUDA: -93.9% and -511.69 us.
  • spike/broadcast-gemm/left-broadcast on CUDA: -91.9% and -249.81 us.
  • spike/broadcast-gemm/right-broadcast on CUDA: -91.8% and -248.72 us.
  • repeat/broadcast/two-axis/consume on CUDA: -84.3% and -666.52 us.

Complete scenario matrix

Each cell shows classification, median percentage delta, and median absolute delta.

ScenarioCPU baselineCPU AccelerateMetalCUDA
einsum/binary-packing/recovered-view/constructT +0.6% / +0.54 usT +0.3% / +0.33 us
einsum/binary-packing/recovered-view/consumeT -4.3% / -10.96 usT +0.7% / +1.21 usW -36.0% / -81.75 usW -33.5% / -6.57 us
einsum/binary/hadamard-overheadT +201.2% / +0.17 usT +251.8% / +0.21 usT +1.4% / +1.83 usT +6.8% / +0.43 us
einsum/binary/hadamard-throughputT +0.6% / +0.17 usT +0.7% / +0.25 usT +0.3% / +0.37 usT +5.1% / +0.47 us
einsum/binary/outer-overheadT +40.1% / +0.17 usT +41.6% / +0.21 usT +0.5% / +0.71 usT +4.4% / +0.39 us
einsum/binary/outer-throughputT +1.8% / +0.21 usT +1.3% / +0.17 usT +0.2% / +0.83 usT +2.5% / +0.41 us
einsum/binary/rank2-matmul-overheadT +18.5% / +0.21 usT +85.6% / +0.25 usT +1.4% / +2.04 usT +3.7% / +0.31 us
einsum/binary/rank2-matmul-throughputT +1.9% / +1.38 usT +3.3% / +0.21 usT +0.3% / +0.37 usT +4.5% / +0.48 us
einsum/binary/rank3-matmul-overheadT +18.9% / +0.29 usT +66.8% / +0.33 usT -0.9% / -1.21 usT +5.4% / +0.45 us
einsum/binary/rank3-matmul-throughputT +0.7% / +0.33 usT +3.4% / +0.37 usT +0.3% / +0.46 usT +3.1% / +0.46 us
einsum/zero-k/output-1x1T +55.5% / +0.21 usT +49.9% / +0.25 usT +0.4% / +0.50 usT +7.7% / +0.63 us
einsum/zero-k/output-512x512T +55.5% / +0.21 usT +45.6% / +0.25 usT +0.4% / +0.54 usT +5.9% / +0.49 us
einsum/zero-k/output-64x64T +55.5% / +0.21 usT +45.6% / +0.21 usT -0.2% / -0.29 usT +5.4% / +0.46 us
layout/extended-compose/post-reduction/constructT +0.5% / +0.21 usT +2.5% / +1.21 usW -11.4% / -20.29 usW -14.3% / -3.82 us
layout/extended-compose/post-reduction/consumeT +0.7% / +0.29 usT +0.7% / +0.63 usT -1.9% / -3.25 usT -0.4% / -0.12 us
layout/extended-compose/runtime-ellipsis/constructW -99.4% / -111.67 usW -99.4% / -141.62 us
layout/extended-compose/runtime-ellipsis/consumeT -0.4% / -0.42 usT +0.5% / +0.67 usT -7.2% / -11.33 usT +4.7% / +0.60 us
layout/permute-compose/c-ab/constructT +0.1% / +0.17 usT +0.4% / +0.62 us
layout/permute-compose/c-ab/consumeT +0.7% / +0.92 usT +0.1% / +0.12 usT -7.7% / -13.17 usT -0.1% / -0.02 us
layout/permute-compose/n-hw-c/constructW -99.6% / -105.75 usW -99.6% / -127.79 us
layout/permute-compose/n-hw-c/consumeT -0.4% / -0.42 usT -0.1% / -0.17 usT -7.3% / -12.50 usT +0.8% / +0.10 us
product/sequential-vs-balanced/k-512T -0.1% / -0.12 usT +0.4% / +0.83 usT -1.5% / -39.00 usT +0.1% / +2.08 us
product/sequential-vs-balanced/k-64T +0.2% / +0.04 usT +0.6% / +0.12 usT +0.6% / +2.75 usT -0.2% / -0.73 us
product/sequential-vs-balanced/k-8T +4.1% / +0.08 usT +3.2% / +0.08 usT -0.5% / -1.00 usT +0.4% / +0.18 us
product/sequential-vs-balanced/two-axis-8x8W -55.9% / -9.75 usW -51.3% / -11.08 usW -35.2% / -166.96 usW -76.3% / -254.11 us
reduce/fusion/contiguous-trailing/meanT +1.3% / +0.12 usT +0.9% / +0.12 usT +2.1% / +2.25 usT +0.6% / +0.14 us
reduce/fusion/contiguous-trailing/sumT +0.9% / +0.08 usT +1.4% / +0.17 usT -1.0% / -1.29 usT +1.1% / +0.24 us
reduce/fusion/strided-non-adjacent/meanT +0.1% / +1.12 usT -0.1% / -0.62 usT +0.1% / +0.17 usT +1.4% / +0.26 us
reduce/fusion/strided-non-adjacent/sumT -0.1% / -0.46 usT -0.0% / -0.17 usT +0.9% / +1.21 usT +0.8% / +0.14 us
repeat/broadcast/single-axis/constructW -100.0% / -3881.75 usW -100.0% / -4953.58 us
repeat/broadcast/single-axis/consumeL +11.6% / +424.00 usT +8.2% / +399.38 usL +16.9% / +107.50 usW -60.0% / -106.78 us
repeat/broadcast/two-axis/constructW -100.0% / -9006.50 usW -100.0% / -13997.96 us
repeat/broadcast/two-axis/consumeW -73.4% / -12625.79 usW -83.7% / -33065.50 usW -38.9% / -1520.71 usW -84.3% / -666.52 us
reshape/identity/contiguous/constructT +2.4% / +0.00 usT +0.0% / +0.00 us
reshape/identity/contiguous/consumeT +0.0% / +0.00 usT +0.0% / +0.00 usT +48.8% / +0.04 usT +5.9% / +0.02 us
reshape/identity/non-contiguous/constructT +0.0% / +0.00 usT +2.4% / +0.00 us
reshape/identity/non-contiguous/consumeT -0.0% / -0.21 usT +7.0% / +37.08 usT -0.2% / -0.38 usT +0.1% / +0.01 us
spike/broadcast-gemm/both-broadcastW -60.8% / -84.58 usW -66.4% / -63.54 usW -70.7% / -438.12 usW -93.9% / -511.69 us
spike/broadcast-gemm/layout-hostileT +0.3% / +0.04 usT +0.0% / +0.00 usT -0.3% / -0.29 usT -0.1% / -0.02 us
spike/broadcast-gemm/left-broadcastW -60.0% / -40.67 usW -67.5% / -29.62 usW -64.2% / -227.96 usW -91.9% / -249.81 us
spike/broadcast-gemm/right-broadcastW -60.3% / -41.04 usW -67.7% / -29.79 usW -64.7% / -230.12 usW -91.8% / -248.72 us
spike/diagonal/interleaved/n16T +0.0% / +0.00 usT -3.6% / -0.04 usT -1.3% / -1.96 usT +0.0% / +0.00 us
spike/diagonal/interleaved/n4T -16.4% / -0.04 usT +0.0% / +0.00 usT +0.1% / +0.17 usT -0.1% / -0.01 us
spike/diagonal/interleaved/n8T -10.9% / -0.04 usT +0.0% / +0.00 usT +0.6% / +0.88 usT -0.5% / -0.04 us
spike/diagonal/simple/n16T +0.0% / +0.00 usT +0.0% / +0.00 usT +2.3% / +3.33 usT +0.0% / +0.00 us
spike/diagonal/simple/n256T +0.0% / +0.00 usT +0.0% / +0.00 usT +0.3% / +0.46 usT +0.1% / +0.01 us
spike/diagonal/simple/n64T -0.3% / -0.00 usT -4.9% / -0.04 usT +1.1% / +1.67 usT -0.2% / -0.02 us
spike/extrema/contiguous-leading/maxT +0.3% / +0.08 usT +0.4% / +0.17 usW -19.6% / -25.88 usT -3.7% / -0.66 us
spike/extrema/contiguous-leading/minT +0.4% / +0.12 usT +0.2% / +0.08 usW -18.2% / -24.54 usT -2.5% / -0.44 us
spike/extrema/contiguous-trailing/maxT +0.3% / +0.08 usT +0.3% / +0.12 usW -25.9% / -37.00 usW -57.4% / -16.18 us
spike/extrema/contiguous-trailing/minT +0.3% / +0.08 usT +0.3% / +0.12 usW -26.5% / -36.62 usW -57.2% / -16.15 us
spike/extrema/strided-trailing/maxT +0.3% / +0.12 usT +0.9% / +0.46 usT +0.3% / +0.46 usT +2.1% / +0.59 us
spike/extrema/strided-trailing/minT +0.2% / +0.08 usT +0.2% / +0.12 usT +0.1% / +0.21 usT +1.9% / +0.53 us
spike/nary-cost/balanced-treeT -1.1% / -0.17 usT -1.2% / -0.17 usT +3.5% / +4.96 usT +3.2% / +1.17 us
spike/nary-cost/broadcast-heavyT +4.0% / +2.12 usT +0.2% / +0.17 usT +0.7% / +1.29 usT +3.3% / +1.70 us
spike/nary-cost/layout-hostileT -1.3% / -0.17 usT -1.5% / -0.21 usT -0.1% / -0.12 usT +2.4% / +0.90 us
spike/nary-cost/linear-chainT -2.1% / -0.25 usT -1.7% / -0.21 usT +1.2% / +1.79 usT +3.0% / +1.12 us

Methodology

Every executed cell uses an optimized release build, 5 independent processes, and 25 timed samples per process after warmup and device synchronization. A classified loss must exceed 10% and 1 us, with its 95% confidence interval excluding 5%. The same rules classify wins in the negative direction. Results inside those materiality and confidence boundaries are ties, even when a tiny operation has a large percentage delta.

The benchmark compares complete public candle-einops paths with equivalent handwired Candle operations. It does not claim custom kernels: wins come from avoiding copies, reshapes, dispatches, or unfavorable operation ordering before invoking Candle's existing kernels.

Data and reproduction

The normalized source data is committed at benchmarks/data/performance-2026-07-16.json. It includes provider metadata, process medians, confidence intervals, workload metadata, and classification thresholds.

Regenerate the report and figures from committed data:

uv run --project benchmarks/reporting python .github/scripts/generate_performance_report.py
uv run --project benchmarks/reporting python .github/scripts/generate_performance_report.py --check

Refresh the normalized snapshot after collecting four new gaps summaries:

uv run --project benchmarks/reporting python .github/scripts/generate_performance_report.py --import-summaries \
  target/benchmarks/final-complete-2/cpu-baseline/summary.json \
  target/benchmarks/final-complete-2/cpu-accelerate/summary.json \
  target/benchmarks/final-complete/metal/summary.json \
  target/benchmarks/final-complete-2/cuda/summary.json

Machine and driver metadata should always be reviewed before comparing snapshots across hosts.