5、 Kernel Trace分析:Ftrace原理、Tracepoint的使用、自定义Trace事件

📅 发布时间:2026/9/7 19:59:13
5、 Kernel Trace分析:Ftrace原理、Tracepoint的使用、自定义Trace事件
5.1 Ftrace是什么Ftrace是Linux内核内置的跟踪器。它几乎不占用额外资源就能记录内核函数的调用过程。说白了它就像内核里的黑匣子记录着每一行代码的执行轨迹。它的核心优势有三个零开销不启用时对性能没有任何影响内核原生不需要打补丁不需要额外安装细粒度可以跟踪到单个函数、单个事件核心概念Ftrace基于静态插桩和动态插桩两种机制。静态插桩是在编译时埋好的钩子动态插桩则利用gcc的-mrecord-mcount选项在运行时动态修改指令。5.2 Ftrace的工作原理Ftrace的工作原理其实不复杂。它利用了GCC编译器的特性——每个函数入口处都会插入一个mcount调用。正常情况下这个调用是NOP指令什么都不做。但当你启用Ftrace时内核会把这些NOP指令替换成真正的跟踪指令。我画了一张图帮你理解这个过程你看整个链路其实很清晰。用户通过debugfs接口下发指令Ftrace核心把数据写入ring buffer内核函数执行时触发回调最后你把数据读出来分析。5.3 Tracepoint的使用Tracepoint是Ftrace的精华所在。它不像function tracer那样记录每个函数调用而是只在你关心的特定位置打点。这就像在马拉松赛道上只放几个计时点而不是全程录像——效率高得多。我个人习惯把Tracepoint分成三类类别示例用途调度类sched_switch, sched_wakeup分析CPU调度延迟、线程切换中断类irq_handler_entry, irq_handler_exit排查中断频繁唤醒问题电源类cpu_frequency, suspend_resume分析CPU调频、休眠流程举个例子排查待机功耗问题时常用的就是sched_switch和irq_handler_entry。命令很简单# 启用调度事件跟踪 echo 0 /sys/kernel/tracing/tracing_on echo /sys/kernel/tracing/trace echo sched_switch /sys/kernel/tracing/set_event echo irq_handler_entry /sys/kernel/tracing/set_event echo 1 /sys/kernel/tracing/tracing_on # 等待一段时间后关闭 sleep 10 echo 0 /sys/kernel/tracing/tracing_on # 查看结果 cat /sys/kernel/tracing/trace | head -100小技巧我习惯先清空trace文件再开始跟踪避免历史数据干扰。另外set_event支持通配符比如echo sched:* set_event可以启用所有调度类事件。5.6 自定义Trace事件有时候内核自带的Tracepoint不够用。比如你在调试一个自定义驱动想知道某个函数被调用了多少次、每次的参数是什么。这时候就需要自定义Trace事件。实现方式有两种使用trace_printk()最简单像printk一样用但输出到trace文件注册自定义Tracepoint更正式性能更好适合生产环境先看trace_printk的用法。我在项目中经常用它做快速验证// 在驱动代码中插入 #include linux/kernel.h void my_driver_func(int arg) { trace_printk(my_driver called with arg%d\n, arg); // ... 业务逻辑 }然后通过Ftrace查看echo function /sys/kernel/tracing/current_tracer echo my_driver_func /sys/kernel/tracing/set_ftrace_filter echo 1 /sys/kernel/tracing/tracing_on # 触发你的驱动操作 cat /sys/kernel/tracing/trace但trace_printk有个坑——它走的是function tracer路径如果函数调用频繁会产生大量数据。我曾经在一个高频中断处理函数里用了trace_printk结果ring buffer瞬间被撑爆系统都卡住了。嗯血的教训。注意trace_printk不适合高频调用场景。如果需要在生产环境长期使用一定要注册正式的Tracepoint。另外记得在产品发布前移除所有trace_printk调用。注册正式Tracepoint的步骤稍微复杂一些但更规范// 1. 在头文件中定义 #include linux/tracepoint.h DECLARE_TRACE(my_driver_event, TP_PROTO(int arg1, const char *arg2), TP_ARGS(arg1, arg2)); // 2. 在源文件中实现 DEFINE_TRACE(my_driver_event); // 3. 在需要的地方触发 void my_driver_func(int val) { trace_my_driver_event(val, hello); // ... }注册完成后你就可以像使用内核自带Tracepoint一样使用它了echo my_driver_event /sys/kernel/tracing/set_event1.5 实战经验总结最后分享几个我在项目中积累的经验先规划再动手别上来就开所有trace数据量会让你崩溃。先想清楚你要查什么问题只开相关的事件。善用trace-cmd命令行工具trace-cmd比直接操作debugfs方便得多支持录制、回放、过滤。注意ring buffer大小默认的ring buffer可能不够用特别是跟踪高频事件时。可以通过buffer_size_kb调整。结合其他工具Ftrace最好和systrace、perf等工具配合使用各有所长。我曾经遇到一个WiFi断流的bug用systrace只能看到表象用Ftrace才追到了驱动层的一个锁竞争问题。所以说工具链要全面但Ftrace绝对是你的核心武器。一句话总结Ftrace是内核级功耗分析的基石。掌握它你就能看到系统最底层的行为。别怕命令行多用几次就熟了。