linux下clock_gettime(clock_process_cputime_id)获取的是用户态+内核态总cpu时间;纯内核态时间需解析/proc/self/stat第15字段stime并换算,windows则用getprocesstimes的lpkerneltime字段。

Linux下用clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)获取内核态+用户态总CPU时间
直接获取“纯内核态”时间在POSIX层面没有标准接口;clock_gettime返回的是进程自启动以来在**所有CPU模式下(用户态+内核态)**累计消耗的CPU时间,单位纳秒。这是最接近你需求、且可移植性最好的方案。
-
CLOCK_PROCESS_CPUTIME_ID统计的是当前进程(含所有线程)在CPU上实际运行的时间,包含系统调用陷入内核后执行的代码耗时 - 它不包含进程休眠、等待IO或被调度器挂起的时间,所以是真正的“占用CPU”时间
- 需要链接
-lrt(部分旧环境),现代glibc通常默认可用 - 示例:
#include <time.h> struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); long long total_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;</time.h>
想分离出纯内核态时间?只能靠/proc/[pid]/stat解析
/proc/self/stat第14字段(utime)是用户态jiffies,第15字段(stime)是内核态jiffies——这才是真正能拆开的来源。但要注意:jiffies不是纳秒,需换算;且该值只对当前进程有效,不含子进程。
- 读取路径:
/proc/self/stat,用空格分割后取第15个字段(索引从1开始计数) - 换算公式:
kernel_time_us = stime * (1000000 / sysconf(_SC_CLK_TCK)),其中sysconf(_SC_CLK_TCK)通常是100(即jiffy=10ms) - 注意字段可能被命令行参数中的空格干扰,必须用
sscanf按格式解析,不能简单strtok - 示例关键片段:
FILE* f = fopen("/proc/self/stat", "r"); if (f) { long utime, stime; fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %ld %ld", &utime, &stime); // 跳过前13个字段,读utime和stime fclose(f); }
Windows上没有等价的轻量级API,GetProcessTimes是唯一选择
Windows用GetProcessTimes返回的kernelTime字段就是内核态CPU时间(100纳秒为单位),但它返回的是FILETIME结构,需转成毫秒或微秒才方便使用。
- 返回值中
lpKernelTime是内核态时间,lpUserTime是用户态时间,两者相加≈clock_gettime(CLOCK_PROCESS_CPUTIME_ID)效果 - FILETIME是自1601-01-01以来的100纳秒计数,差值计算要用
ULARGE_INTEGER避免溢出 - 该API不支持跨线程聚合,只反映调用时刻主进程的累计值(不含已结束的子线程)
- 必须用
GetCurrentProcess()传入句柄,不能随便传INVALID_HANDLE_VALUE
别误用getrusage(RUSAGE_SELF, ...)的ru_stime
getrusage看似有ru_stime(system time),但它在多数Linux发行版中**并不精确反映内核态CPU时间**,而是基于/proc/[pid]/stat的近似值,且glibc内部做了缓存和四舍五入,实测误差可达几十毫秒甚至更多。
- 尤其在短生命周期进程或高频率调用场景下,
ru_stime.tv_usec可能始终为0 - 它比直接读
/proc/self/stat多一层封装,还引入了额外的系统调用开销 - 若你看到
ru_stime和/proc/self/stat第15字段差异明显,优先信后者
真要严格区分用户/内核态,/proc/self/stat是Linux上最可靠的数据源;但要注意jiffies精度低、换算易错,而且“内核态时间”本身受内核版本和调度策略影响,并非绝对稳定指标。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











