Five-vector comparison — GooseArrays (prototype measurements retained for v0.1)

Measurements from October 31, 2026: 1,406 cases (996 original + 410 additional) and 6,030 passing assertions, using Julia 1.13.3 on an Apple M5 Max with one Julia task and one BLAS thread.

Each cell reports median time in nanoseconds / GC-allocated bytes. Arena initialization and compilation are excluded from these operations and measured separately. — means not measured, never zero. Differences of a few percent may be measurement noise.

The five vector types are measured at lengths 2, 3, 4, 8, 16, 32, 64, 100, and 1,000. MVector cases with 10,000 or 100,000 elements are omitted to limit StaticArrays code expansion and compilation; StaticGooseArray is measured at those lengths.

Vector mapping, reductions, and broadcasting

The mapping function is map(x -> 2x+1, b) and the reduction is mapreduce(abs2,+,b). Fused summation is sum(x -> 2x+1, b) and does not materialize an intermediate result. Out-of-place operations are followed by sum to consume the result, measuring the full pipeline. For arena-backed arrays, this includes entering and leaving the scope.

<!– BEGIN GENERATED BENCHMARK: vectors –>

SizeOperationVectorFixedSizeVectorGooseVectorStaticGooseVectorMVector
2in-place map!2.4 / 02.4 / 02.9 / 02.8 / 01.5 / 0
2map then sum7.3 / 805.5 / 4814.0 / 011.2 / 01.5 / 0
2fused sum(f)1.5 / 02.0 / 03.0 / 02.2 / 01.5 / 0
2abs2 reduction2.8 / 02.5 / 03.0 / 02.7 / 01.5 / 0
2in-place broadcast2.8 / 02.9 / 06.0 / 05.5 / 01.3 / 0
2broadcast then sum7.7 / 805.6 / 4813.8 / 011.3 / 01.5 / 0
22 .* b .+ 1 then sum7.5 / 805.6 / 4813.8 / 011.2 / 01.3 / 0
3in-place map!2.6 / 02.8 / 03.9 / 03.2 / 01.8 / 0
3map then sum7.8 / 805.8 / 4814.1 / 013.8 / 01.8 / 0
3fused sum(f)2.1 / 01.9 / 03.0 / 02.5 / 01.8 / 0
3abs2 reduction2.8 / 02.8 / 02.8 / 02.9 / 01.5 / 0
3in-place broadcast2.9 / 03.1 / 06.5 / 05.9 / 01.8 / 0
3broadcast then sum8.4 / 806.3 / 4814.1 / 013.8 / 01.8 / 0
32 .* b .+ 1 then sum8.0 / 806.0 / 4814.2 / 014.7 / 01.8 / 0
4in-place map!3.0 / 03.0 / 03.2 / 03.2 / 01.8 / 0
4map then sum8.5 / 966.9 / 6414.3 / 014.0 / 01.8 / 0
4fused sum(f)2.4 / 02.2 / 03.1 / 02.6 / 01.8 / 0
4abs2 reduction3.0 / 03.2 / 03.2 / 02.6 / 01.5 / 0
4in-place broadcast3.2 / 03.1 / 06.3 / 05.9 / 01.8 / 0
4broadcast then sum9.2 / 966.6 / 6414.1 / 014.2 / 01.8 / 0
42 .* b .+ 1 then sum8.6 / 967.0 / 6414.0 / 013.7 / 01.8 / 0
8in-place map!2.2 / 02.4 / 03.2 / 03.6 / 02.0 / 0
8map then sum10.0 / 1288.6 / 9614.5 / 014.9 / 02.0 / 0
8fused sum(f)3.0 / 03.1 / 04.2 / 02.8 / 02.0 / 0
8abs2 reduction4.0 / 04.3 / 04.1 / 02.8 / 01.8 / 0
8in-place broadcast3.1 / 03.2 / 06.1 / 06.6 / 01.8 / 0
8broadcast then sum8.8 / 1286.7 / 9614.4 / 014.8 / 01.9 / 0
82 .* b .+ 1 then sum8.5 / 1286.8 / 9614.3 / 014.6 / 02.0 / 0
16in-place map!2.6 / 02.8 / 03.7 / 04.8 / 02.9 / 0
16map then sum12.5 / 19211.1 / 16017.2 / 016.6 / 02.6 / 0
16fused sum(f)4.3 / 04.3 / 05.6 / 04.6 / 02.8 / 0
16abs2 reduction5.0 / 05.2 / 05.8 / 04.5 / 02.3 / 0
16in-place broadcast3.8 / 03.7 / 06.7 / 07.8 / 02.4 / 0
16broadcast then sum12.1 / 1929.7 / 16017.0 / 015.9 / 02.6 / 0
162 .* b .+ 1 then sum11.9 / 1929.7 / 16017.1 / 016.2 / 02.6 / 0
32in-place map!3.7 / 03.5 / 04.7 / 04.4 / 04.8 / 0
32map then sum15.5 / 32013.8 / 28817.9 / 016.0 / 05.2 / 0
32fused sum(f)5.2 / 05.2 / 06.5 / 05.6 / 05.2 / 0
32abs2 reduction5.2 / 05.4 / 06.3 / 05.4 / 03.5 / 0
32in-place broadcast4.9 / 05.2 / 08.1 / 07.4 / 04.0 / 0
32broadcast then sum15.3 / 32013.4 / 28817.7 / 016.4 / 05.3 / 0
322 .* b .+ 1 then sum15.1 / 32013.2 / 28817.5 / 015.6 / 05.2 / 0
64in-place map!4.8 / 05.4 / 06.7 / 06.2 / 08.8 / 0
64map then sum20.2 / 57618.0 / 54420.1 / 018.7 / 012.9 / 0
64fused sum(f)7.0 / 06.8 / 08.2 / 07.2 / 010.6 / 0
64abs2 reduction6.9 / 06.9 / 07.2 / 06.3 / 08.5 / 0
64in-place broadcast7.0 / 06.9 / 011.3 / 09.0 / 014.2 / 0
64broadcast then sum20.3 / 57618.1 / 54419.8 / 018.5 / 012.9 / 0
642 .* b .+ 1 then sum20.2 / 57617.9 / 54419.7 / 018.5 / 012.9 / 0
100in-place map!7.6 / 08.0 / 08.8 / 08.9 / 014.2 / 0
100map then sum26.1 / 92823.6 / 89623.3 / 021.7 / 026.8 / 0
100fused sum(f)9.0 / 09.1 / 09.5 / 09.5 / 018.9 / 0
100abs2 reduction7.0 / 07.2 / 07.6 / 06.8 / 015.5 / 0
100in-place broadcast8.8 / 08.8 / 015.9 / 011.8 / 028.4 / 0
100broadcast then sum25.8 / 92824.2 / 89623.4 / 021.3 / 026.7 / 0
1002 .* b .+ 1 then sum25.9 / 92824.3 / 89623.4 / 023.8 / 025.1 / 0
1000in-place map!63.9 / 063.3 / 065.2 / 064.9 / 0125.2 / 0
1000map then sum200.8 / 8256202.2 / 8224147.4 / 0144.3 / 0589.6 / 0
1000fused sum(f)83.4 / 084.4 / 084.2 / 087.8 / 0421.3 / 0
1000abs2 reduction75.7 / 075.8 / 076.4 / 075.3 / 0401.0 / 0
1000in-place broadcast64.8 / 065.5 / 071.0 / 067.2 / 0273.3 / 0
1000broadcast then sum182.1 / 8256182.2 / 8224147.1 / 0144.2 / 0589.6 / 0
10002 .* b .+ 1 then sum181.4 / 8256182.7 / 8224146.9 / 0144.1 / 0589.6 / 0
10000in-place map!634.1 / 0629.3 / 0633.4 / 0625.9 / 0—
10000map then sum2175.9 / 819842129.6 / 819521541.7 / 01525.0 / 0—
10000fused sum(f)867.1 / 0869.4 / 0874.4 / 0877.7 / 0—
10000abs2 reduction906.7 / 0905.8 / 0904.8 / 0904.3 / 0—
10000in-place broadcast633.0 / 0631.8 / 0631.4 / 0628.2 / 0—
10000broadcast then sum2115.7 / 819842025.0 / 819521541.7 / 01525.0 / 0—
100002 .* b .+ 1 then sum2115.7 / 819842029.1 / 819521541.6 / 01533.3 / 0—
100000in-place map!11500.0 / 011000.0 / 011375.0 / 011500.0 / 0—
100000map then sum20791.0 / 80288020834.0 / 80284819250.0 / 019250.0 / 0—
100000fused sum(f)8805.3 / 08805.7 / 08861.0 / 08847.3 / 0—
100000abs2 reduction9375.0 / 09375.0 / 09375.0 / 09375.0 / 0—
100000in-place broadcast11542.0 / 011000.0 / 011500.0 / 011333.0 / 0—
100000broadcast then sum20583.0 / 80288020542.0 / 80284819250.0 / 019250.0 / 0—
1000002 .* b .+ 1 then sum20916.5 / 80288020541.0 / 80284819209.0 / 019375.0 / 0—

<!– END GENERATED BENCHMARK: vectors –>

Matrix multiplication

Square Float64 matrices. mul! uses a preallocated destination; multiplying and then summing includes allocation and consumption of the result. MMatrix is only measured up to 16×16.

<!– BEGIN GENERATED BENCHMARK: matrices –>

SizeOperationMatrixFixedSizeMatrixGooseMatrixStaticGooseMatrixMMatrix
2×2in-place mul!12.3 / 017.0 / 09.2 / 05.4 / 0—
2×2multiply then sum18.7 / 11244.4 / 6420.0 / 016.9 / 0—
3×3in-place mul!13.9 / 018.2 / 015.4 / 07.2 / 0—
3×3multiply then sum22.5 / 14446.7 / 9625.4 / 018.3 / 0—
4×4in-place mul!43.6 / 047.1 / 030.3 / 010.4 / 0—
4×4multiply then sum54.2 / 20856.8 / 16040.8 / 022.1 / 0—
8×8in-place mul!79.6 / 082.4 / 077.7 / 075.9 / 0—
8×8multiply then sum92.7 / 592102.0 / 544101.7 / 091.5 / 0—
16×16in-place mul!223.9 / 0217.9 / 0214.0 / 0212.7 / 0—
16×16multiply then sum268.8 / 2128278.3 / 2080254.1 / 0245.4 / 0—
64×64in-place mul!19208.0 / 019375.0 / 019209.0 / 019208.0 / 0—
64×64multiply then sum20958.0 / 3284819417.0 / 3280019333.0 / 019209.0 / 0—
256×256in-place mul!632583.0 / 0634875.0 / 0634187.5 / 0634291.0 / 0—
256×256multiply then sum648083.0 / 524368638833.5 / 524320643542.0 / 0639021.0 / 0—

<!– END GENERATED BENCHMARK: matrices –>

Additional operations, construction allocations, SVector / SMatrix, and specialization are covered below and in the CSV files under benchmark/reference/m5-max-2026-10-31/.

Multiple inputs and scaling operations

Functions: f₂(x,y)=xy and f₃(x,y,z)=x+yz. Mapping followed by summation remains two operations and materializes an intermediate result. Native global numeric + mapreduce implementations do not store mapped elements. For Goose arrays, out-of-place operations and multi-input reductions use the same scope per invocation across all four benchmark groups, including after temporaries are released. axpy! uses α=0.25; axpby! uses α=0.25 and β=0.5. All 410 additional cases use the same kernels at each stage.

<!– BEGIN GENERATED BENCHMARK: multi-input –>

SizeOperationVectorFixedSizeVectorGooseVectorStaticGooseVectorMVector
2two-input map!4.1 / 02.6 / 03.0 / 02.8 / 03.5 / 0
2three-input map!6.3 / 06.5 / 03.8 / 03.5 / 03.5 / 0
2two-input map then sum9.2 / 809.8 / 8014.4 / 011.6 / 01.5 / 0
2three-input map then sum9.9 / 8010.5 / 8014.7 / 011.5 / 01.5 / 0
2two-input mapreduce9.2 / 809.7 / 8012.2 / 011.0 / 01.5 / 0
2three-input mapreduce10.0 / 8010.6 / 8012.5 / 010.8 / 01.6 / 0
2axpy!5.3 / 05.7 / 02.9 / 03.8 / 03.6 / 0
2axpby!4.8 / 04.8 / 03.0 / 04.4 / 04.3 / 0
3two-input map!4.4 / 03.0 / 03.2 / 02.9 / 03.6 / 0
3three-input map!6.6 / 06.8 / 04.1 / 03.7 / 03.8 / 0
3two-input map then sum9.8 / 8010.2 / 8014.6 / 014.0 / 01.5 / 0
3three-input map then sum10.8 / 8011.0 / 8014.8 / 014.1 / 01.8 / 0
3two-input mapreduce9.8 / 8010.1 / 8012.2 / 011.0 / 01.5 / 0
3three-input mapreduce10.6 / 8011.0 / 8012.8 / 010.8 / 01.8 / 0
3axpy!5.3 / 06.0 / 03.2 / 03.9 / 03.4 / 0
3axpby!5.0 / 04.9 / 03.2 / 04.4 / 04.3 / 0
4two-input map!4.6 / 03.2 / 03.5 / 03.2 / 03.8 / 0
4three-input map!6.8 / 07.0 / 04.4 / 04.0 / 04.0 / 0
4two-input map then sum10.1 / 9610.7 / 9615.4 / 014.7 / 01.8 / 0
4three-input map then sum11.0 / 9611.6 / 9615.1 / 014.7 / 01.7 / 0
4two-input mapreduce10.2 / 9610.6 / 9612.2 / 010.9 / 01.8 / 0
4three-input mapreduce11.1 / 9611.6 / 9612.7 / 011.0 / 01.8 / 0
4axpy!5.4 / 06.4 / 03.4 / 03.9 / 03.6 / 0
4axpby!5.3 / 05.3 / 03.3 / 04.5 / 04.4 / 0
8two-input map!5.8 / 04.0 / 03.5 / 03.9 / 04.7 / 0
8three-input map!6.5 / 07.0 / 04.2 / 04.8 / 05.4 / 0
8two-input map then sum11.4 / 12812.0 / 12815.1 / 016.0 / 01.9 / 0
8three-input map then sum12.5 / 12813.3 / 12816.2 / 015.5 / 02.2 / 0
8two-input mapreduce11.7 / 12812.1 / 12812.3 / 010.7 / 01.8 / 0
8three-input mapreduce12.7 / 12813.2 / 12813.2 / 010.7 / 02.2 / 0
8axpy!6.3 / 07.2 / 03.3 / 04.0 / 03.8 / 0
8axpby!5.3 / 05.2 / 03.9 / 04.5 / 04.5 / 0
16two-input map!6.7 / 05.0 / 04.2 / 05.0 / 06.2 / 0
16three-input map!7.5 / 07.7 / 05.1 / 07.2 / 09.0 / 0
16two-input map then sum14.2 / 19214.8 / 19217.0 / 017.0 / 02.5 / 0
16three-input map then sum15.6 / 19216.4 / 19218.3 / 018.1 / 03.3 / 0
16two-input mapreduce14.4 / 19215.3 / 19217.8 / 015.6 / 02.5 / 0
16three-input mapreduce16.0 / 19217.0 / 19220.5 / 018.1 / 03.4 / 0
16axpy!8.2 / 09.4 / 04.2 / 05.7 / 05.4 / 0
16axpby!5.8 / 06.0 / 04.5 / 06.5 / 06.0 / 0
64two-input map!10.4 / 08.8 / 08.1 / 07.8 / 014.2 / 0
64three-input map!13.6 / 012.3 / 011.1 / 010.6 / 019.5 / 0
64two-input map then sum22.2 / 57622.3 / 57622.1 / 020.2 / 013.3 / 0
64three-input map then sum25.0 / 57624.8 / 57625.9 / 023.8 / 015.9 / 0
64two-input mapreduce22.5 / 57621.8 / 57620.5 / 017.8 / 011.0 / 0
64three-input mapreduce24.9 / 57624.6 / 57625.5 / 021.9 / 014.2 / 0
64axpy!10.0 / 010.1 / 08.1 / 07.3 / 07.5 / 0
64axpby!10.7 / 010.5 / 08.4 / 08.3 / 08.0 / 0
1000two-input map!95.0 / 095.2 / 090.3 / 089.7 / 0169.5 / 0
1000three-input map!123.8 / 0127.5 / 0122.7 / 0122.0 / 0245.5 / 0
1000two-input map then sum219.2 / 8256222.7 / 8256162.4 / 0169.6 / 0621.4 / 0
1000three-input map then sum246.0 / 8256250.9 / 8256198.5 / 0203.8 / 0769.0 / 0
1000two-input mapreduce220.1 / 8256225.5 / 8256105.1 / 0103.3 / 0437.1 / 0
1000three-input mapreduce245.0 / 8256251.6 / 8256138.6 / 0135.6 / 0494.2 / 0
1000axpy!83.2 / 085.8 / 092.1 / 091.9 / 092.8 / 0
1000axpby!94.4 / 094.7 / 092.3 / 091.9 / 093.3 / 0
10000two-input map!1583.4 / 01616.7 / 01487.5 / 01720.9 / 0—
10000three-input map!2310.1 / 02300.9 / 02262.5 / 02301.0 / 0—
10000two-input map then sum2731.4 / 819842731.4 / 819842263.9 / 02263.9 / 0—
10000three-input map then sum3437.5 / 819843432.2 / 819842921.3 / 02898.2 / 0—
10000two-input mapreduce2736.1 / 819842740.7 / 819841038.2 / 01089.7 / 0—
10000three-input mapreduce3437.5 / 819843447.9 / 819841625.0 / 01666.6 / 0—
10000axpy!1300.0 / 01400.0 / 01441.7 / 01437.5 / 0—
10000axpby!1462.5 / 01458.3 / 01450.0 / 01512.5 / 0—
100000two-input map!17917.0 / 017875.0 / 017875.0 / 017916.0 / 0—
100000three-input map!23792.0 / 023750.0 / 023709.0 / 023709.0 / 0—
100000two-input map then sum26750.0 / 80288026750.0 / 80288026459.0 / 026375.0 / 0—
100000three-input map then sum33145.5 / 80288033042.0 / 80288032375.0 / 032750.0 / 0—
100000two-input mapreduce26917.0 / 80288026750.0 / 80288012417.0 / 012375.0 / 0—
100000three-input mapreduce33354.5 / 80288033208.0 / 80288019333.0 / 019209.0 / 0—
100000axpy!14500.0 / 014666.0 / 014459.0 / 014459.0 / 0—
100000axpby!15292.0 / 015291.0 / 014834.0 / 015417.0 / 0—

<!– END GENERATED BENCHMARK: multi-input –>

Matrix–vector products

Square n×n matrices and n-element vectors. mul! uses a preallocated output; multiplication followed by summation includes allocation and consumption of the result, as in the matrix–matrix benchmarks.

<!– BEGIN GENERATED BENCHMARK: matvec –>

SizeOperationMatrix × VectorFixedSizeMatrix × FixedSizeVectorGooseMatrix × GooseVectorStaticGooseMatrix × StaticGooseVectorMMatrix × MVector
2×2matrix–vector mul!19.7 / 018.9 / 06.2 / 04.2 / 05.3 / 0
2×2multiply then sum28.1 / 8026.7 / 4819.5 / 015.9 / 01.5 / 0
3×3matrix–vector mul!24.6 / 024.8 / 07.4 / 04.8 / 06.0 / 0
3×3multiply then sum34.3 / 8034.2 / 4820.3 / 017.3 / 01.8 / 0
4×4matrix–vector mul!21.1 / 020.0 / 010.4 / 05.1 / 06.5 / 0
4×4multiply then sum28.9 / 9627.6 / 6421.3 / 017.7 / 02.0 / 0
8×8matrix–vector mul!34.5 / 034.6 / 023.1 / 011.0 / 013.8 / 0
8×8multiply then sum45.6 / 12843.8 / 9635.5 / 020.8 / 04.5 / 0
16×16matrix–vector mul!65.5 / 065.3 / 070.1 / 016.6 / 041.3 / 0
16×16multiply then sum78.1 / 19277.3 / 160101.8 / 025.6 / 019.5 / 0
64×64matrix–vector mul!452.5 / 0452.1 / 0455.2 / 0453.9 / 0—
64×64multiply then sum584.8 / 576589.1 / 544493.4 / 0466.8 / 0—
256×256matrix–vector mul!7700.0 / 07687.5 / 07698.0 / 07700.0 / 0—
256×256multiply then sum7770.9 / 21127885.5 / 20807750.0 / 07739.5 / 0—

<!– END GENERATED BENCHMARK: matvec –>

Exact benchmark environment

GooseArrays: 0.6.0 (measured before the prototype was renamed to v0.1.0)
Julia: 1.13.3; kernel: Darwin; architecture: aarch64
CPU: Apple M5 Max
Julia threads: 1; BLAS threads: 1
FixedSizeArrays: 1.5.1
StaticArrays: 1.9.24
BenchmarkTools: 1.8.0
Seconds per case: 0.25; max samples: 3000
Lengths: 2,3,4,8,16,32,64,100,1000,10000,100000; StaticArrays max: 1000
Square matrix sides: 2,3,4,8,16,64,256
BLAS: LBTConfig([ILP64] libopenblas64_.0.3.30.dylib)

Additional benchmark campaign:

GooseArrays=0.6.0 (measured before the prototype was renamed to v0.1.0)
Julia=1.13.3
CPU=Apple M5 Max
BLAS=LBTConfig([ILP64] libopenblas64_.0.3.30.dylib)
threads=1, BLAS=1
seconds=0.25, samples=3000
lengths=2,3,4,8,16,64,1000,10000,100000
StaticGoose max=100000
sides=2,3,4,8,16,64,256

The four packages are Base, FixedSizeArrays, GooseArrays, and StaticArrays. The five vector columns contain mutable vectors. Immutable SVector and SMatrix provide additional reference points, not replacements for in-place operations.

Construction, indexing, and additional operations

Units: nanoseconds / GC bytes. Escaping constructors store their result in Ref{Any}; arena cases call reset! to reuse storage. Construction plus computation fills the array with 2 and then reduces it. This workload can be optimized substantially when the array length is known.

<!– BEGIN GENERATED BENCHMARK: additional –>

SizeOperationVectorFixedSizeVectorGooseVectorStaticGooseVectorMVector
2escaping construction6.8 / 807.5 / 807.3 / 649.3 / 483.4 / 32
2construct + fill + sum7.8 / 805.5 / 4813.6 / 011.1 / 03.5 / 32
2fill!1.5 / 01.5 / 02.8 / 02.8 / 01.1 / 0
2sum1.7 / 01.3 / 02.2 / 02.0 / 01.0 / 0
2indexing1.1 / 01.1 / 02.2 / 02.2 / 01.1 / 0
2copyto!2.8 / 03.0 / 05.8 / 04.6 / 01.8 / 0
2dot6.3 / 06.5 / 02.4 / 02.1 / 01.1 / 0
2affine loop2.2 / 02.2 / 02.9 / 02.7 / 01.5 / 0
2in-place broadcast expression2.8 / 03.0 / 06.0 / 05.7 / 01.5 / 0
3escaping construction7.3 / 808.0 / 807.5 / 649.5 / 483.4 / 32
3construct + fill + sum8.5 / 807.8 / 4814.8 / 014.4 / 03.7 / 32
3fill!1.5 / 01.8 / 04.3 / 04.2 / 01.1 / 0
3sum1.3 / 01.3 / 02.4 / 02.3 / 00.9 / 0
3indexing1.1 / 01.2 / 02.4 / 02.2 / 01.1 / 0
3copyto!3.1 / 03.1 / 06.3 / 04.9 / 01.7 / 0
3dot6.2 / 07.0 / 02.6 / 02.2 / 01.3 / 0
3affine loop2.0 / 02.5 / 03.8 / 03.0 / 01.8 / 0
3in-place broadcast expression3.1 / 03.2 / 06.4 / 05.9 / 01.8 / 0
4escaping construction7.3 / 968.0 / 967.3 / 649.2 / 483.7 / 48
4construct + fill + sum16.0 / 9610.3 / 6413.8 / 013.7 / 03.8 / 48
4fill!1.8 / 02.0 / 02.8 / 02.8 / 01.1 / 0
4sum1.3 / 01.8 / 02.6 / 02.2 / 01.1 / 0
4indexing1.1 / 01.3 / 02.2 / 02.2 / 01.1 / 0
4copyto!3.6 / 03.2 / 06.2 / 05.0 / 01.8 / 0
4dot7.0 / 07.1 / 02.6 / 02.1 / 01.3 / 0
4affine loop2.5 / 02.6 / 03.2 / 03.0 / 01.8 / 0
4in-place broadcast expression3.2 / 03.5 / 06.3 / 06.1 / 01.5 / 0
8escaping construction7.7 / 1288.5 / 1287.2 / 649.2 / 484.1 / 80
8construct + fill + sum9.2 / 1287.2 / 9614.8 / 014.5 / 04.4 / 80
8fill!1.5 / 01.7 / 03.8 / 03.8 / 01.1 / 0
8sum2.4 / 02.7 / 03.5 / 02.2 / 01.3 / 0
8indexing1.1 / 01.3 / 02.2 / 02.2 / 01.1 / 0
8copyto!2.8 / 03.4 / 06.1 / 05.3 / 02.1 / 0
8dot7.4 / 07.6 / 02.4 / 02.1 / 01.3 / 0
8affine loop2.2 / 02.2 / 03.1 / 03.7 / 02.0 / 0
8in-place broadcast expression3.3 / 03.2 / 06.1 / 06.7 / 01.8 / 0
16escaping construction20.0 / 19220.5 / 1927.3 / 649.8 / 4810.9 / 144
16construct + fill + sum13.2 / 1929.6 / 16016.7 / 015.1 / 06.0 / 144
16fill!1.8 / 02.2 / 03.8 / 03.8 / 01.6 / 0
16sum3.7 / 03.7 / 05.0 / 03.9 / 01.5 / 0
16indexing1.1 / 01.3 / 02.2 / 02.2 / 01.2 / 0
16copyto!3.0 / 03.6 / 06.5 / 05.8 / 03.3 / 0
16dot9.4 / 09.9 / 02.9 / 02.7 / 02.0 / 0
16affine loop2.6 / 02.6 / 03.7 / 04.8 / 03.0 / 0
16in-place broadcast expression3.8 / 03.7 / 06.7 / 07.8 / 02.4 / 0
32escaping construction30.5 / 32025.9 / 3207.5 / 649.2 / 4814.8 / 272
32construct + fill + sum17.4 / 32012.5 / 28817.9 / 016.3 / 08.3 / 272
32fill!2.8 / 03.2 / 04.8 / 04.8 / 02.4 / 0
32sum4.5 / 04.8 / 05.6 / 04.5 / 02.2 / 0
32indexing1.1 / 01.3 / 02.2 / 02.2 / 01.0 / 0
32copyto!4.0 / 04.7 / 07.3 / 06.4 / 05.2 / 0
32dot7.6 / 07.6 / 04.1 / 04.0 / 03.0 / 0
32affine loop3.2 / 03.5 / 04.6 / 04.3 / 02.8 / 0
32in-place broadcast expression4.9 / 04.8 / 08.1 / 07.3 / 04.0 / 0
64escaping construction15.3 / 57627.3 / 5767.5 / 649.2 / 488.8 / 544
64construct + fill + sum21.8 / 57616.6 / 54420.3 / 018.9 / 016.8 / 544
64fill!4.5 / 05.0 / 07.2 / 07.0 / 04.1 / 0
64sum6.0 / 05.6 / 06.6 / 05.8 / 05.6 / 0
64indexing0.9 / 01.3 / 02.2 / 02.2 / 01.1 / 0
64copyto!6.0 / 06.6 / 09.0 / 08.4 / 04.7 / 0
64dot9.9 / 09.8 / 06.7 / 06.5 / 05.5 / 0
64affine loop5.0 / 05.3 / 06.5 / 06.2 / 04.5 / 0
64in-place broadcast expression6.9 / 06.8 / 011.1 / 09.1 / 014.2 / 0
100escaping construction18.3 / 92819.9 / 9287.5 / 649.4 / 488.9 / 816
100construct + fill + sum27.8 / 92822.1 / 89622.9 / 021.6 / 030.6 / 816
100fill!7.1 / 07.5 / 09.0 / 09.0 / 08.1 / 0
100sum5.9 / 06.1 / 06.8 / 06.1 / 011.0 / 0
100indexing1.1 / 01.3 / 02.2 / 02.2 / 01.1 / 0
100copyto!7.8 / 08.5 / 010.8 / 010.5 / 07.2 / 0
100dot13.2 / 013.4 / 09.6 / 09.4 / 09.0 / 0
100affine loop7.5 / 08.0 / 09.0 / 08.8 / 07.5 / 0
100in-place broadcast expression8.9 / 08.8 / 015.9 / 011.7 / 028.4 / 0
1000escaping construction37.8 / 825636.9 / 82567.5 / 649.2 / 4825.7 / 8064
1000construct + fill + sum172.6 / 8256170.0 / 8224140.6 / 0139.9 / 0574.7 / 8064
1000fill!59.2 / 057.6 / 057.9 / 057.6 / 0105.7 / 0
1000sum59.3 / 059.2 / 060.2 / 059.7 / 0378.3 / 0
1000indexing0.9 / 01.3 / 02.2 / 02.2 / 01.1 / 0
1000copyto!65.7 / 065.5 / 068.4 / 067.0 / 063.1 / 0
1000dot97.5 / 097.6 / 084.7 / 084.4 / 083.5 / 0
1000affine loop64.4 / 065.0 / 064.2 / 064.5 / 064.2 / 0
1000in-place broadcast expression63.9 / 063.9 / 071.4 / 067.3 / 0273.3 / 0
10000escaping construction159.3 / 81984162.6 / 819847.5 / 649.5 / 48—
10000construct + fill + sum1533.3 / 819841537.5 / 819521208.3 / 01204.2 / 0—
10000fill!551.4 / 0550.3 / 0546.3 / 0546.1 / 0—
10000sum614.3 / 0615.7 / 0603.5 / 0602.3 / 0—
10000indexing1.1 / 01.3 / 02.2 / 02.2 / 0—
10000copyto!746.2 / 0776.3 / 0740.0 / 0572.1 / 0—
10000dot1104.2 / 01104.2 / 01054.2 / 01070.8 / 0—
10000affine loop645.9 / 0633.7 / 0625.0 / 0625.0 / 0—
10000in-place broadcast expression628.4 / 0631.9 / 0634.5 / 0626.8 / 0—
100000escaping construction696.2 / 802880698.4 / 8028807.6 / 649.8 / 48—
100000construct + fill + sum14333.0 / 80288014375.0 / 80284812792.0 / 012875.0 / 0—
100000fill!5444.5 / 05465.2 / 05430.5 / 05430.5 / 0—
100000sum6775.0 / 06725.0 / 06800.0 / 06800.0 / 0—
100000indexing1.1 / 01.3 / 02.2 / 02.2 / 0—
100000copyto!8194.3 / 08153.0 / 08152.7 / 08153.0 / 0—
100000dot11584.0 / 011542.0 / 011583.0 / 011584.0 / 0—
100000affine loop11375.0 / 011000.0 / 011375.0 / 011417.0 / 0—
100000in-place broadcast expression11542.0 / 011042.0 / 011500.0 / 011583.0 / 0—

<!– END GENERATED BENCHMARK: additional –>

Construction inside a non-escaping scope is measured separately in the CSV for both Goose variants. The CSV also reports arena bytes consumed. Zero GC bytes does not mean zero memory usage: for these Float64 arrays, elements occupy 8×n bytes, plus initial metadata and any escaping descriptors.

Immutable StaticArrays reference results

<!– BEGIN GENERATED BENCHMARK: svector –>

nSVector sumSVector abs2 reductionSVector map then sumSVector broadcast then sum
21.1 / 01.5 / 01.5 / 01.5 / 0
31.1 / 01.5 / 01.8 / 01.8 / 0
41.0 / 01.5 / 01.8 / 01.8 / 0
81.3 / 01.8 / 01.9 / 01.9 / 0
161.5 / 02.1 / 02.3 / 02.4 / 0
322.2 / 03.5 / 05.0 / 05.0 / 0
646.0 / 09.3 / 012.5 / 012.5 / 0
10011.0 / 017.3 / 023.6 / 023.6 / 0
1000378.3 / 0401.0 / 0589.1 / 0589.1 / 0

<!– END GENERATED BENCHMARK: svector –>

SMatrix multiplication followed by summation is also available in the CSV for small matrices.

Compilation and specialization

Measurements use a fresh process, excluding input construction and package loading. The first call uses invokelatest to include compilation of the measured kernel. Timings depend on call order and compiler behavior, so these do not constitute a full startup benchmark. Counts refer to MethodInstance objects, not an exhaustive inventory of CodeInstance objects.

<!– BEGIN GENERATED BENCHMARK: specialization –>

FamilyShapes testedConcrete typesFinal kernel instancesCumulative kernel compilation (ms)
Array11114.080
FixedSizeArray111115.825
GooseArray11117.212
StaticGooseArray11111173.773
MVector99954.738
SVector99925.656

<!– END GENERATED BENCHMARK: specialization –>

GooseArray retains a single concrete type across all tested lengths. StaticGooseArray and StaticArrays intentionally specialize by shape. Generation tokens and arena identities are not type parameters; tests cover recreating arrays with identical shapes.

Validation and limitations

6,030 assertions passed via Pkg.test with --check-bounds=yes in the original benchmark campaign. The tests cover shapes, zero-copy conversions, aliasing, nested scopes, memory reuse, callbacks that invalidate arenas, matrix operations, allocations, and specialization. Both Goose array variants retain lifetime checks even under @inbounds; as in Julia, bounds checks may still be disabled by @inbounds.

Results cover warmed-up kernels with concrete types. The arena and scope states are allocated once, while descriptors can still incur GC allocations if they escape. Static dimensions do not imply inline tuples or native stack placement. The LLVM optimization is enabled on Julia 1.13.x (tested on 1.13.3), with a portable fallback on other versions. Static shapes do not guarantee a speedup for every operation.

The benchmark case count includes all families and sizes; it is not a count of wins by any one type. Minimum and p95 values are in the CSV files; the tables show medians. RSS and physical memory pages were not measured. No direct speed comparison with the Goose language was performed.

Reproduce these measurements

Public release 0.1.0 uses code from the last prototype iteration, which was still internally numbered 0.6.0 when these measurements were collected. The CSV files are historical reference measurements, not universal performance guarantees. Raw values and environment details are available in benchmark/reference/m5-max-2026-10-31/.

From the repository root:

julia --startup-file=no benchmark/bench.jl
julia --startup-file=no benchmark/bench.jl --full

The first command runs a short selection; the second runs both full suites. Outputs are written to the untracked benchmark/results/ directory. Use --out path/to/directory for a different destination.

Refresh the displayed tables

All benchmark tables in this page and the README are generated by a Julia-only script from the CSV files in benchmark/reference/m5-max-2026-10-31/:

julia --startup-file=no benchmark/update_tables.jl

For a new campaign, first save the benchmarks.csv, staged.csv, and, if available, specialization.csv files in a version-controlled reference folder. Then refresh both Markdown files in one command:

julia --startup-file=no benchmark/update_tables.jl --source benchmark/reference/my-new-run

If specialization.csv is missing, its existing table is left unchanged. Update the written hardware, Julia version, date, case counts, and methodology separately: the generator only replaces the tables, not their contextual text. For CI-style consistency checks, use --check instead of regenerating files.

Out-of-place map timings include consuming the result and, for Goose arrays, leaving the scope. Zero reported GC allocation does not mean the arena uses zero bytes. Escaping descriptors and arena initialization can allocate on the GC heap. Results depend on the machine, Julia version, and execution context.