17370845950

C++ 怎么计算程序运行时间 C++ chrono高精度计时器代码【测试】
最可靠跨平台高精度计时应优先使用 std::chrono::steady_clock,它语义明确、单调稳定;仅当需纳秒级精度且确认平台支持时才考虑 high_resolution_clock。

std::chrono::high_resolution_clock 获取纳秒级起止时间

这是 C++11 起最可靠、跨平台的高精度计时方式,底层通常映射到系统最高精度时钟(如 Linux 的 CLOCK_MONOTONIC 或 Windows 的 QueryPerformanceCounter),不会受系统时间调整影响。

关键点:必须用同一时钟类型获取开始和结束时间,否则差值无定义;time_point 本身不直接可读,需用 duration_cast 转成具体单位。

常见错误:用 system_clock 测运行时间——它反映的是挂钟时间,可能被 NTP 调整或手动修改,导致负值或跳变。

  • 起始时间:auto start = std::chrono::high_resolution_clock::now();
  • 结束时间:auto end = std::chrono::high_resolution_clock::now();
  • 计算毫秒:std::chrono::duration_cast<:chrono::milliseconds>(end - start).count()
  • 计算微秒:std::chrono::duration_cast<:chrono::microseconds>(end - start).count()
  • 计算纳秒(注意溢出风险):std::chrono::duration_cast<:chrono::nanoseconds>(end - start).count()

避免编译器优化干扰真实耗时测量

如果被测代码太简单(比如空循环或纯计算),编译器可能在 -O2 或更高优化级别下整个删掉,测出来永远是 0。必须确保结果被实际使用,或用 volatile / asm volatile 阻止优化。

典型场景:测一个函数执行时间,但返回值没被读取,编译器就认为该调用无副作用,直接优化掉。

  • 安全做法:把函数返回值赋给 volatile 变量,例如 volatile auto result = my_func();
  • 更通用做法(尤其对 void 函数):asm volatile("" ::: "memory"); 插入内存屏障,阻止指令重排和优化
  • 测试前加 std::chrono::high_resolution_clock::now(); 多次预热,减少首次调用 cache 缺失干扰(对短时间测量影响明显)

steady_clockhigh_resolution_clock 选哪个?

steady_clock 保证单调递增、不受系统时间调整影响,是“稳定时钟”语义的首选;high_resolution_clock 是实现定义的,C++ 标准只要求它是“当前系统支持的最高精度时钟”,但很多平台(如 GCC/libstdc++)让它直接 alias 到 steady_clock

所以:优先用 steady_clock —— 它语义明确、行为可预测;只有当你明确需要纳秒级分辨率且确认平台支持时,才考虑 high_resolution_clock,但不要假设它一定比 steady_clock 更快。

  • 推荐写法:auto start

    = std::chrono::steady_clock::now();
  • 别依赖 high_resolution_clock::period::num / .den 判断精度,不同标准库实现差异大
  • Windows 上 MSVC 的 steady_clock 精度约 15.6ms(基于 GetTickCount64),此时应改用 high_resolution_clock(基于 QueryPerformanceCounter,精度 ~100ns)

完整可运行测试示例(含防优化 + 多次采样)

下面这段代码测一个简单循环的耗时,并取 3 次最小值(排除系统抖动干扰),同时防止编译器优化掉循环:

#include 
#include 

int main() { constexpr int iter = 1000000; volatile long sum = 0; // 防优化关键:volatile 变量

auto min_ns = std::chrono::nanoseconds::max();
for (int r = 0; r zuojiankuohaophpcn 3; ++r) {
    auto start = std::chrono::steady_clock::now();
    for (int i = 0; i zuojiankuohaophpcn iter; ++i) {
        sum += i;
    }
    auto end = std::chrono::steady_clock::now();
    auto ns = std::chrono::duration_castzuojiankuohaophpcnstd::chrono::nanosecondsyoujiankuohaophpcn(end - start).count();
    if (ns zuojiankuohaophpcn min_ns.count()) min_ns = std::chrono::nanoseconds(ns);
}

std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Min time: " zuojiankuohaophpcnzuojiankuohaophpcn min_ns.count() zuojiankuohaophpcnzuojiankuohaophpcn " ns\n";
return 0;

}

注意 volatile long sum 和三次采样逻辑——真实性能测试中,单次测量意义不大,最小值比平均值更能反映“理想路径”开销。

真正难的不是写对那几行 now(),而是让被测代码不被优化、不被缓存干扰、不被调度器打断;这些细节不处理,测出来的数字只是幻觉。