hyperfine 是命令行的基准测试工具,Rust 写的单文件 exe。给它几条命令,它每条跑几十轮,然后告诉你均值、标准差、最快最慢,以及「B 比 A 慢百分之多少」。做性能对比的时候,不用自己写计时循环,也不用担心第一轮冷启动把均值带偏。

拿它量这台机器上的几个运行时,结论挺直观:Python 启动一次 482.6 毫秒,是 cmd 的 3.4 倍;Node 181.5 毫秒,只比 cmd 慢 27.1%。

一条命令跑一组对比

hyperfine -w 2 -r 20 --style basic \
  -n "cmd /c exit"    "cmd /c exit" \
  -n "python -c pass" "python -c pass"

-n 给每条命令起个名字,报告里显示这个名字。-w 2 是热身 2 轮不计入成绩,-r 20 是正式跑 20 轮。默认情况下 hyperfine 会自己决定跑几轮,但对比启动开销这类毫秒级任务时,固定次数更利于复现。

输出是四列:均值、标准差、最小值、最大值,最后给一行相对基准的百分比。这个百分比以第一条命令为基准,后面每条都跟它比。

四个运行时的启动开销

同一台机器、各 20 轮、热身 2 轮,比的是「什么都不干,启动起来立刻退出」要多久:

命令均值(毫秒)标准差(毫秒)比 cmd 多(毫秒)相对 cmd
cmd /c exit142.822.70基准
hadolint --version155.414.412.6+8.9%
node -e ""181.511.238.7+27.1%
python -c pass482.623.3339.8+238.0%

cmd 自身 142.8 毫秒,这是 Windows 上起一个 shell 进程的底价,任何走 cmd 的方式都逃不掉。hadolint 只贵 12.6 毫秒,一个 Haskell 写的静态检查器启动开销几乎可以忽略。Node 比 cmd 多 38.7 毫秒,Python 多 339.8 毫秒。

标准差这一列也值得看:cmd 的 22.7 毫秒最大,说明它波动最大;Python 的 23.3 毫秒也不小。做对比时如果两条命令的差值小于标准差之和,这个差值就不太可信。

同一个任务,两种写法差 13%

把 0 到 999999 求和,一个是内置的 sum(range()),一个是手写循环累加,各跑 20 轮:

写法均值(毫秒)比内置多(毫秒)相对内置
sum(range(1000000))476.50基准
循环累加538.461.9+13.0%

差值只有 61.9 毫秒,而两者的启动开销都在 476.5 与 538.4 这个量级,等于九成的耗时跟算法无关。这也说明一件事:Python 短脚本做微基准测试意义有限,先扣掉启动成本再看。

hyperfine 的做法是先热身再计时,扣不掉解释器启动,因为它测的是整条命令的墙钟时间。想只测算法,得在命令内部自己打点。

轮数不是越多越好

轮数均值(毫秒)标准差(毫秒)
-r 3117.43.0
-r 10120.011.6
-r 50131.218.1

同一台机器上测同一件事,跑 3 轮得到 117.4 毫秒,跑 50 轮反而涨到 131.2 毫秒,标准差也从 3.0 涨到 18.1。原因不复杂:跑得越久,系统上别的东西越可能插进来,风扇转速、后台更新、测温轮询都会体现在均值里。

所以轮数不是越高越准。毫秒级命令用 10 到 20 轮就够,需要判断差异是否显著时看标准差,别只看均值。

结果能直接导出

hyperfine -w 1 -r 5 --export-json result.json "cmd /c exit"

导出的 JSON 里有每条命令的 measurements 数组和 summary,summary 里带 mean、stddev、median、min、max 和每轮的耗时。写进报告、画曲线、做回归对比都能直接用。除 JSON 外还支持 CSV 和 Markdown。

被测命令失败会中断

> hyperfine -r 3 "cmd /c exit 7"
Error: Command 'cmd /c exit 7' terminated with non-zero exit code 7
in the first benchmark run. Use the '-i'/'--ignore-failure' option
if you want to ignore this.

退出码 1

只要被测命令返回非零,hyperfine 立刻停下,不给你结果,退出码 1。这是防止「测一条一直报错的命令还得出漂亮数字」的设计。确实需要测失败路径时加 --ignore-failure,它会把失败轮次照样计入统计。

命令本身不存在时报的是 program not found,和退出码非零是两种不同的错误,脚本里能区分。另外 -r 0 会在参数校验阶段就被拒,报 0 is not in 1..18446744073709551615。

什么时候它帮不上忙

测的是内存分配或 CPU 指令数。hyperfine 只测墙钟时间,GC、缺页、调度抖动都会混进去。要看分配和指令,得用 perf、valgrind 这类工具。

单次耗时低于 1 毫秒。进程启动本身就一百多毫秒,被测代码再快也被淹掉,得把循环写进被测命令里,测 N 次的平均值。

需要控制 CPU 频率和负载。它不锁频也不隔离核心,同一台机器上跑两次结果差 10% 很正常。要做严格对比,得自己保证环境一致,或者多跑几组看分布。

还没测的两项:--parameter-list 参数扫描的实际用法 / 与 Linux 下 hyperfine 的差异对比。前者要设计一组参数矩阵,后者要另一台机器。