8

Dynamic function tracing events

 3 years ago
source link: https://kernel.taobao.org/2018/09/Dynamic-function-tracing-events/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Sep 6, 2018

Dynamic function tracing events

原文链接

从内核引入tracepoint开始,开发者们就对这些tracepoint是否为内核ABI的一部分而发生过争执。过去由于破坏了已有存在依赖的用户态程序,tracepoint相关变更被回退过。同时,对内部代码无法改变的恐慌使得在多个内核子系统中新增tracepoint变得困难。如今,一个新的tracing功能被提了出来以避开这些问题。

tracepoint是否作为内核ABI的一部分并非是无关紧要的问题。内核ABI承诺运行应用程序不会因内核更新而遭到破坏。很明确这个承诺在过去就已扩展覆盖到tracepoint。尤其是2011年当一个tracepoint变更因破坏了powertop而不得不被回退。一些内核维护者禁止或严格控制其维护的子系统中新增tracepoint,就是担心类似的事情会同样发生在自己身上。其结果导致内核缺乏用户认为有用的tracepoint。

这个主题在多个会议上作为议程讨论过,包括2017年维护者峰会。正是那时提出一个更聪明的想法:与其将tracepoint放置到敏感位置,不如由开发者简单地做好标记,而这些标记可以在运行时显示地连接并转化成tracepoint。通过跳出束缚 (jump through some hoops) 以此期望保证这个新机制将不会创建任何新的ABI。接下来几个月一切归于平静。

但最近tracing的维护者Steve Rostedt面临该提案的一个变化,他称之为“动态创建基于函数的事件 (dynamically created function-based events) ”。细节上发生了一些变化,但ABI规避本质上保持一致。关键细节差异来源于其观察到内核已经在特定位置上有了tracing代码可以利用的一种类型的标记。内核代码通常带有正常用于代码分析的参数编译。结果,每个函数都以调用mcount() (或新编译器使用的__fentry()__ ) 开始。当分析用户态程序时,mcount()追踪每个函数的调用并因此很耗时。尽管内核使用支持诸如function tracing的特性版本来替换mcount()。但大多时候都是直接整体打上mcount()调用,只是可以在运行时需要tracing特定函数调用时启用。

也存在其他可能使用函数入口钩子的场景。Rostedt的补丁可在运行时任何内核函数的开始处启用创建tracepoint。在tracefs控制文件系统挂载的前提下,一个新tracepoint可通过如下命令创建:

echo 'SyS_openat(int dfd, string path, x32 flags, x16 mode)' \
	> /sys/kernel/tracing/function_events

SyS_openat()是openat()系统调用的内核实现,该命令请求在SyS_openat()入口处创建一个tracepoint。4个值将从tracepoint报告出来:目录文件描述符 (dfd),给定路径名(path),以及标记和模式参数。这个tracepoint将在events/functions下显示出来,跟内核中其他tracepoint看上去一样。也可以像平常那样被查询,启用和关闭。有趣地是,这个例子中的路径指向用户空间,但tracing系统能恰当地获取并打印出相应数据。

很明显还存在进一步的工作要做:“我需要重写function graph tracer,并且能在函数返回时增加动态事件”。其核心部分看上去已经有了且能正常工作。但这里遗留了一个重要问题:这是否已经足够确保避免创建一个新ABI的内核接口集?Mathieu Desnoyers担心仍然不够。

让这些工具在函数名/参数上挂个钩子无法解决该问题。一旦内核代码变更,广泛使用的trace分析工具将开始变得不正常。而此时,其内部函数签名将会成为ABI。

Linus Torvalds却不同意该担心。内核钩子需要的额外步骤隐含了不同状态视角:

每个人*理解*这像一个调试工具:如果你有一个gdb脚本显示某些信息,接着你到处修改源代码,*明显*你同样需要回过头来修改调试脚本。你并没有没有保持源代码不变来使gdb脚本无需变更,这看上去很傻。 相反,显示的tracepoint使人们相信它们有着长远的意义。

如果现实与该观点一致,那么新的动态tracepoint机制将在缓解ABI问题有很大帮助。大量内核新增的tracepoint将很可能被丢弃,因为开发者将简单地使用动态变种来替代。将来增加tracepoint时,相对可能的是这些tracepoint将被设计成支持某些系统管理工具,并且在外部看上去是ABI的一部分。

当然那是假定这个系列补丁最终会被合入。Alexei Starovoitov对此有些不同意见,他抱怨新接口在kprobe现有的基础上增加很少。同时他也不喜欢面向文本的接口,建议使用BPF来替代以提取内核数据的某些特定信息。但Rostedt指出,许多开发者因BPF上手复杂性而退却,而更偏向简单的。

Rostedt认为该接口将很有用,但如果其他人存在不同意见的话他将不再继续开发:“如果其他人认为这将有用,那么我想让他们现在大声地说出来”。然而迄今为止,几乎没有人明确表达出来。如果动态函数tracing机制的确是其他开发者想要的,他们需要显示发声以表示支持。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK