最稳妥的性能测试时钟是std::chrono::steady_clock,因其单调且不受系统时间调整影响;high_resolution_clock虽精度高但语义不如steady_clock明确;需用duration_cast转换time_point差值,避免直接使用count()或错误cast导致截断。

用 std::chrono::high_resolution_clock 获取真实运行时间
直接用 std::chrono::high_resolution_clock 是最稳妥的选择,它在绝大多数平台(linux/macOS/windows)上都映射到系统最高精度的单调时钟源。不要用 std::chrono::system_clock,它受系统时间调整影响,测性能会出错。
关键点:
-
high_resolution_clock::now()返回的是一个time_point,不能直接相减得秒数,必须用duration_cast - 测量前建议调用一次
now()预热,避免首次调用因缓存/TLB未命中带来偏差 - 如果只测一次短操作,务必循环多次再取平均,单次
nanoseconds级别可能被噪声淹没
auto start = std::chrono::high_resolution_clock::now(); // your code here auto end = std::chrono::high_resolution_clock::now(); auto ns = std::chrono::duration_cast(end - start).count();
为什么 std::chrono::steady_clock 更适合性能测试
steady_clock 是单调递增、不受系统时间修改干扰的时钟,c++11 起就保证其“稳定”,比 high_resolution_clock 语义更明确。虽然部分旧编译器(如 GCC 4.8)里它和 system_clock 同义,但现代标准下它才是性能测试的首选。
常见误用:
立即学习“C++免费学习笔记(深入)”;
- 把
steady_clock::now().time_since_epoch().count()当作绝对时间戳用——它只是自某个未指定起点的 tick 数,仅差值有意义 - 跨线程共享
time_point做比较——不同线程调用now()没问题,但若涉及 sleep 或调度延迟,需注意上下文一致性 - 用
microseconds或milliseconds直接 cast 短于 1ms 的耗时——会截断为 0,应先 cast 到nanoseconds再转浮点
windows 下 QueryPerformanceCounter 和 chrono 的实际差异
在 Windows 上,high_resolution_clock 底层通常就是 QueryPerformanceCounter(QPC),两者精度一致(约 15–25 ns)。但手动调用 QPC 有额外风险:
- QPC 在某些老旧 bios 或虚拟机中可能不稳(计数器跳变),而
chrono实现已做兜底适配 - QPC 返回的
LARGE_INTEGER需配合QueryPerformanceFrequency手动换算,容易溢出或精度丢失 - Clang/MSVC 对
chrono的内联优化更好,实测开销比裸 QPC 低 1–2 个周期
除非你在写驱动或极端受限环境,否则没必要绕过 chrono。
避免被编译器优化掉待测代码
这是最容易被忽略的问题:如果编译器发现你测的函数没有副作用,它可能整个删掉,导致测出 0ns。
解决方法(按优先级):
- 把计算结果赋给
volatile变量:volatile auto result = expensive_func(); - 用
asm volatile("" ::: "memory")插入编译器屏障(GCC/Clang) - 将输入数据声明为
volatile,或从std::cin读取(仅调试用) - 关掉优化(
-O0)只用于验证逻辑,不能代表真实性能
尤其注意:std::cout 不足以阻止优化,I/O 可能被延迟或缓冲,仍可能被裁剪。