Quick mode: Benchmark
Benchmark is the entry point for one-off measurements. It requires no class structure, no attributes, and no project setup beyond adding the NuGet reference. Use it anywhere you want a quick, reliable number.
Basic usage
using NBenchmark;
var result = Benchmark.Run(() =>
{
// code to measure
for (int i = 0; i < 1000; i++) { }
});Benchmark.Run runs 25 warmup iterations, then 200 measured iterations, trims the top 5% of outliers, and returns a BenchmarkResult.
Overloads
Synchronous
// Action - for code with no return value
var result = Benchmark.Run(() => DoWork());
// Func<T> - for code that returns a value
// The result is consumed by a sink to prevent the compiler optimising the call away.
var result = Benchmark.Run(() => ComputeHash(data));Async
// Func<Task>
var result = await Benchmark.RunAsync(async () => await FetchDataAsync());
// Func<Task<T>>
var result = await Benchmark.RunAsync(async () => await ComputeAsync(input));Raw outcome
Benchmark.RunRaw returns a MeasurementOutcome which includes both the BenchmarkResult and the raw per-iteration sample array. Use this if you need the underlying data.
var outcome = Benchmark.RunRaw(() => DoWork());
double[] rawSamples = outcome.RawSamples; // nanoseconds, before outlier trimming
BenchmarkResult result = outcome.Result;Custom options
Pass a MeasurementOptions instance to override the defaults:
var options = new MeasurementOptions
{
Iterations = 500,
WarmupIterations = 50,
MeasureAllocations = true,
ConfidenceLevel = 0.99,
};
var result = Benchmark.Run(() => MyMethod(), options: options);See Configuration for the full list of options.
Naming the benchmark
The name parameter sets the label used in output and file reporters:
var result = Benchmark.Run(() => MyMethod(), name: "MyMethod with 1000-item input");Displaying results
Plain text (core package)
result.Print();Output:
MyMethod: 1.20 µs median
Mean: 1.24 µs, P95: 2.00 µs
StdDev: 360 ns
95% CI: 1.19 µs … 1.29 µs (±50 ns)Rich console table (NBenchmark.Console)
using NBenchmark.Console;
await result.PrintAsync();This runs the result through ConsoleReporter and renders a Spectre.Console table.
File reporters
await result.ToMarkdownAsync("results.md");
await result.ToCsvAsync("results.csv");
await result.ToJsonAsync("results/"); // output directoryAccessing result fields directly
BenchmarkResult is a plain record - access any field directly:
Console.WriteLine($"Median: {result.Median} ns");
Console.WriteLine($"Mean: {result.Mean} ns");
Console.WriteLine($"P95: {result.P95} ns");
Console.WriteLine($"StdDev: {result.StandardDeviation} ns");
Console.WriteLine($"Error: ±{result.MarginOfError} ns ({result.ConfidenceLevel * 100:0}% CI)");
Console.WriteLine($"CI: {result.ConfidenceIntervalLower} … {result.ConfidenceIntervalUpper} ns");
if (result.MeanAllocatedBytes.HasValue)
Console.WriteLine($"Alloc: {result.MeanAllocatedBytes.Value} bytes/op");What Benchmark does not do
- It does not compare benchmarks. Use BenchmarkSuite for A/B comparisons.
- It does not run significance testing between multiple results. Significance testing requires paired raw samples and is handled by
BenchmarkSuiteandBenchmarkHost.
Next steps
- Suite mode: BenchmarkSuite - compare two or more implementations
- Configuration - full options reference
- Reporters - save results to files
