What is nanobench and what is it used for?
Updated
nanobench is a C++ microbenchmarking library for measuring small code snippets. It is header-only and can be used by direct inclusion or through CMake integration. It is intended for benchmarking code that is fast, slow, or unstable, and it produces results as tables, CSV, JSON, HTML box plots, or pyperf output. Use it when you need a repeatable measurement of a small piece of C++ code and want the result in a form you can read, compare, or feed into another tool.
What problem it solves
Measuring small code snippets with a hand-rolled timer is easy to get wrong: the measured time can be dominated by setup, the compiler can optimize the work away, and a single run says little about variation. nanobench is designed around the experiment rather than just the timer. Its documentation covers design goals, how a round is reduced to one number, estimating and reporting, what was rejected, and serial correlation and why warmup is not the answer. In practice, that means you define the benchmark, let the library run it, and then read a result that includes more than one number.
How you use it
A benchmark is built around ankerl::nanobench::Bench. The main entry point is Bench(), and the workflow is:
- Create a
Benchobject. - Configure it as needed, for example with
title(),name(),context(),batch(),unit(),timeUnit(),warmup(),epochs(),minEpochTime(),maxEpochTime(),minEpochIterations(), orepochIterations(). - Call
run()with the code to measure.doNotOptimizeAway()is available to keep the compiler from removing the work. - Read the results through
results(), or render them withrender().
For comparisons, compare() and CompareResult provide size(), operator[](), rounds(), comparisons(), isSignificant(), and fastest(), so you can check whether a difference is significant rather than just looking at two numbers.
Output formats
The library documents several output paths, each suited to a different use:
| Output | How it is produced | Typical use |
|---|---|---|
| Table | Default console output with configurable columns | Reading results directly |
| CSV | templates::csv / csv() |
Spreadsheets and further analysis |
| JSON | templates::json / json() |
Passing results to other tools |
| HTML box plot | templates::htmlBoxplot / htmlBoxplot() |
Seeing the distribution of runs |
| pyperf | templates::pyperf / pyperf() |
The Python pyperf module |
Columns can be chosen with showColumn(), hideColumn(), and isColumnVisible(), and context can be shown as columns with contextColumn() and clearContextColumns(). Available columns include relative, complexityN, timePerUnit, unitPerSecond, error, instructions, cycles, ipc, branches, branchMisses, and total.
Reading the output
The documentation has a dedicated section on reading the output and on how precise a comparison is. It also covers asymptotic complexity through complexityN(), complexityBigO(), and the complexityBigO() column, which is useful when you want to see how cost grows with input size rather than only how fast one case runs. For unstable code, the histogram and box plot outputs show the spread that a single average would hide.
Practical notes
NANOBENCH_ENDLESSruns a specific test endlessly.NANOBENCH_SUPPRESS_WARNINGSturns off stability warnings.NANOBENCH_CONFIGchanges settings without recompiling.- The documentation includes comparisons against Google Benchmark, nonius, Picobench, Catch2, moodycamel::microbench, sltbench, Celero, and folly Benchmark, with source code and results for each, which is useful if you are choosing between libraries.
If you only need a quick timing of one function, a simple timer may be enough. If you need to compare alternatives, check whether a difference is significant, or present results as a table, CSV, JSON, or box plot, nanobench is built for that job.