9.12 进阶阅读与技术地图
本章的内容到此结束,但你的探索才刚刚开始。
在这一节里,我整理了一份「进阶阅读地图」。这不仅仅是把书里的链接罗列出来,而是要把它们放在你的认知地图里——告诉你哪些资源是地图,哪些是矿藏,哪些是当你遇到特定怪兽时需要拔出的专用武器。
把这些资源当作你随身工具箱的扩展说明。
🗺️ 宏观视野:理解 Tracing 的全景
在深入具体的命令之前,先从高处看看这片森林。以下几篇文章适合用来建立整体认知,特别是当你搞不清楚 ftrace、perf、eBPF 和 LTTng 之间到底是什么关系时。
-
Unified Tracing Platform – Bringing tracing together
- Steven Rostedt (VMware), 2019
- https://static.sched.com/hosted_files/osseu19/5f/unified-tracing-platform-oss-eu-2019.pdf
- 为什么读它:Ftrace 的主要维护者亲自画蓝图。如果你想了解这些工具未来如何统一到一个架构下,这是第一手资料。
-
Unifying kernel tracing
- Jack Edge, LWN, Oct 2019
- https://lwn.net/Articles/803347/
- 为什么读它:LWN 的深度一如既往。这篇主要讲如何把 tracefs、perf 和 eBPF 这三座大山连起来。
-
Linux tracing systems & how they fit together
- Julia Evans (@b0rk), July 2017
- https://jvns.ca/blog/2017/07/05/linux-tracing-systems/
- 为什么读它:Julia 的图解能力是一流的。如果你觉得文字描述太抽象,看看她怎么用图表把 Ftrace、Uprobes、SystemTap 等拼在一起。
-
Using the Linux Tracing Infrastructure
- Jan Altenberg (Linutronix GmbH), Nov 2017
- https://events.static.linuxfound.org/sites/events/files/slides/praesentation_0.pdf
- 为什么读它:实战导向的幻灯片,包含了不少实际操作中的截图和参数组合。
-
The comprehensive kernel index – all articles on tracing on LWN
- https://lwn.net/Kernel/Index/#Tracing
- 为什么收藏它:LWN 是内核开发者的新闻圣经。这个索引页是所有 Tracing 相关文章的总入口。
⚙️ Ftrace:深入内核的开关
如果你想挖掘 Ftrace 的潜力,或者只是想确认 set_ftrace_pid 到底怎么用,以下是核心资料。
官方文档与必读经典
-
Official kernel documentation – ftrace
- https://www.kernel.org/doc/html/v5.10/trace/ftrace.html
- 定位:案头手册。详细到你可能不想一次性读完,但遇到问题时必须查。
-
Ftrace: The hidden light switch
- Brendan Gregg, Aug 2014
- https://lwn.net/Articles/608497/
- 定位:概念引入。如果你对「为什么 Ftrace 开销这么小」感兴趣,这篇必看。
-
Ftrace internals
- Brendan Gregg, Oct 2019
- https://www.brendangregg.com/blog/2019-10-15/kernelrecipes-kernel-ftrace-internals.html
- 定位:硬核内核机制。讲述了
mcount、蹦床和动态插桩的底层黑魔法。
老而弥坚的系列文章 虽然年代久远,但 Steven Rostedt(Ftrace 之父)的这三篇文章依然是理解设计逻辑的佳作:
-
Debugging the kernel using Ftrace - part 1 & 2
-
Secrets of the Ftrace function tracer
- LWN, Jan 2010
- https://lwn.net/Articles/370423/
新手入门与速查表
-
Welcome to ftrace & the Start of Your Journey...
- Steven Rostedt, Nov 2019
- https://blogs.vmware.com/opensource/2019/11/12/ftrace-linux-kernel/
-
ftrace: trace your kernel functions!
- Julia Evans, Mar 2017
- https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/
- 定位:如果你只想看一个教程快速上手,看 Julia 的这篇就够了。
-
Ftrace cheat sheets
- 常用命令速查:Linux-tipps Cheat Sheet
- 通用 Kernel Tracing 速查:lzone.de
- 建议:把这几个页面打印出来贴在显示器旁边,直到你把常用的
echo命令烂熟于心。
内核栈深度专题
本章我们提到了栈溢出的风险。如果你想深入了解内核栈的机制(特别是 CONFIG_VMAP_STACK),这两篇 LWN 文章是必读的:
- Virtually mapped kernel stacks
- Jon Corbet, June 2016
- https://lwn.net/Articles/692208/
- Virtually mapped stacks 2: thread_info strikes back
- Jon Corbet, June 2016
- https://lwn.net/Articles/692953/
🛠️ 工具链:trace-cmd 与 KernelShark
虽然我们演示了直接操作 tracefs,但在实际工作中,你更需要这些前端工具。
trace-cmd (命令行前端)
-
trace-cmd: A front-end for Ftrace
- Steven Rostedt, LWN, Oct 2010
- https://lwn.net/Articles/410200/
-
Kernel tracing with trace-cmd
- G Kamathe (RedHat), July 2021
- https://opensource.com/article/21/7/linux-kernel-trace-cmd
- 实战价值:包含具体的
trace-cmd record和report示例。
KernelShark (图形化神器)
- Official KernelShark Documentation
- Swimming with the New KernelShark
- Yordan Karadzhov (VMware), 2018
- 提示:KernelShark v2 有了巨大的架构重写(基于 Qt),这篇 PPT 能带你快速了解新特性。
📦 perf-tools:Brendan Gregg 的脚本百宝箱
不要被名字迷惑,perf-tools 实际上是大量基于 Ftrace 和 tracefs 的 Bash 脚本封装。在 eBPF 还没普及的年代,它们是主力军,现在依然因为「无需编译、直接运行」而极具价值。
-
GitHub Repository
-
Examples Directory
- https://github.com/brendangregg/perf-tools/tree/master/examples
- 建议:直接去读这些脚本的源码——它们就是最好的 Ftrace 使用教程。你可以看到作者是如何组装简单的
echo命令来实现复杂功能的。
-
Linux Performance Analysis: New Tools and Old Secrets
🚀 eBPF 的延伸
我们在第 4 章讨论过 Kprobes 和 Instrumentation。eBPF 已经彻底改变了内核跟踪的格局。 虽然本章重点在 Ftrace,但你必须知道它们的关系:Ftrace 是底层的基石,eBPF 是在上层构建的高级大厦。
- eBPF and frontends resources
- 参见 Chapter 4 (Debug via Instrumentation – Kprobes) 的 "Further reading" 部分。
📡 LTTng:高频数据的工业级方案
当 Ftrace 的开销在高频事件下成为瓶颈,或者你需要分析用户空间和内核空间的关联时,LTTng 是最佳选择。
-
LTTng Main Website & Quick start
-
Babeltrace 2 (CLI Tool)
- https://lttng.org/blog/2020/06/01/bt2-cli/
- 说明:LTTng 生成的 CTF (Common Trace Format) 数据是二进制的,
babeltrace2是用来把它转成人能读的文本的工具。
-
Finding the Root Cause of a Web Request Latency
- Julien Desfossez, Feb 2015
- https://lttng.org/blog/2015/02/04/web-request-latency-root-cause/
- 案例价值:展示了如何结合内核和用户空间跟踪来定位一个真实的业务问题。
-
Tutorial: Remotely tracing an embedded Linux system
- C Babeux, Mar 2016
- https://lttng.org/blog/2016/03/07/tutorial-remote-tracing/
- 适用场景:正如我们在本章结尾提到的,嵌入式板子资源有限。这篇教程教你在板子上采集,在主机上分析的正确姿势。
-
LTTng: A Comprehensive User's Guide (version 2.3)
- Daniel U. Thibault (DRDC Valcartier Research Centre)
- 说明:这是一本小书。如果你需要一本纸质书(或 PDF)放在案头从头读到尾,选这个。
Trace Compass (LTTng 的可视化前端)
- Trace Compass Website
- Alternate tracing tools
- https://lttng.org/docs/v2.13/#doc-lttng-alternatives
- 比较:这里列出了 LTTng 与其他工具(如 SystemTap, perf)的对比,帮你决定在什么时候用 LTTng。
🔧 杂项:特殊场景与技巧
最后,这里有几个在特定场景下能救命的资源:
-
Boot-time tracing via ftrace
- Documentation
- 痛点解决:如何跟踪内核启动早期的过程?那时候
/sys还没挂载呢。这篇文章教你通过内核参数 (ftrace=) 来解决这个问题。
-
Trace Linux System Calls with Least Impact on Performance
- PingCAP, Dec 2020
- https://en.engpic.com/blog/how-to-trace-linux-system-calls-in-production-with-minimal-impact-on-performance/
- 场景:在生产环境(Production)进行系统调用跟踪。这里讨论了如何在不拖垮业务的前提下获取数据。
把所有这些工具都装进你的工具箱里。在不同的场景下,针对不同的问题,选择最锋利的那把刀。
下一章,我们要面对一个更沉重的话题:Kernel Panic。别慌,有了今天的调试利器,哪怕是内核崩溃,我们也能从尸体里读出点东西来。
练习题
练习 1:understanding
题目:比较 Tracing(跟踪)和 Profiling(性能分析)的主要区别。如果内核开发者想要获取某个系统调用在内核内部完整的函数调用流程,应该使用哪种技术?为什么?
答案与解析
答案:应使用 Tracing。
区别:
- Tracing 是捕获性的,记录代码执行路径上的所有细节(函数调用、参数、时间戳等),提供完整的执行历史。
- Profiling 是统计性的,通过周期性采样来捕获事件,不捕获所有细节,主要用于发现性能热点。
原因:获取“完整的函数调用流程”需要记录代码执行的每一个步骤,而不是统计样本,因此必须使用 Tracing。
解析:这道题考察对核心概念的定义辨析。根据章节开头定义,Tracing 类似于“黑匣子”,记录所有细节;而 Profiling 旨在通过采样进行性能监控。Strace 是系统调用边界的 Tracing,而 Ftrace 则深入内核进行 Tracing。要查看内部流程,必须使用具有完整记录能力的 Tracing 技术。
练习 2:understanding
题目:在 Linux 内核配置中,CONFIG_DYNAMIC_FTRACE 选项的作用是什么?如果没有开启这个选项,直接使用 -pg 编译器选项进行插桩,会对生产环境的内核性能产生什么影响?
答案与解析
答案:作用:允许内核在运行时动态修改机器指令(将函数入口处的指令替换为 NOP 指令或跳转到 Trampoline),从而在不跟踪时实现零性能损耗。
影响:如果没有开启此选项,内核将保留编译器插入的 mcount 调用。每个函数调用的入口都会执行判断逻辑(类似 if tracing_enabled { ... }),这会带来巨大的 CPU 开销,不适合在生产环境开启。
解析:考察对 Ftrace 实现机制的理解。普通的编译器插桩(-pg)会永久性地在每个函数入口添加代码,导致性能下降。而动态 Ftrace 利用了内核的自我修改代码能力,在未开启跟踪时通过填空指令来维持原生性能。
练习 3:application
题目:假设你正在调试一个随机的内核崩溃,并且怀疑崩溃发生在一系列复杂的内核函数调用之后。你希望在崩溃发生时自动捕获 Ftrace 缓冲区中的数据,以便分析崩溃前的执行流。请给出具体的操作步骤或配置方法。
答案与解析
答案:可以通过以下方法之一实现:
-
内核参数启动配置:在内核启动参数中加入
ftrace_dump_on_oops。 例如:ftrace_dump_on_oops=1(在 Oops 时向控制台转储)或ftrace_dump_on_oops=2(转储更多原始缓冲区内容)。 -
运行时配置(Procfs):在系统运行时,通过 Proc 文件系统接口开启:
echo 1 > /proc/sys/kernel/ftrace_dump_on_oops
这样,一旦内核发生 Panic 或 Oops,Ftrace 会自动将 Ring Buffer 中的跟踪日志转储到控制台和日志中,供事后分析。
解析:考察实际调试场景的应用能力。知识点来自 ftrace_dump_on_oops。这是处理“事后分析”类问题的关键技巧,因为一旦内核崩溃,通常无法手动执行命令复制 trace 文件,必须依赖内核的自动转储机制。
练习 4:application
题目:你正在使用 function_graph 跟踪器分析一个延迟敏感的内核模块。为了过滤掉噪音,你只想跟踪与该模块相关的函数,并且只想观察执行时间超过 100 微秒的函数调用。请结合 set_ftrace_filter 和 Ftrace 的延迟标记特性,描述如何配置。
答案与解析
答案:配置步骤如下:
-
设置过滤器:将模块相关的函数名写入
set_ftrace_filter。echo 'mod:*' > /sys/kernel/tracing/set_ftrace_filter(注:mod:是一个过滤命令,用于匹配特定模块的所有函数,假设已知模块名,也可以直接使用通配符如my_module_*) -
启用延迟标记:虽然
function_graph本身会显示 Duration(持续时间),但 Ftrace 提供了延迟标记功能来直观地突显异常。 确保options/funcgraph-cpu和options/funcgraph-duration已开启(默认通常开启)。 在 Trace 输出中,持续时间列左侧出现的符号(如!)表示函数执行时间超过了特定的阈值(例如!通常代表超过 100us 或更高阈值,具体取决于内核配置)。 -
读取分析:
cat /sys/kernel/tracing/trace| grep '!'
或者,如果使用 perf-tools,可以直接使用 funcslower 脚本:
./funcslower 100 (这会直接显示超过 100us 的函数)。
解析:考察对 Ftrace 过滤功能和输出解读的综合应用。题目要求结合 set_ftrace_filter(缩小跟踪范围)和对延迟标记的理解(识别长耗时函数)。实际操作中,利用 mod: 过滤命令或通配符是常见的排查手段,而观察 Duration 列的符号(如 $, +, !)是快速定位性能瓶颈的关键。
练习 5:thinking
题目:在阅读 Ftrace 的 function_graph 输出时,你注意到某个特定的内核线程(PID 123)在日志中显示了函数调用的缩进和持续时间,但根据你的理解,该线程当时应该完全处于休眠状态。请分析可能产生这种“幽灵”跟踪数据的原因,并说明如何利用 Ftrace 的 latency-format 选项来验证你的推测。
答案与解析
答案:可能原因分析:
这种现象最可能的原因是中断上下文的干扰。虽然日志显示的是“PID 123 线程”上下文,但实际上记录的是硬件中断(Hard IRQ)或软中断在该线程被调度出去、或者是刚刚准备运行时切入到内核模式执行的处理函数。在 function_graph 默认输出下,中断处理函数的执行往往归入当前被中断进程的上下文中,容易造成误解。
验证方法:
- 启用
latency-format选项:echo 1 > /sys/kernel/tracing/options/latency-format - 再次查看 Trace 输出。该格式会增加一列详细信息,显示中断状态、抢占计数器和上下文标志。
- 分析标志:查看新增列中的标志位(如
dN表示中断深度,X表示存在 NMI 等)。如果看到中断标志位被置起,或者irqs-off相关的标记,就证明这些函数实际上是在中断上下文中执行的,而非 PID 123 线程主动发起的调用。
这揭示了 function_graph 默认视图的一个局限性:它倾向于将底层活动的“账”算在当前运行的任务头上。
解析:这是一道深度思考题,考察对内核执行上下文(进程上下文 vs 中断上下文)以及 Tracing 工具本身局限性的理解。单纯看 PID 可能会被误导,理解 latency-format 提供的底层硬件状态(如中断是否关闭、抢占是否禁用)是区分“进程主动行为”和“中断被动行为”的关键。
要点提炼
本章的核心在于如何利用 Linux 内核的跟踪技术揭开系统运行的“黑盒”。Ftrace 作为内核自带的跟踪引擎,通过 tracefs 文件系统提供了控制接口,利用编译器插桩技术(如将函数入口替换为 NOP 指令)实现了在不开启跟踪时对性能零损耗。理解 Tracing(跟踪) 与 Profiling(剖析) 的区别是选对工具的前提:前者关注连续的流程细节,记录每一次函数调用以回答“在某一时刻具体发生了什么”;后者关注统计热点,通过采样回答“时间都去哪儿了”。
要实现有效的内核观测,仅仅开启跟踪器是不够的,必须掌握上下文识别与高级过滤技巧。通过开启 latency-format 和 funcgraph-proc 等选项,用户可以解码出 d.h2 这种内核状态密码,从而区分代码是运行在进程上下文还是硬中断上下文,以及是否持有锁。同时,利用 set_ftrace_filter 配合 Glob 匹配或基于索引的过滤,能够将海量的函数调用日志精简到特定范围(如仅限 TCP 协议栈或特定驱动模块),这是在信息洪流中定位问题的关键。
在实际调试中,通过跟踪 Tracepoints(跟踪点) 比单纯跟踪函数调用能获取更多有价值的信息。Tracepoints 是内核开发者预先埋好的“钩子”,位于调度器、中断等关键路径上。使用 set_event 接口监听这些事件(如 net:* 或 skb:*),虽然可能牺牲了函数调用的层级缩进图,但能获取具体的函数参数值,这对于排查“参数错误导致丢包”等问题至关重要。
针对动态插入调试信息的需求,内核提供了 trace_printk() 这一轻量级 API,它优于传统的 printk。trace_printk 仅写入内存环形缓冲区,避免了控制台 I/O 带来的性能损耗和时序干扰,且不会因缓冲区溢出而丢失关键数据。结合 trace_pipe 实时流式输出,开发者可以在不中断系统运行的情况下,像观看直播一样监控内核行为,真正实现了对内核“显微镜”般的动态观测。