1. What Are Benchmarks?
A benchmark is a controlled, repeatable experiment that measures the performance characteristics of a piece of code.
A good benchmark answers questions like:
- How long does this method take to run?
- How many CPU cycles does this algorithm consume?
- What is the memory allocation?
- How does performance change with input sizes?
- Does version A outperform version B?
✔ Benchmarking Focuses On:
- Execution time (ns, µs, ms)
- Memory allocations
- Throughput (operations/sec)
- JIT/Runtime behavior
- GC impact
- Branch prediction & micro-architectural effects
2. Why Benchmarking Is Needed?
Because developers guess, but numbers never lie.
Benchmarking helps you:
✔ 1. Compare two algorithms
Example:List<T> vs Span<T> vs Array.
✔ 2. Detect regressions
Upgrading from .NET 6 → 8 → 9 may change performance.
✔ 3. Understand JIT optimizations
- inlining
- bounds check elimination
- loop unrolling
✔ 4. Optimize hot paths
Critical in:
- microservices
- high-frequency trading
- game engines
- telemetry pipelines
✔ 5. Avoid “fake performance perception”
Normal debugging/profiling distorts real performance.
A benchmark runs code:
- multiple times
- warms up the JIT
- isolates noise
- prints statistically correct data
That is why BenchmarkDotNet exists.
3. What Is BenchmarkDotNet?
BenchmarkDotNet is an open-source, industry-standard benchmarking framework for .NET created by .NET performance experts.
It is used by:
- Microsoft .NET runtime team
- JetBrains
- StackOverflow
- Elastic
- Cloudflare
- Prof. Andrey Akinshin (GC expert)
✔ What it does?
It automatically:
- Compiles benchmarks in RELEASE mode
- Runs warm-ups
- Runs in-process or in a separate process
- Produces statistically accurate reports
- Removes JIT & GC noise
- Exports results to HTML/Markdown/CSV
- Supports hardware counters (Perf Counters, PMCs)
- Works on Windows, Linux, macOS
4. Key Features of BenchmarkDotNet (2025)
✔ Full cross-platform (.NET 6–9)
Supports Windows/Linux/macOS, ARM64, Docker.
✔ Automatic Environment Info
- CPU name
- OS version
- .NET runtime version
- Turbo boost, frequency
- GC mode
- Memory info
✔ Accurate measurements
- Warmup
- Pilot execution
- Auto iteration
- Outlier removal
- Confidence intervals
- Standard deviation
✔ Memory diagnostics
- Allocations per operation
- GC pressure
✔ Hardware counters
Supports:
- Branch misses
- Cache hits/misses
- Instruction count
- CPU cycles
✔ Export formats
- HTML
- Markdown
- JSON
- CSV
- GitHub-flavored tables
✔ Baseline comparison
Easy before/after performance comparison.
✔ Parameterized benchmarks
Run inputs like 10, 100, 1000 automatically.
5. Installing BenchmarkDotNet (Latest Version 2025)
Run:
dotnet add package BenchmarkDotNet
Verify:
dotnet list package
Code language: PHP (php)
6. Basic Workflow of BenchmarkDotNet
Step 1 — Create a console app
dotnet new console -n BenchmarksDemo
cd BenchmarksDemo
Code language: JavaScript (javascript)
Step 2 — Install BenchmarkDotNet
dotnet add package BenchmarkDotNet
Step 3 — Create Benchmark class
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class StringBenchmarks
{
[Benchmark]
public string ConcatPlus() => "Hello" + "World";
[Benchmark]
public string ConcatJoin() => string.Join("", "Hello", "World");
[Benchmark]
public string ConcatStringBuilder()
{
var sb = new System.Text.StringBuilder();
sb.Append("Hello");
sb.Append("World");
return sb.ToString();
}
}
Code language: PHP (php)
Step 4 — Run benchmarks
BenchmarkRunner.Run<StringBenchmarks>();
Code language: HTML, XML (xml)
Step 5 — Build & Run (Always RELEASE mode)
dotnet run -c Release
BenchmarkDotNet automatically:
- emits code
- runs warmups
- executes millions of iterations
- prints HTML reports
Output example:
| Method | Mean | Error | StdDev | Allocated |
|------------------ |----------:|---------:|---------:|------------:|
| ConcatPlus | 12.25 ns | 0.20 ns | 0.18 ns | - |
| ConcatJoin | 23.12 ns | 0.18 ns | 0.17 ns | 24 B|
| ConcatStringBuilder | 45.55 ns | 0.55 ns | 0.50 ns | 120 B|
Code language: JavaScript (javascript)
7. BenchmarkDotNet Commands / Attributes (Latest 2025 Guide)
✔ [Benchmark]
Marks a benchmark method.
✔ [MemoryDiagnoser]
Adds memory usage & allocations.
✔ [SimpleJob]
Custom job configuration.
Example:
[SimpleJob(RuntimeMoniker.Net80)]
Code language: JSON / JSON with Comments (json)
✔ [Params]
Parameterized benchmark inputs.
[Params(10, 100, 1000)]
public int Size;
Code language: CSS (css)
✔ [BenchmarkCategory]
Categorize benchmarks.
✔ [IterationCount]
Controls iterations.
✔ [WarmupCount]
Warm-up run count.
✔ [Baseline]
Mark comparison baseline.
✔ [RankColumn]
Ranks the results.
✔ [Orderer]
Sort results by speed.
✔ [HardwareCounters]
Enable hardware-level CPU counters.
8. Practical Examples (Beginner → Advanced)
⭐ Example 1: Basic Benchmark
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[MemoryDiagnoser]
public class MathBenchmark
{
[Benchmark]
public double SqrtFast() => Math.Sqrt(12345);
[Benchmark]
public double Pow() => Math.Pow(12345, 0.5);
}
public class Program
{
public static void Main() => BenchmarkRunner.Run<MathBenchmark>();
}
Code language: PHP (php)
⭐ Example 2: Compare two versions (Baseline)
[MemoryDiagnoser]
public class LoopBench
{
[Benchmark(Baseline = true)]
public int ForLoop()
{
int sum = 0;
for (int i = 0; i < 1000; i++) sum += i;
return sum;
}
[Benchmark]
public int LinqSum() => Enumerable.Range(0, 1000).Sum();
}
Code language: PHP (php)
⭐ Example 3: Parameterized Benchmark
[MemoryDiagnoser]
public class ArrayBench
{
[Params(10, 100, 1000)]
public int N;
[Benchmark]
public int[] AllocateArray() => new int[N];
}
Code language: PHP (php)
⭐ Example 4: Benchmark async/await
[MemoryDiagnoser]
public class AsyncBench
{
[Benchmark]
public async Task Delay() => await Task.Delay(10);
}
Code language: PHP (php)
⭐ Example 5: Benchmark with hardware counters
[HardwareCounters(HardwareCounter.CacheMisses, HardwareCounter.BranchMispredictions)]
[MemoryDiagnoser]
public class CpuBench
{
[Benchmark]
public void Work()
{
long x = 0;
for (int i = 0; i < 1_000_000; i++) x += i;
}
}
Code language: PHP (php)
9. Use Cases of BenchmarkDotNet
✔ Algorithm comparison
- sorting
- searching
- hashing
- JSON serialization
✔ Testing performance regressions
Used in CI pipelines.
✔ Microservices / API optimizations
- cold start time
- deserialization
- routing
✔ Game engines
Unity developers use it for hot paths.
✔ Memory optimization
Detect unnecessary allocations.
✔ Comparing new .NET versions
.NET 6 → .NET 7 → .NET 8 → .NET 9 improvements.
✔ Database client performance
EF Core, Dapper, MongoDB drivers.
10. Best Practices (2025 Edition)
✔ Always run benchmarks in Release mode
Debug mode distorts everything.
✔ Don’t benchmark using IDE run button
Must use:dotnet run -c Release
✔ Don’t benchmark noisy code
Avoid:
- network I/O
- disk
- random sleeps
- unpredictable cache
✔ Avoid too small methods
JIT may inline them.
Use:
[MethodImpl(MethodImplOptions.NoInlining)]
Code language: JSON / JSON with Comments (json)
✔ Use MemoryDiagnoser
Memory is often more important than CPU.
✔ Always isolate variables
Use parameters instead of manual loops.
✔ Avoid reading/writing files
Use mocks for consistency.
✔ Use baselines
Comparisons are clearer.
11. CI/CD Integration (2025)
BenchmarkDotNet supports running inside:
- GitHub Actions
- GitLab CI
- Azure DevOps
- Jenkins
- TeamCity
Use command:
--exporters json
--filter *BenchmarkName*
Example GitHub Action:
- name: Run Benchmarks
run: dotnet run -c Release -- --filter *MyBench*
12. BenchmarkDotNet Architecture (Simplified)
- Generate auto code
- Compile project separately
- Launch a new process
- Warm-up phase
- Pilot phase
- Targeted runs
- Statistical analysis
- HTML export
- Store results in /BenchmarkDotNet.Artifacts/
13. Additional Useful Attributes (2025)
| Attribute | Description |
|---|---|
[MinColumn, MaxColumn] | Show min/max results |
[StdDevColumn] | Standard deviation |
[Orderer] | Sort results by speed |
[RankColumn] | Rank results |
[ThreadingDiagnoser] | Thread usage |
[ConcurrencyVisualizer] | Thread visualization |
[EtwProfiler] | ETW profiler |
[DisassemblyDiagnoser] | JIT ASM output |
14. Advanced: Disassembly (JIT ASM)
[DisassemblyDiagnoser(printSource: true)]
public class Bench
{
[Benchmark]
public int Add() => 1 + 2;
}
Code language: PHP (php)
Run:
dotnet run -c Release -- --disasm
This shows machine instructions.
15. Summary
You now have the most advanced, end-to-end, complete, updated (2025) tutorial for:
✔ Benchmarking fundamentals
✔ BenchmarkDotNet features
✔ Install instructions
✔ Attributes list
✔ Commands
✔ CI/CD Integration
✔ Best practices
✔ Baseline comparisons
✔ Memory and CPU diagnostics
✔ Examples from beginner to expert
Just tell me!
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I have worked at Cotocus. I share tech blog at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow , and SEO strategies at Wizbrand.
Do you want to learn Quantum Computing?
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at WIZBRAND