应使用clock_gettime(clock_process_cputime_id, ...)获取进程级精确cpu时间,它返回用户态与内核态实际执行时间之和,纳秒级精度,需链接-lrt,两次采样差值才反映真实cpu开销。

用 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) 获取进程级精确CPU时间
要拿到当前进程在CPU上真正执行的时间(排除休眠、等待IO等非执行时间),clock_gettime 是Linux下最直接可靠的选择。它返回的是进程自启动以来在所有CPU核心上实际消耗的**用户态 + 内核态**CPU时间,精度通常达纳秒级。
关键点:必须传入 CLOCK_PROCESS_CPUTIME_ID —— 这个时钟只对调用进程有效,且完全不依赖系统挂钟或调度延迟,是真正的“执行时间片”度量。
- 不能用
CLOCK_MONOTONIC或CLOCK_REALTIME,它们测的是墙钟时间,包含睡眠、抢占、中断等待 - 不能用
getrusage(RUSAGE_SELF, ...)的ru_utime/ru_stime,其微秒精度在现代高性能场景下明显不足,且部分glibc实现存在舍入误差 - 调用前需确保链接
-lrt(POSIX实时库),否则链接失败报undefined reference to clock_gettime
两次采样差值才是有意义的CPU时间片
单次 clock_gettime 值本身意义有限;真实分析靠的是两个时间点之间的差值,即某段代码/函数/循环体实际占用了多少CPU周期。
示例:测一个密集计算循环的纯CPU开销
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
#include <time.h> struct timespec start, end; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); // ... your hot loop here ... clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); double delta_ns = (end.tv_sec - start.tv_sec) * 1e9 + (end.tv_nsec - start.tv_nsec); </time.h>
- 务必用
struct timespec,不要转成double秒再乘——大数值下浮点精度会丢失纳秒量级细节 - 避免在采样区间内触发系统调用(如
printf、malloc),否则统计会混入内核态时间,失真 - 若循环太短(volatile 或用
asm volatile("" ::: "memory")防止过度优化
注意多线程下 CLOCK_PROCESS_CPUTIME_ID 的聚合行为
这个时钟统计的是整个进程所有线程的CPU时间总和,不是单线程独占时间。如果你在多线程程序中用它测某段并行代码,得到的是所有worker线程累计消耗的CPU时间,可能远大于 wall-clock 时间(比如4核满跑2秒 → 约8秒CPU时间)。
- 想测单个线程的CPU时间?得换
CLOCK_THREAD_CPUTIME_ID,并确保在目标线程内调用 - 跨线程共享同一个
struct timespec变量?必须加锁或使用线程局部存储(thread_local),否则读写竞争导致结果乱码 - 频繁调用
clock_gettime本身有开销(约50–200ns),高频率采样(如每微秒一次)会显著污染测量结果
对比 /proc/[pid]/stat 中的 utime 和 stime
虽然 /proc/[pid]/stat 第14、15字段(utime、stime)也表示用户态/内核态CPU时间,但它是**jiffies单位**(通常10ms一格),且只在进程被调度器更新时刷新(非实时),不适合精细性能分析。
- 读取该文件需打开、解析、转换,延迟高、不可靠,仅适合粗粒度监控(如top、ps)
- 它的值和
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)在长时间运行后应大致一致,但短期偏差可达几十毫秒 - 若发现两者长期严重偏离(如
clock_gettime增长极慢而/proc/pid/stat疯涨),大概率是进程被cgroup限频或CPU affinity被强制绑定到低频核心
真正做性能热点定位,别碰 /proc 文件——它不是为低延迟采样设计的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










