在 Linux 环境下进行调试时,基于内核原生支持的追踪技术是一种最为稳妥的选择。追踪技术本身是目的,为实现这一目的,衍生出了多种方法与工具。下文将以 ftrace 为例进行简要讨论,不对 kprobe、uprobe 和 eBPF 等展开阐述,因笔者对后者研究尚不够深入。追踪技术可分为动态与静态两类。所谓动态追踪,指的是无需在代码中人为插入辅助函数(即探针),而是通过挂载 debugfs 获取相关信息。实现该机制的前提是,编译器在编译阶段已在函数入口和出口加入了锚点(mcount)。在不启用追踪功能时,这些锚点对程序的执行逻辑与性能无任何影响;启用后,则可能对系统性能带来一定开销。ftrace 动态追踪方式主要用于观察函数的调用关系及其运行时间,且其对性能的影响程度,取决于追踪函数的类型与数量。若需全面了解追踪技术的原理与体系,建议参考内核官方文档,其介绍比多数资料更为专业和严谨,链接如下:https://www.kernel.org/doc/html/latest/trace/index.html
以下示例展示了如何使用 ftrace 追踪函数调用关系与运行时间。此外,ftrace 还支持其他功能,例如追踪哪些接口占用中断时间较长等,功能相对完善,能够满足多数调试场景需求。mount -t debugfs none /sys/kernel/debugcd /sys/kernel/debug/tracingecho function_graph > current_tracerecho 待追踪的函数名 > set_ftrace_filterecho 1 > tracing_oncat trace_pipe`
使用上述功能的前提是,在内核编译时需通过 menconfig 启用相关配置选项,以将对应的追踪功能编译进内核。笔者曾尝试在某 MCU 上执行上述追踪过程。在未对追踪函数进行过滤的情况下,开启动态追踪后,CPU 占用率一度飙升至接近 100%,一度怀疑存在系统异常。后通过以下命令限定追踪范围:echo 待追踪的函数名 > set_ftrace_filter
即只追踪感兴趣的函数,系统才恢复到可用状态。但需注意,输出的运行时间仅可作为相对参考,真实的绝对执行时间应短于工具所测结果,因为追踪机制本身会引入额外性能开销。在此背景下,静态追踪技术的价值愈加凸显。所谓静态追踪,实质上是开发者在关注的关键代码路径中手动添加探针,依据需求在特定位置插入不同类型的探针,并基于 trace event 接口实现。具体的添加方式可参考内核提供的示例代码:`samples/trace_events/trace-events-sample.h`相较于动态追踪,ftrace 静态追踪的核心优势在于:能够输出自定义变量以辅助观测,且观测粒度可灵活控制。开发者可根据实际需要选择启用单个探针或批量启用,从而在最大限度上降低对系统性能的影响,实现精细化的追踪与观测。