clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) 获取的是用户态+内核态总CPU时间;/proc/self/stat 的第15字段stime提供纯内核态时间(需换算);getrusage(RUSAGE_SELF, ...) 的ru_stime更便携但精度仅微秒级。

用 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) 获取内核态+用户态总CPU时间
严格来说,POSIX 没有单独导出「仅内核态」的进程 CPU 时间的接口。但 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) 返回的是当前进程自启动以来在**用户态 + 内核态**累计消耗的 CPU 时间(即 `utime + stime`),精度通常为纳秒级,且是标准、可移植的做法。
常见错误是误用 CLOCK_MONOTONIC 或 CLOCK_REALTIME —— 它们返回的是墙上时钟,和 CPU 占用完全无关。
- 必须链接
-lrt(Linux)或确保系统支持 POSIX clocks(macOS 也支持该 clock ID) -
ts.tv_sec和ts.tv_nsec需组合为 double 秒或 uint64_t 纳秒值,避免截断 - 该值是进程维度的,不包含子进程(除非调用了
wait()且启用了WCONTINUED等选项)
从 /proc/self/stat 解析 stime 字段获取纯内核态时间
Linux 下唯一能分离出「纯内核态 CPU 时间」的方式,是读取 /proc/self/stat 并解析第 15 个字段(stime),它表示进程在内核态消耗的**时钟滴答数(jiffies)**,需换算为秒。
注意:stime 不含子进程、不更新实时(内核只在调度点更新)、且依赖 sysconf(_SC_CLK_TCK) 获取 jiffy 频率(通常是 100 Hz,但可能被编译配置修改)。
立即学习“C++免费学习笔记(深入)”;
- 读取路径必须是
/proc/self/stat(不是/proc/<pid>/stat),避免竞态 - 字段顺序固定但易错:前 14 个字段含空格/括号,建议用
std::stringstream或strtol跳过前 13 个,再取第 14 个索引(0-based) - 示例片段:
long stime;<br>std::ifstream f("/proc/self/stat");<br>for (int i = 0; i < 14; ++i) f >> std::skipws >> (i == 13 ? stime : std::string());
getrusage(RUSAGE_SELF, ...) 的 ru_stime 字段更便携但精度低
getrusage(RUSAGE_SELF, &ru) 的 ru.ru_stime 成员直接给出内核态时间(struct timeval),语义清晰、无需解析文本,且跨 Unix 系统(Linux/macOS/BSD)都支持。
缺点是精度只有微秒级(tv_usec),且某些旧系统或容器环境可能因 cgroup 限制导致值滞后或归零。
- 务必检查返回值:失败时
ru_stime值未定义 - 该值同样不含子进程;若要含子进程,改用
RUSAGE_CHILDREN - 注意:macOS 上
ru_stime是近似值,实际基于采样,非精确累加
为什么没有标准的「纯内核态高精度 API」?
因为内核并不持续维护一个独立、高精度、用户态可原子读取的「仅内核态」计数器。所有现有接口(/proc、getrusage、clock_gettime)底层都依赖调度器在上下文切换时更新的统计字段,而这些字段本身是合并更新或周期性刷新的。
如果你需要区分某段代码引发的内核开销(比如系统调用密集型逻辑),唯一可靠方式是:在前后两次调用 getrusage(RUSAGE_SELF, ...),取 ru_stime 差值 —— 这比解析 /proc/self/stat 更轻量,也比 clock_gettime 更贴近「纯内核态」语义。
别指望单次调用就拿到绝对精确的内核态时间;差值测量才是实际工程中真正可用的模式。


















