📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
利用 perf 与 ftrace 精准定位项目卡顿问题 —— 从现象到本质的分析思路
在嵌入式图形界面项目中,例如医疗监护仪、工业HMI、消费类终端等,我们常遇到一种模糊的反馈:“UI切换时卡了一下”、“点击没反应,要等一秒”。这些现象统称为 卡顿(Lagging),但卡顿只是表象,背后的原因可能千差万别。
本文将结合实际项目经验(如监护仪UI界面切换),详细讲解如何使用 perf 与 ftrace 两大工具,从内核层精准分析卡顿的本质,给出一套结构清晰、可复用、实战导向的分析流程。
一、什么是“卡顿”?它本质上是性能瓶颈的表现
“卡顿” ≠ “程序挂了”,而是响应时间异常变长。
常见表现:
- UI点击后迟钝(> 200ms)
- 页面切换过程中黑屏或空白停顿
- 动画播放掉帧、不流畅
这些现象通常是因为系统资源(CPU、内存、锁、调度等)在短时间内无法满足当前需求,导致执行延迟。
二、卡顿常见根因类型
| 类型 | 具体表现 | 可用工具分析 |
|---|---|---|
| CPU占用高 | top 显示 100% | perf top, perf record |
| Page Fault多 | malloc后首次访问大内存 | perf stat, ftrace |
| 锁竞争严重 | 多线程抢锁、长时间等待 | ftrace traceevents |
| 调度延迟 | 实时线程调度延迟 | sched_switch + ftrace |
| I/O阻塞 | read/write等待设备响应 | perf record, ftrace |
三、分析总流程:三步走(perf 定热点 → record 捕栈 → ftrace 解剖)
✅ Step 1:perf top 快速确认热点
sudo perf top -p $(pidof your_app)
用途:实时查看 CPU 最忙的函数。
典型场景:若看到 malloc / memset / do_anonymous_page,说明可能是 page fault 导致。
✅ Step 2:perf record 捕获卡顿时刻的函数调用栈
sudo perf record -g -p $(pidof your_app) -o perf.data
# 同时在前台执行 UI 操作,制造卡顿
sudo perf report
分析报告中查看耗时函数和调用路径。
典型表现:
- 大量时间消耗在
__alloc_pages_slowpath()→ 碎片整理compact_zone() - 或 syscall 层出现
poll、read、mutex_lock堆栈过深
✅ Step 3:ftrace 精确剖析函数耗时与调度阻塞

开启 function_graph 跟踪器
cd /sys/kernel/debug/tracing
echo function_graph > current_tracer
# 过滤只看 page fault 处理路径
echo do_anonymous_page > set_ftrace_filter
echo 1 > tracing_on
sleep 2 # 在此期间触发卡顿操作
echo 0 > tracing_on
cat trace
可以看到函数调用路径、每个函数耗时、内核是否被调度走等。
四、实战案例:监护仪 UI 页面切换卡顿
📌 场景:
- 用户点击菜单,切换 ECG → SPO2 页面
- UI卡顿 1 秒左右,图像区域显示延迟
📌 代码行为:
char *buf = malloc(1024 * 1024); // 分配图像缓存
memset(buf, 0, 1024 * 1024); // 初始化 → 引发 Page Fault
📌 问题分析过程:
perf stat显示 page-faults 每秒超 150 万次perf report显示大部分时间耗在do_anonymous_page → __alloc_pages_slowpath → compact_zoneftrace显示compact_zone()每次耗时约 200~300ms,累计导致明显卡顿
📌 原因总结:
- 每次切换 UI 页面时重新 malloc 图像缓冲区(1MB),首次访问触发大量缺页异常。
- 内存碎片过多,分配大块页帧困难,内核进入碎片整理路径。
五、优化建议与实效
✅ 方案一:复用静态图像缓存,避免频繁 malloc
static char *global_buf = NULL;
if (!global_buf)
global_buf = malloc(2 * 1024 * 1024);
memset(global_buf, 0, 1024 * 1024); // 清空后复用
✅ 方案二:提升系统低阶空闲页水位
echo 65536 > /proc/sys/vm/min_free_kbytes
解释:保留 64MB 空闲页,避免内核走 slowpath 分配 → 提升瞬时分配能力。
📈 优化效果:
- 卡顿时间从 1 秒 → 减至 200ms
- page fault 次数下降 70%
- ftrace 中不再频繁出现
compact_zone()
六、小结
perf 适合从宏观上定位 CPU 热点和函数栈,ftrace 则用于精细观察函数执行耗时、调度延迟、锁阻塞等。二者结合,是嵌入式/内核开发中排查“卡顿”类问题的黄金组合。
本案例中,卡顿的根因是 page fault 触发了碎片整理,perf 和 ftrace 让我们精确地看清问题路径,并验证优化效果,这是实践中极具价值的定位思路。
📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
678

被折叠的 条评论
为什么被折叠?



