Linux下如何排查两个检查点间运行的任务与进程耗时问题
void main() { //some code printf(" hi \n"); checkpoint1(); // <-------- checkpoint1 //some Code with no dependency on other program/task or HW IO checkpoint2(); // <-------- checkpoint2 printf(" test end \n"); //some code return; }
Linux下排查checkpoint1与checkpoint2间耗时过长的方案
一、系统工具类方案(适合手动/临时排查)
1. perf 性能分析工具
perf是Linux内核自带的性能分析框架,可精准捕获这段时间内的CPU调度与进程运行情况:
- 操作步骤:
- 程序运行到
checkpoint1时,在终端执行:perf record -a -e sched:sched_switch -g -- sleep <预估耗时>(若无法预估耗时,可在checkpoint2触发后立即按Ctrl+C停止perf) - 执行
perf script分析捕获的日志,可看到所有CPU上的进程切换事件,以及每个进程/线程的运行时间段,通过时间戳对比可计算出各进程在这段时间内的CPU占用时长。
- 程序运行到
- 补充:若需要更详细的CPU使用统计,可执行
perf stat -a -I 1000(每隔1秒输出一次全系统CPU使用统计),结合程序checkpoint1/checkpoint2的时间戳,定位对应时间段的高占用进程。
2. pidstat 进程统计工具
pidstat可周期性输出所有进程/线程的CPU、内存等资源使用情况,适合定位突发的CPU占用:
- 操作步骤:
- 程序启动前执行:
pidstat -u -t -d 1 > pidstat.log(每隔1秒输出一次进程/线程的CPU、IO统计,结果写入日志) - 程序运行完
checkpoint2后停止pidstat,根据日志中记录的时间戳,筛选checkpoint1到checkpoint2的时间段,查看各进程的%CPU列和UTIME/STIME列的变化,即可得到这段时间内各进程的CPU运行时长。
- 程序启动前执行:
3. ftrace 内核跟踪工具
ftrace是内核级别的跟踪框架,可精准捕获进程调度的细节:
- 操作步骤:
- 挂载tracefs:
mount -t tracefs nodev /sys/kernel/tracing - 启动跟踪:
echo sched_switch > /sys/kernel/tracing/set_event,echo 1 > /sys/kernel/tracing/tracing_on - 程序运行过
checkpoint2后,停止跟踪:echo 0 > /sys/kernel/tracing/tracing_on - 查看日志:
cat /sys/kernel/tracing/trace,日志中会记录每个CPU上的进程切换事件,包含进程PID、名称、切换时间,可通过这些数据计算各进程的运行时长。
- 挂载tracefs:
二、编程式API方案(适合集成到程序自动排查)
1. 读取/proc文件系统
/proc是内核暴露给用户态的虚拟文件系统,可直接读取进程与CPU的运行统计数据:
- 实现思路:
- 在
checkpoint1()中,遍历/proc目录下的所有PID文件夹,读取每个进程的/proc/<pid>/stat文件,提取第14、15个字段(utime:用户态运行时间,stime:内核态运行时间,单位为jiffies),同时读取/proc/stat中各CPU的总运行时间,保存为初始状态。 - 在
checkpoint2()中,重复上述读取操作,计算每个进程utime+stime的差值,以及CPU总时间的差值,即可得到这段时间内各进程占用CPU的时长占比与绝对时长。
- 在
- 注意:若需要跟踪线程,需遍历
/proc/<pid>/task/<tid>目录,读取每个线程的stat文件。
2. perf_event_open API
这是perf工具的底层内核API,可在程序中直接创建性能事件,捕获调度数据:
- 核心步骤:
- 使用
perf_event_open()函数打开PERF_TYPE_TRACEPOINT类型的事件,对应tracepoint:sched:sched_switch事件(事件ID可通过/sys/kernel/tracing/events/sched/sched_switch/id获取),设置PERF_FLAG_FD_CLOEXEC等标志。 - 在
checkpoint1()中启动事件采样(ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)),在checkpoint2()中停止采样(ioctl(fd, PERF_EVENT_IOC_DISABLE, 0))。 - 通过
read()函数读取捕获的事件数据,解析出进程切换的时间戳、进程PID/名称等信息,计算各进程的运行时长。
- 使用
- 代码示例片段:
#include <linux/perf_event.h> #include <sys/ioctl.h> #include <unistd.h> int perf_fd; void checkpoint1() { struct perf_event_attr attr = {0}; attr.type = PERF_TYPE_TRACEPOINT; attr.config = /* 替换为sched_switch的tracepoint ID */; attr.size = sizeof(attr); attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME; attr.sample_period = 1; attr.wakeup_events = 1; perf_fd = perf_event_open(&attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); ioctl(perf_fd, PERF_EVENT_IOC_ENABLE, 0); } void checkpoint2() { ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0); // 读取并解析perf_fd中的事件数据 char buf[4096]; ssize_t n = read(perf_fd, buf, sizeof(buf)); // 解析逻辑省略,需根据perf事件格式解析进程切换信息 close(perf_fd); }
内容的提问来源于stack exchange,提问作者Henry Leong
相关产品推荐
相关产品推荐

