不能用std::chrono::steady_clock获取墙钟时间,它仅提供单调递增的高精度间隔测量;墙钟时间应使用std::chrono::system_clock,因steady_clock反映的是自系统启动以来的稳定流逝时间,与现实世界时间无关。

用 std::chrono::steady_clock 获取可靠的墙钟时间
墙钟时间(real-time / wall-clock time)是你看表时的时间,它反映真实流逝,但不等于程序实际占用 CPU 的时间。在 C++11 及以后,std::chrono::steady_clock 是首选——它单调、不可调、分辨率高,且不受系统时钟跳变影响。
常见错误是误用 std::chrono::system_clock 做计时:它可能因 NTP 同步或手动调时而倒退或跳跃,导致测出负值或异常大值。
- 测量一段代码耗时,统一用
steady_clock::now()前后取差 - 若需转换为秒/毫秒,用
duration_cast<seconds>()</seconds>或duration_cast<milliseconds>()</milliseconds> - 注意:不同平台的
steady_clock底层实现不同(Linux 通常是CLOCK_MONOTONIC),但接口行为一致
auto start = std::chrono::steady_clock::now(); do_work(); auto end = std::chrono::steady_clock::now(); auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
用 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) 获取进程级 CPU 时间
标准库没直接暴露“进程 CPU 时间”的接口,std::clock() 理论上返回 CPU 时间,但实际在多数现代系统(尤其是 Linux)上它只返回 CLOCK_MONOTONIC 或等效的墙钟时间,精度低、易溢出(CLOCKS_PER_SEC 通常仅 1e6),基本不可靠。
真正可用的是 POSIX 的 clock_gettime,配合 CLOCK_PROCESS_CPUTIME_ID(整个进程的用户态 + 内核态 CPU 时间)或 CLOCK_THREAD_CPUTIME_ID(单线程)。Windows 需用 QueryProcessCycleTime 或 GetThreadTimes,但跨平台时建议封装。
立即学习“C++免费学习笔记(深入)”;
- 必须链接
-lrt(Linux),否则链接失败报undefined reference to `clock_gettime` -
CLOCK_PROCESS_CPUTIME_ID不包含子进程时间,只统计当前进程 - 该时间不含等待 I/O、睡眠、被抢占的时间,纯 CPU 占用——适合分析算法计算开销
struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); double cpu_sec = ts.tv_sec + ts.tv_nsec * 1e-9;
Windows 下获取 CPU 时间的替代方案
Windows 没有 clock_gettime,但 GetProcessTimes 能拿到 FILETIME 格式的用户态和内核态 CPU 时间,加起来就是总 CPU 时间。注意:FILETIME 是 100 纳秒单位,需转成秒。
-
GetProcessTimes(GetCurrentProcess(), &ftCreate, &ftExit, &ftKernel, &ftUser)中,ftKernel和ftUser是关键 - 两个
FILETIME相加后,用ULARGE_INTEGER转换再除以 1e7 得到秒 - 不要用
clock()或timeGetTime()替代——前者不准,后者是墙钟
FILETIME ftKernel, ftUser; GetProcessTimes(GetCurrentProcess(), nullptr, nullptr, &ftKernel, &ftUser); ULARGE_INTEGER uk, kk; uk.LowPart = ftUser.dwLowDateTime; uk.HighPart = ftUser.dwHighDateTime; kk.LowPart = ftKernel.dwLowDateTime; kk.HighPart = ftKernel.dwHighDateTime; double cpu_sec = (uk.QuadPart + kk.QuadPart) / 1e7;
为什么不能混用 wall-clock 和 CPU 时间做性能归因?
一个函数耗时 100ms 墙钟,但只用了 5ms CPU 时间,说明它大部分时间在等磁盘、网络或锁——这时优化算法毫无意义,得查 I/O 或并发瓶颈。反过来,CPU 时间远大于墙钟(极少见),往往意味着多线程重复计时或时钟源异常。
- 并行程序中,总 CPU 时间可远超墙钟时间(比如 4 线程各跑 100ms,墙钟约 100ms,CPU 时间约 400ms)
- 调试时若发现 CPU 时间 ≈ 0 但墙钟很长,基本锁定为阻塞操作(如
read、sleep、锁竞争) - 某些容器环境(如 Docker)下,
CLOCK_PROCESS_CPUTIME_ID可能受限于 cgroup CPU quota,读出值会“被压缩”
真正难的不是怎么取数,而是理解这两个时间维度各自代表什么,并在日志、benchmark 或 profiler 中同时采集两者——缺一不可。


















