What it is
BenchmarkDotNet is a .NET benchmarking library that handles warm-up, statistics, memory measurement and multi-runtime comparison automatically.
Mark methods with [Benchmark]. The runner isolates each in its own process, warms up, runs many iterations, and reports statistics with allocation counts.
Installation
dotnet add package BenchmarkDotNetGetting started
The smallest useful thing you can do with it, and what each part means.
csharp
[MemoryDiagnoser] // reports allocations, often the real story
[SimpleJob(RuntimeMoniker.Net80)]
public class StringBenchmarks
{
private readonly string[] _parts = Enumerable.Range(0, 100)
.Select(i => i.ToString()).ToArray();
[Benchmark(Baseline = true)]
public string Concat()
{
var result = "";
foreach (var p in _parts) result += p; // O(n^2) allocations
return result;
}
[Benchmark]
public string Builder()
{
var sb = new StringBuilder();
foreach (var p in _parts) sb.Append(p);
return sb.ToString();
}
[Benchmark]
public string Join() => string.Concat(_parts);
}
BenchmarkRunner.Run<StringBenchmarks>();Advanced usage
Where the library earns its place over a simpler alternative.
csharp
public class SortBenchmarks
{
[Params(100, 10_000, 1_000_000)]
public int Size;
private int[] _data = default!;
[GlobalSetup]
public void Setup() => _data = new Random(42).GenerateArray(Size);
[IterationSetup] // runs before each iteration, excluded from timing
public void Reset() => _data.Shuffle(42);
[Benchmark]
public void ArraySort() => Array.Sort(_data);
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Assembly was built in Debug mode
- Run with -c Release. Debug disables optimisations and the numbers would be meaningless.
- Results vary hugely between runs
- Background load or a benchmark that mutates shared state. Use IterationSetup to restore state and close other work.
Best practices
- Always run in Release configuration; the runner refuses Debug for good reason.
- Enable MemoryDiagnoser — allocations usually explain the result.
- Mark one method as Baseline so the report shows relative ratios.
- Return a value from the benchmark so the work cannot be optimised away.
Background
Why it exists, and what it was reacting to.
It became the standard because naive Stopwatch timing is nearly always wrong — JIT warm-up, tiered compilation and garbage collection all distort results in ways this library controls for.
