Benchmarks Medians of five repetitions on Intel(R) Core(TM) i9-14900HX, commit 8023a0d, 2026-10-22.
Every operation works on float matrices stored column-major; the size column is the side n of an n × n matrix, and fixed marks an operation with one size of its own. The times are per element, so the sizes can be compared. The fastest of a row is bold, and in the last column more than 1× means strata is faster than Eigen.
strata : views evaluated by assign. eigen : the same operation in Eigen, assigned with noalias(). loop : hand-written loops over raw memory, the floor. What a library adds to it is its overhead. strata_arena : strata with the temporaries taken from an arena. add out = x + y for two n × n matrices: the baseline. One pass that reads two arrays and writes one.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0376 ns strata, 256: 0.0941 ns strata, 1024: 0.232 ns eigen, 64: 0.0414 ns eigen, 256: 0.0951 ns eigen, 1024: 0.239 ns loop, 64: 0.0334 ns loop, 256: 0.0913 ns loop, 1024: 0.233 ns
size strata eigen loop strata vs Eigen 64 0.0376 ns 0.0414 ns 0.0334 ns 1.10× 256 0.0941 ns 0.0951 ns 0.0913 ns 1.01× 1024 0.232 ns 0.239 ns 0.233 ns 1.03×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.037 ns strata, 256: 0.0905 ns strata, 1024: 0.243 ns eigen, 64: 0.0363 ns eigen, 256: 0.0905 ns eigen, 1024: 0.232 ns loop, 64: 0.0369 ns loop, 256: 0.095 ns loop, 1024: 0.242 ns
size strata eigen loop strata vs Eigen 64 0.0370 ns 0.0363 ns 0.0369 ns 0.98× 256 0.0905 ns 0.0905 ns 0.0950 ns 1.00× 1024 0.243 ns 0.232 ns 0.242 ns 0.95×
add4 out = w + x + y + z. Does a longer chain still run as one pass? A library that makes a temporary for every + falls behind here; one that fuses the chain pays only for the two extra arrays it reads, so the gap to add is memory traffic, not extra loops.
clang-bench gcc-bench
0.1 ns 1 ns 64 256 1024 strata, 64: 0.131 ns strata, 256: 0.131 ns strata, 1024: 0.373 ns eigen, 64: 0.132 ns eigen, 256: 0.136 ns eigen, 1024: 0.368 ns loop, 64: 0.132 ns loop, 256: 0.141 ns loop, 1024: 0.367 ns
size strata eigen loop strata vs Eigen 64 0.131 ns 0.132 ns 0.132 ns 1.01× 256 0.131 ns 0.136 ns 0.141 ns 1.04× 1024 0.373 ns 0.368 ns 0.367 ns 0.99×
0.1 ns 1 ns 64 256 1024 strata, 64: 0.131 ns strata, 256: 0.13 ns strata, 1024: 0.416 ns eigen, 64: 0.125 ns eigen, 256: 0.127 ns eigen, 1024: 0.389 ns loop, 64: 0.129 ns loop, 256: 0.131 ns loop, 1024: 0.402 ns
size strata eigen loop strata vs Eigen 64 0.131 ns 0.125 ns 0.129 ns 0.96× 256 0.130 ns 0.127 ns 0.131 ns 0.98× 1024 0.416 ns 0.389 ns 0.402 ns 0.93×
add_mixed_order The destination is row-major, the operands column-major. The loops are nested, the destination is written in its own order and the operands are read across: the price of mismatched layouts.
clang-bench gcc-bench
0.1 ns 1 ns 10 ns 64 256 1024 strata, 64: 0.372 ns strata, 256: 0.766 ns strata, 1024: 3.39 ns eigen, 64: 0.323 ns eigen, 256: 0.945 ns eigen, 1024: 4.61 ns
size strata eigen strata vs Eigen 64 0.372 ns 0.323 ns 0.87× 256 0.766 ns 0.945 ns 1.23× 1024 3.39 ns 4.61 ns 1.36×
0.1 ns 1 ns 10 ns 64 256 1024 strata, 64: 0.365 ns strata, 256: 0.753 ns strata, 1024: 3.2 ns eigen, 64: 0.334 ns eigen, 256: 0.922 ns eigen, 1024: 5.24 ns
size strata eigen strata vs Eigen 64 0.365 ns 0.334 ns 0.91× 256 0.753 ns 0.922 ns 1.22× 1024 3.20 ns 5.24 ns 1.64×
add_ramp out = x + ramp, where ramp(i, j) = i + j is computed from the indices and never read from memory. Nested loops with the coordinates stepped like offsets.
clang-bench gcc-bench
0.1 ns 1 ns 64 256 1024 strata, 64: 0.846 ns strata, 256: 0.832 ns strata, 1024: 0.831 ns eigen, 64: 0.846 ns eigen, 256: 0.832 ns eigen, 1024: 0.831 ns
size strata eigen strata vs Eigen 64 0.846 ns 0.846 ns 1.00× 256 0.832 ns 0.832 ns 1.00× 1024 0.831 ns 0.831 ns 1.00×
0.1 ns 1 ns 64 256 1024 strata, 64: 0.536 ns strata, 256: 0.565 ns strata, 1024: 0.538 ns eigen, 64: 0.532 ns eigen, 256: 0.531 ns eigen, 1024: 0.529 ns
size strata eigen strata vs Eigen 64 0.536 ns 0.532 ns 0.99× 256 0.565 ns 0.531 ns 0.94× 1024 0.538 ns 0.529 ns 0.98×
add_row_major add with all three matrices row-major, walked in their own order. It should match add: the same flat loop.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0377 ns strata, 256: 0.0943 ns strata, 1024: 0.234 ns eigen, 64: 0.0414 ns eigen, 256: 0.0942 ns eigen, 1024: 0.228 ns
size strata eigen strata vs Eigen 64 0.0377 ns 0.0414 ns 1.10× 256 0.0943 ns 0.0942 ns 1.00× 1024 0.234 ns 0.228 ns 0.98×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0367 ns strata, 256: 0.0913 ns strata, 1024: 0.261 ns eigen, 64: 0.038 ns eigen, 256: 0.0906 ns eigen, 1024: 0.251 ns
size strata eigen strata vs Eigen 64 0.0367 ns 0.0380 ns 1.03× 256 0.0913 ns 0.0906 ns 0.99× 1024 0.261 ns 0.251 ns 0.96×
axpy out = 2x + y: a scalar multiplication fused into the addition, the classic axpy .
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0451 ns strata, 256: 0.0943 ns strata, 1024: 0.231 ns eigen, 64: 0.0438 ns eigen, 256: 0.0938 ns eigen, 1024: 0.226 ns
size strata eigen strata vs Eigen 64 0.0451 ns 0.0438 ns 0.97× 256 0.0943 ns 0.0938 ns 0.99× 1024 0.231 ns 0.226 ns 0.98×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0382 ns strata, 256: 0.0909 ns strata, 1024: 0.25 ns eigen, 64: 0.037 ns eigen, 256: 0.0906 ns eigen, 1024: 0.25 ns
size strata eigen strata vs Eigen 64 0.0382 ns 0.0370 ns 0.97× 256 0.0909 ns 0.0906 ns 1.00× 1024 0.250 ns 0.250 ns 1.00×
block add on the n/2 × n/2 corner of each matrix. Every column of a block is contiguous but the columns are n apart, so this is a strided view that is not one flat run. The time is per element of the block.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0965 ns strata, 256: 0.11 ns strata, 1024: 0.286 ns eigen, 64: 0.142 ns eigen, 256: 0.162 ns eigen, 1024: 0.303 ns
size strata eigen strata vs Eigen 64 0.0965 ns 0.142 ns 1.47× 256 0.110 ns 0.162 ns 1.47× 1024 0.286 ns 0.303 ns 1.06×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0936 ns strata, 256: 0.109 ns strata, 1024: 0.292 ns eigen, 64: 0.11 ns eigen, 256: 0.106 ns eigen, 1024: 0.323 ns
size strata eigen strata vs Eigen 64 0.0936 ns 0.110 ns 1.17× 256 0.109 ns 0.106 ns 0.98× 1024 0.292 ns 0.323 ns 1.11×
column_sums Sums along the fast axis: every result reads one contiguous column, front to back.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.212 ns strata, 256: 0.108 ns strata, 1024: 0.0859 ns eigen, 64: 0.055 ns eigen, 256: 0.0314 ns eigen, 1024: 0.0937 ns loop, 64: 0.146 ns loop, 256: 0.0549 ns loop, 1024: 0.0828 ns
size strata eigen loop strata vs Eigen 64 0.212 ns 0.0550 ns 0.146 ns 0.26× 256 0.108 ns 0.0314 ns 0.0549 ns 0.29× 1024 0.0859 ns 0.0937 ns 0.0828 ns 1.09×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.172 ns strata, 256: 0.0581 ns strata, 1024: 0.072 ns eigen, 64: 0.0544 ns eigen, 256: 0.0283 ns eigen, 1024: 0.076 ns loop, 64: 0.125 ns loop, 256: 0.054 ns loop, 1024: 0.0709 ns
size strata eigen loop strata vs Eigen 64 0.172 ns 0.0544 ns 0.125 ns 0.32× 256 0.0581 ns 0.0283 ns 0.0540 ns 0.49× 1024 0.0720 ns 0.0760 ns 0.0709 ns 1.06×
count_positive count(x > 0): a reduction of a mask to one number.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0889 ns strata, 256: 0.0881 ns strata, 1024: 0.105 ns eigen, 64: 0.697 ns eigen, 256: 0.697 ns eigen, 1024: 0.697 ns loop, 64: 0.0888 ns loop, 256: 0.0881 ns loop, 1024: 0.105 ns
size strata eigen loop strata vs Eigen 64 0.0889 ns 0.697 ns 0.0888 ns 7.84× 256 0.0881 ns 0.697 ns 0.0881 ns 7.91× 1024 0.105 ns 0.697 ns 0.105 ns 6.65×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0994 ns strata, 256: 0.099 ns strata, 1024: 0.103 ns eigen, 64: 0.0998 ns eigen, 256: 0.0995 ns eigen, 1024: 0.104 ns loop, 64: 0.0994 ns loop, 256: 0.0993 ns loop, 1024: 0.104 ns
size strata eigen loop strata vs Eigen 64 0.0994 ns 0.0998 ns 0.0994 ns 1.00× 256 0.0990 ns 0.0995 ns 0.0993 ns 1.01× 1024 0.103 ns 0.104 ns 0.104 ns 1.01×
fill out = 1.5: a constant written out, a flat write-only loop. Bounded by memory bandwidth.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0173 ns strata, 256: 0.066 ns strata, 1024: 0.107 ns eigen, 64: 0.017 ns eigen, 256: 0.0666 ns eigen, 1024: 0.107 ns
size strata eigen strata vs Eigen 64 0.0173 ns 0.0170 ns 0.98× 256 0.0660 ns 0.0666 ns 1.01× 1024 0.107 ns 0.107 ns 1.00×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.018 ns strata, 256: 0.0663 ns strata, 1024: 0.107 ns eigen, 64: 0.0178 ns eigen, 256: 0.0663 ns eigen, 1024: 0.107 ns
size strata eigen strata vs Eigen 64 0.0180 ns 0.0178 ns 0.99× 256 0.0663 ns 0.0663 ns 1.00× 1024 0.107 ns 0.107 ns 1.00×
magnitude sqrt(x² + y²): a function of <cmath> over an expression.
clang-bench gcc-bench
0.1 ns 1 ns 64 256 1024 strata, 64: 0.794 ns strata, 256: 0.792 ns strata, 1024: 0.793 ns eigen, 64: 0.198 ns eigen, 256: 0.204 ns eigen, 1024: 0.231 ns loop, 64: 0.198 ns loop, 256: 0.204 ns loop, 1024: 0.237 ns
size strata eigen loop strata vs Eigen 64 0.794 ns 0.198 ns 0.198 ns 0.25× 256 0.792 ns 0.204 ns 0.204 ns 0.26× 1024 0.793 ns 0.231 ns 0.237 ns 0.29×
0.1 ns 1 ns 64 256 1024 strata, 64: 0.198 ns strata, 256: 0.198 ns strata, 1024: 0.245 ns eigen, 64: 0.198 ns eigen, 256: 0.198 ns eigen, 1024: 0.245 ns loop, 64: 0.198 ns loop, 256: 0.198 ns loop, 1024: 0.252 ns
size strata eigen loop strata vs Eigen 64 0.198 ns 0.198 ns 0.198 ns 1.00× 256 0.198 ns 0.198 ns 0.198 ns 1.00× 1024 0.245 ns 0.245 ns 0.252 ns 1.00×
materialize Tensor sum = x + y: a new tensor from an expression. The allocation (left uninitialized) is inside the timed loop.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0579 ns strata, 256: 0.0946 ns strata, 1024: 0.244 ns eigen, 64: 0.0612 ns eigen, 256: 0.0945 ns eigen, 1024: 0.234 ns
size strata eigen strata vs Eigen 64 0.0579 ns 0.0612 ns 1.06× 256 0.0946 ns 0.0945 ns 1.00× 1024 0.244 ns 0.234 ns 0.96×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0543 ns strata, 256: 0.0907 ns strata, 1024: 0.247 ns eigen, 64: 0.0582 ns eigen, 256: 0.0907 ns eigen, 1024: 0.243 ns
size strata eigen strata vs Eigen 64 0.0543 ns 0.0582 ns 1.07× 256 0.0907 ns 0.0907 ns 1.00× 1024 0.247 ns 0.243 ns 0.98×
relu where(x > 0, x, 0): a comparison and a select, which is max(x, 0).
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0555 ns strata, 256: 0.0775 ns strata, 1024: 0.176 ns eigen, 64: 0.0483 ns eigen, 256: 0.0804 ns eigen, 1024: 0.171 ns loop, 64: 0.0255 ns loop, 256: 0.0835 ns loop, 1024: 0.172 ns
size strata eigen loop strata vs Eigen 64 0.0555 ns 0.0483 ns 0.0255 ns 0.87× 256 0.0775 ns 0.0804 ns 0.0835 ns 1.04× 1024 0.176 ns 0.171 ns 0.172 ns 0.97×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0361 ns strata, 256: 0.0794 ns strata, 1024: 0.177 ns eigen, 64: 0.061 ns eigen, 256: 0.0799 ns eigen, 1024: 0.173 ns loop, 64: 0.036 ns loop, 256: 0.0794 ns loop, 1024: 0.177 ns
size strata eigen loop strata vs Eigen 64 0.0361 ns 0.0610 ns 0.0360 ns 1.69× 256 0.0794 ns 0.0799 ns 0.0794 ns 1.01× 1024 0.177 ns 0.173 ns 0.177 ns 0.97×
row_sums Sums along the slow axis: every result reads a row, which is strided in a column-major matrix.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0528 ns strata, 256: 0.0711 ns strata, 1024: 0.0857 ns eigen, 64: 0.0237 ns eigen, 256: 0.069 ns eigen, 1024: 0.373 ns loop, 64: 0.0441 ns loop, 256: 0.0412 ns loop, 1024: 0.0822 ns
size strata eigen loop strata vs Eigen 64 0.0528 ns 0.0237 ns 0.0441 ns 0.45× 256 0.0711 ns 0.0690 ns 0.0412 ns 0.97× 1024 0.0857 ns 0.373 ns 0.0822 ns 4.36×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0878 ns strata, 256: 0.0542 ns strata, 1024: 0.0812 ns eigen, 64: 0.0204 ns eigen, 256: 0.0667 ns eigen, 1024: 0.37 ns loop, 64: 0.0482 ns loop, 256: 0.0424 ns loop, 1024: 0.079 ns
size strata eigen loop strata vs Eigen 64 0.0878 ns 0.0204 ns 0.0482 ns 0.23× 256 0.0542 ns 0.0667 ns 0.0424 ns 1.23× 1024 0.0812 ns 0.370 ns 0.0790 ns 4.56×
short_rows_read Sums along axis 0 of a 3 × 2 000 000 matrix: two million results of three values each. The work per result is so small that the overhead of making a result dominates. Fixed size.
short_rows_run Sums along axis 1 of a 2 000 000 × 3 matrix: two million results, all accumulated column after column. Only three long, contiguous passes. Fixed size.
small_temporaries Sixteen temporaries of 8 × 8 in a row, each x + y. strata takes each from the heap, strata_arena from a std::pmr::monotonic_buffer_resource that is released all at once. The time is per element of the sixteen results.
static_add x + y for 4 × 4 matrices whose shape is known at compile time: sixteen elements, nothing to loop over. The time is almost all fixed cost, so do not compare it with the large sizes. Fixed size.
sum The sum of all elements of a matrix, reduced to one number.
clang-bench gcc-bench
0.01 ns 0.1 ns 64 256 1024 strata, 64: 0.0228 ns strata, 256: 0.0281 ns strata, 1024: 0.0693 ns eigen, 64: 0.0317 ns eigen, 256: 0.033 ns eigen, 1024: 0.0716 ns loop, 64: 0.026 ns loop, 256: 0.0266 ns loop, 1024: 0.0711 ns
size strata eigen loop strata vs Eigen 64 0.0228 ns 0.0317 ns 0.0260 ns 1.39× 256 0.0281 ns 0.0330 ns 0.0266 ns 1.17× 1024 0.0693 ns 0.0716 ns 0.0711 ns 1.03×
0.01 ns 0.1 ns 64 256 1024 strata, 64: 0.0215 ns strata, 256: 0.0285 ns strata, 1024: 0.0703 ns eigen, 64: 0.0318 ns eigen, 256: 0.033 ns eigen, 1024: 0.0721 ns loop, 64: 0.0202 ns loop, 256: 0.0256 ns loop, 1024: 0.0722 ns
size strata eigen loop strata vs Eigen 64 0.0215 ns 0.0318 ns 0.0202 ns 1.48× 256 0.0285 ns 0.0330 ns 0.0256 ns 1.16× 1024 0.0703 ns 0.0721 ns 0.0722 ns 1.02×
tall_columns Sums along axis 1 of a 1024 × 16 384 matrix: 1024 results of 16 384 values each, accumulated column after column. Fixed size.
transpose out = x + yᵀ: the second operand is read against its memory order, with a stride of n. It shows what a permuted view costs once the matrix no longer fits in cache.
clang-bench gcc-bench
0.1 ns 1 ns 10 ns 64 256 1024 strata, 64: 0.301 ns strata, 256: 0.608 ns strata, 1024: 3.12 ns eigen, 64: 0.283 ns eigen, 256: 0.603 ns eigen, 1024: 3.15 ns loop, 64: 0.359 ns loop, 256: 0.618 ns loop, 1024: 3.13 ns
size strata eigen loop strata vs Eigen 64 0.301 ns 0.283 ns 0.359 ns 0.94× 256 0.608 ns 0.603 ns 0.618 ns 0.99× 1024 3.12 ns 3.15 ns 3.13 ns 1.01×
0.1 ns 1 ns 10 ns 64 256 1024 strata, 64: 0.232 ns strata, 256: 0.608 ns strata, 1024: 3.21 ns eigen, 64: 0.231 ns eigen, 256: 0.605 ns eigen, 1024: 4.85 ns loop, 64: 0.231 ns loop, 256: 0.612 ns loop, 1024: 3.3 ns
size strata eigen loop strata vs Eigen 64 0.232 ns 0.231 ns 0.231 ns 1.00× 256 0.608 ns 0.605 ns 0.612 ns 1.00× 1024 3.21 ns 4.85 ns 3.30 ns 1.51×
zeros A new tensor of zeros: allocation and value-initialization, with no arithmetic. The cost materialize has to pay on top of add.
clang-bench gcc-bench
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.0222 ns strata, 256: 0.0654 ns strata, 1024: 0.108 ns eigen, 64: 0.0225 ns eigen, 256: 0.0655 ns eigen, 1024: 0.108 ns
size strata eigen strata vs Eigen 64 0.0222 ns 0.0225 ns 1.01× 256 0.0654 ns 0.0655 ns 1.00× 1024 0.108 ns 0.108 ns 1.00×
0.01 ns 0.1 ns 1 ns 64 256 1024 strata, 64: 0.022 ns strata, 256: 0.0654 ns strata, 1024: 0.106 ns eigen, 64: 0.0227 ns eigen, 256: 0.0655 ns eigen, 1024: 0.107 ns
size strata eigen strata vs Eigen 64 0.0220 ns 0.0227 ns 1.03× 256 0.0654 ns 0.0655 ns 1.00× 1024 0.106 ns 0.107 ns 1.01×