BENCHMARKS · NUMERICS & SIMD
Vectorized math: scalar loops vs hand-rolled SIMD vs TensorPrimitives. Suite and raw reports: github.com/gdhami-net/dotnet-benchmarks.
SumFloats
Sum 100,000 floats: scalar loop vs hand-rolled Vector<T> SIMD vs TensorPrimitives.
TAKEAWAY Reach for TensorPrimitives first: it's the SIMD win without writing SIMD, and it keeps improving with each release. Hand-rolled Vector<T> only earns its complexity when you need an operation TensorPrimitives doesn't ship.
In this run: TensorPrimitives_sum is fastest — 8.1× faster than the baseline.
In this run: TensorPrimitives_sum is fastest — 8.1× faster than the baseline.
RESULTS
| method | net9.0 | net10.0 | ratio | allocated | Δ net10.0 |
|---|---|---|---|---|---|
| Scalar_loop baseline | 38.0 µs ±622 ns | 38.3 µs ±545 ns | 1.00× | — | +1% |
| Vector_simd | 4.9 µs ±64 ns | 4.8 µs ±10 ns | 0.13× | — | -2% |
| TensorPrimitives_sum | 4.8 µs ±9 ns | 4.7 µs ±62 ns | 0.12× | — | -2% |
RATIO VS BASELINE · net10.0
THE LEDGER · SAME WORKLOAD ACROSS RELEASES (LOG)
The ledger starts here — 3 run recorded. Trend lines appear from the second release onward.
THE CODE BEING MEASURED
Scalar_loop — what this measures
Plain scalar loop — one float at a time.
[Benchmark (Baseline)]
public float Scalar_loop()
{
var sum = 0f;
foreach (var v in _values) sum += v;
return sum;
}Vector_simd — what this measures
Hand-written Vector<float> SIMD with a scalar tail.
[Benchmark]
public float Vector_simd()
{
var acc = Vector<float>.Zero;
var span = _values.AsSpan();
var i = 0;
for (; i <= span.Length - Vector<float>.Count; i += Vector<float>.Count)
acc += new Vector<float>(span.Slice(i, Vector<float>.Count));
var sum = Vector.Sum(acc);
for (; i < span.Length; i++) sum += span[i];
return sum;
}TensorPrimitives_sum — what this measures
TensorPrimitives.Sum — the BCL's vectorized kernel.
[Benchmark]
public float TensorPrimitives_sum()
=> TensorPrimitives.Sum(_values);DotProduct
Dot product of two 100,000-float vectors: scalar vs TensorPrimitives.
TAKEAWAY If you're writing embeddings/similarity code by hand, stop: TensorPrimitives.Dot is the one-liner that's also the fast path.
In this run: TensorPrimitives_dot is fastest — 6.8× faster than the baseline.
In this run: TensorPrimitives_dot is fastest — 6.8× faster than the baseline.
RESULTS
| method | net9.0 | net10.0 | ratio | allocated | Δ net10.0 |
|---|---|---|---|---|---|
| Scalar_dot baseline | 41.3 µs ±75 ns | 42.4 µs ±1.0 µs | 1.00× | — | +3% |
| TensorPrimitives_dot | 6.2 µs ±111 ns | 6.2 µs ±60 ns | 0.15× | — | -0% |
RATIO VS BASELINE · net10.0
THE LEDGER · SAME WORKLOAD ACROSS RELEASES (LOG)
The ledger starts here — 3 run recorded. Trend lines appear from the second release onward.
THE CODE BEING MEASURED
Scalar_dot — what this measures
Scalar multiply-accumulate loop.
[Benchmark (Baseline)]
public float Scalar_dot()
{
var sum = 0f;
for (var i = 0; i < _a.Length; i++) sum += _a[i] * _b[i];
return sum;
}TensorPrimitives_dot — what this measures
TensorPrimitives.Dot.
[Benchmark]
public float TensorPrimitives_dot()
=> TensorPrimitives.Dot(_a, _b);