利用 perf 与 ftrace 精准定位项目卡顿问题 —— 从现象到本质的分析思路

📖 推荐阅读:《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 层出现 pollreadmutex_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_zone
  • ftrace 显示 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


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值