Benchmark shell commands with hyperfine
Time shell commands with hyperfine: warmup runs, cache-clearing with --prepare, side-by-side comparisons, parameter scans and Markdown or JSON export.
Updated
in short
Run hyperfine 'cmd A' 'cmd B' to time both over repeated runs and see which is faster. Add --warmup or --prepare to control caches, -P/-L to sweep a parameter, and --export-markdown to save the table.
Timing a command once with time gives a single noisy number. hyperfine runs each command many times, reports the mean, standard deviation and range, warns about outliers, and prints how many times faster one command is than another.
This guide covers basic runs, cache control, comparisons, parameter sweeps, export formats, and the shell-spawning correction that matters for very fast commands.
Tools used
hyperfine
Command-line benchmarking tool that runs statistical analysis across multiple timing runs of shell commands
29.2kRustfd
Fast filesystem search tool that replaces find with regex patterns and smart defaults
44.9kRustjq
Command-line JSON processor for slicing, filtering, mapping and transforming structured data
36.0kC
Before you start
- Linux, macOS, BSD or Windows
- The commands you want to measure, working from the current directory
Steps
Step 1: Install hyperfine
hyperfine is packaged for most systems. Distribution packages can be a few releases behind; the GitHub releases page has current binaries and
.debpackages.sh# macOS or Linux with Homebrew brew install hyperfine # Debian / Ubuntu sudo apt install hyperfine # Fedora sudo dnf install hyperfine # Arch Linux sudo pacman -S hyperfine # Windows winget install hyperfine # From source cargo install --locked hyperfineshhyperfine --versionStep 2: Run a basic benchmark
Quote each command. hyperfine does at least 10 runs and picks a run count that takes about 3 seconds in total.
--runssets an exact count;--min-runsand--max-runsset bounds.The result shows the mean and standard deviation, user and system time, and the min and max range.
shhyperfine 'sleep 0.3'shhyperfine --runs 20 'make -s test'Step 3: Control caches with
--warmupand--prepareCommands that read files run faster once the OS has cached them.
--warmup Nruns the command N times before measuring, so every timed run sees a warm cache.--prepareruns a command before each timed run, which you can use to drop the cache and measure cold runs instead.On Linux, dropping the page cache needs root. Run
sudo -vfirst so the prepare command does not stop at a password prompt.shhyperfine --warmup 3 'grep -R TODO .'shsudo -v hyperfine --prepare 'sync; echo 3 | sudo tee /proc/sys/vm/drop_caches' 'grep -R TODO .'Step 4: Compare commands
Pass several commands and hyperfine benchmarks each in turn, then prints a summary of how many times faster the fastest one is.
-ngives each command a short name for the output.fdskips hidden and.gitignored files by default, so-HImakes it walk the same files asfind.hyperfine 1.19+ has
--reference CMDto compare everything against a baseline you choose instead of the fastest command.shhyperfine --warmup 3 \ -n find "find . -name '*.md'" \ -n fd 'fd -HI -e md'shhyperfine --reference 'git status' 'git status --untracked-files=no'Step 5: Scan a parameter with
-Por-L-P NAME MIN MAXruns the command once per integer in the range and replaces{NAME}in the command.-Dsets a different step size, including decimals.-L NAME a,b,ctakes a list of values instead.-Lcan be given several times to benchmark every combination.shhyperfine --prepare 'make clean' -P threads 1 8 'make -j {threads}'shhyperfine -P delay 0.3 0.7 -D 0.2 'sleep {delay}'shhyperfine -L compiler gcc,clang -L opt O0,O2 '{compiler} -{opt} main.c -o /dev/null'Step 6: Export the results
--export-markdownwrites a table you can paste into a README or pull request.--export-jsonwrites every result, including the time of each individual run, for further analysis.--export-csv,--export-asciidocand--export-orgmodeare also available, and several can be used at once. Times in the JSON file are in seconds.shhyperfine --warmup 3 --export-markdown bench.md --export-json bench.json \ "find . -name '*.md'" 'fd -HI -e md'shjq -r '.results[] | "\(.command)\t\(.mean)\t\(.stddev)"' bench.jsonStep 7: Measure very fast commands with
-NBy default hyperfine runs each command through a shell (
shon Unix,cmd.exeon Windows), measures the shell's startup time, and subtracts it. For commands that finish in under about 5 ms, that correction is noisy compared with the command itself.-N(hyperfine 1.13+, same as--shell=none) runs the command directly with no shell. Without a shell, globs,~, pipes,;and variables do not work.--shell(-S) picks a different shell when the command needs its syntax.shhyperfine -N --warmup 10 'git rev-parse HEAD'shhyperfine --shell zsh 'for i in {1..10000}; do echo test; done'
Troubleshooting
Command terminated with non-zero exit code: the command failed. Check it with--show-output, or use-iif failure is expected.Statistical outliers were detected: something else used the CPU or disk. Close other programs, add--warmup, and re-run.Command took less than 5 ms to complete: the shell correction dominates. Re-run with-N.The first benchmarking run ... was significantly slower: caches were cold on the first run. Add--warmup.{name}is not replaced: the name in braces must match the name given to-Por-L.- Shell syntax fails with
-N: there is no shell. Drop-N, or wrap the command assh -c '...'.
Tips
--setupruns once before all runs of a command;--cleanupruns once after them.--concluderuns after each timed run, for example to stop a server started in--prepare.--style basicturns off colors and the progress bar, which keeps CI logs readable.
FAQ
- Does the reported time include shell startup?
- No. hyperfine measures the startup time of an empty shell command and subtracts it. With `-N` there is no shell, so nothing is subtracted.
- Can I benchmark a shell function?
- Aliases are not loaded in the non-interactive shell hyperfine starts. For a bash function, `export -f my_function` and run `hyperfine --shell=bash my_function`, or define the function inside the quoted command.
- How many runs are enough?
- The default (at least 10, about 3 seconds per command) suits most commands. If the standard deviation is large compared with the gap between commands, add runs with `--runs` or `--min-runs`.