内核调测技术之Ftrace(上)

科技布道师 2024-03-14 20:47:12
前言:此前介绍了Tracepoint、bpftrace,而今天我们再介绍另外一项技术——Ftrace。本篇内容将围绕ftrace的发展历程、基本原理、特点以及相关功能的演示等内容,带大家全面的了解ftrace。Linux Tracing System从Linux系统的跟踪功能看,主要分为三个层级,即数据源、tracing内核框架以及前端工具/库 ,他们各自的功能为:数据源:提供数据来源Tracing 内核框架:负责对接数据源,采集解析发送数据,并对用户态提供接口前端工具/库:对接 Tracing 内核框架,直接与用户交互,负责采集配置和数据分析

ftrace作为为内核函数挂钩子的一个设施,可以用它来挂静态钩子,也可以挂动态钩子,接下来我们更具体的介绍一下Ftrace。Ftrace介绍Ftrace是一个针对Linux内核的跟踪框架。它最初的名字是Function Tracer,来自于ftrace记录内核运行时执行的各种函数调用相关信息的能力,这是因为它最开始主要是为了跟踪与采集内核运行时,函数的调用与执行情况。但经过不断发展,ftrace逐渐提供了更多的各类跟踪功能。像是通过各种跟踪插件,ftrace可以针对不同的静态跟踪点,例如调度事件、中断、内存映射I/O、CPU电源状态转换,以及与文件系统和虚拟化相关的操作。此外,还可以动态跟踪内核函数调用并通过使用globs将其限制在函数子集内,以及生成调用图并提供堆栈使用报告。同时,ftrace可以用来测量Linux内核中的各种延迟,比如禁用中断或抢占的时间。Ftrace发展史ftrace是Steven Rostedt在1998年做硕士论文时开发的。Steven Rostedt是一位资深的Linux内核开发者,拥有丰富的操作系统和实时系统方面的经验。他当时创建了一个"Logdev"机制,能比printk()更快的把输出信息放到ring buffer里。他当时在调査网络服务质量(QoS)的行为,printk()对他来说太慢了。后来他在Timesys工作之后,需要能更快地从公司的实时内核里面提取出信息,因此他就把logdev加到平台上了。第一版的logdev是在2.0内核上开发的,后来移植到2.2,2.4等新的kernel上。由于他开发ftrace的时候都是利用logdev来调试的。因而logdev就成为了ftrace的两个来源之一。另一个来源是实时补丁(realtime patch set)中带有的latency tracer。这是2004年Ingo Molnar和Nadia Chambers创建的。latency tracer利用了GCC的profiling功能,会在每个函数的最开头调用mcount(),这样就可以用来跟踪kernel的执行流程了。latency tracer不是动态的,因为function tracing不能在运行时进行控制,只能在编译时决定是否加入。2008年的时候,Rostedt在Red Hat的realtime团队工作,当时这个团队做了很多工作希望能把realtime patch推到kernel mainline上去。Arnaldo Carvalho de Melo试过把latency tracer移植到upstream kernel,不过这个tracer确实太复杂了,它会调用trace(),其中会调用_trace(),然后一直这样调下去,直到有5个下划线的_____trace0,蔚为奇观。Rostedt对这部分代码很熟悉,所以进行了清理,并且利用上了logdev,最终成型为ftrace。

Ftrace原理ftrace的名字由function trace而来,function trace是利用gcc编译器在编译时在每个函数的入口地址放置一个probe点,这个probe点会调用一个probe函数(gcc默认调用名为mcount的函数),这样这个 probe函数会对每个执行的内核函数进行跟踪(其实有少数几个内核函数不会被跟踪),并打印log到一个内核中的环形缓存(ring buffer)中,而用户可以通过debugfs来访问这个环形缓存中的内容。各类tracer往ftrace主框架注册,不同的trace则在不同的probe点把信息通过probe函数给送到ring buffer中,再由暴露在用户态debufs实现相关控制。其主要的框架图如下图所示:

其主要由两部分构成:1. ftrace Framework core: 其主要包括利用debugfs 系统在/debugfs下建立tracing 目录,对用户空间输出trace信息,并提供了一系列的控制文件2. 一系列的 tracer:每个tracer完成不同的功能,ftrace的trace信息保存在ring buffer(内存缓冲区)中,它们统一由framework管理对于ftrace有两种主要的跟踪机制往缓冲区写数据动态探针:可以动态跟踪内核函数的调用栈,包括function tracer,function graph trace两个tracer。其原理是利用mcount机制,在内核编译时,在每个函数入口保留数个字节,然后在使用ftrace时,将保留的字节替换为需要的指令,比如跳转到需要的执行探测操作的代码。静态探针:是在内核代码中调用ftrace提供的相应接口实现,称之为静态是因为,是在内核代码中写死的,静态编译到内核代码中的,在内核编译后,就不能再动态修改。在开启ftrace相关的内核配置选项后,内核中已经在一些关键的地方设置了静态探测点,需要使用时,即可查看到相应的信息。

总结一下,Ftrace可以提供以下能力:

内核函数挂钩子的基础设施。(对内核的绝大部分函数有效,挂钩子函数)基于tracefs文件系统的trace框架。(通过tracefs操作的命令做成shell脚本,来实现自动化)基于event机制跟踪内核活动。(实现对日志过滤等功能,便于抓取有效日志等)

同时在Linux内核中与其他追踪工具一起完成内核的追踪,了解内核内部发生的情况,比如函数执行。在此基础上调试或分析内核产生的延迟和性能问题,最终以此为基础形成性能分析报告。

那么接下来我们则分享部分Ftrace功能的实际演示案例,将按照以下四个层面进行分享:1、Ftrace的使用,通过tracefs或者前端工具的操作2、Ftrace的hook机制,如何为内核添加动态钩子和静态钩子3、Ftrace的日志缓冲区,如何将自己的日志写入到trace缓冲区

4、Ftrace的event机制,如何更加轻松的调试内核

使用前配置挂载tracefs(包含所有与内核的ftrace交互的文件节点,位于 /sys/kernel/debug/tracing 下)mount -t tracefs nodev /sys/kernel/tracing # 挂载tracefsls -l /sys/kernel/tracing # 查看挂载点内核配置项(至少添加内核配置,一般操作系统默认配置会开启这些选项)CONFIG_FUNCTION_TRACERCONFIG_FUNCTION_GRAPH_TRACERCONFIG_STACK_TRACERCONFIG_DYNAMIC_FTRACE演示环境qemu.x86.linux-5.12-rc3 平台

制作shell脚本进行ftrace演示

tracefs文件系统

可trace函数

演示1:观察指定函数被执行这里使用ftrace系统中的function tracer功能,该功能会匹配内核中的可trace函数,然后结合set_ftrace_filter选项使用,查看指定的函数的执行情况。步骤说明 :

进入tracefs目录 '/sys/kernel/debug/tracing'

通过读取'available_filter_functions' 文件,查看可trace函数列表

脚本中的操作步骤:关闭系统trace输出,清空系统trace buffer,将函数 blk_update_request加入过滤列表,开启function tracer功能,打开系统trace输出,进行测试(trace日志会自动写入trace buffer)和转存日志文件,最后移除前面的设置。

日志内容

演示2:观察指定模块执行流对ext4模块中所有函数的调用进行跟踪,查看模块的执行情况。

步骤说明

进入tracefs目录 '/sys/kernel/debug/tracing'

脚本中的操作步骤:关闭系统trace输出,清空系统trace buffer,将模块加入过滤列表,开启function tracer功能,打开系统trace输出,进行测试(trace 日志会自动写入 trace buffer)和转存日志文件,最后移除前面的设置。

日志内容

演示3:观察指定函数栈回溯通过func_stack_trace查看指定函数执行时的调用栈。

步骤说明

进入tracefs目录 '/sys/kernel/debug/tracing'

通过读取 'available_filter_functions' 文件,查看可trace函数列表

脚本中的操作步骤:关闭系统trace输出,清空系统trace buffer,将模块加入过滤列表,使能func_stack_trace选项,开启function tracer功能,打开系统trace输出,进行测试(trace日志会自动写入trace buffer)和转存日志文件,最后移除前面的设置。

日志内容演示4:观察指定函数间执行流这里主要对ftrace的set_ftrace_filter进行设置,当执行到函数bio_add_page时打开 ftrace对trace buffer写入,执行到函数blk_update_request时记录函数的栈回溯,随后关闭ftrace对trace buffer的写入。完成ftrace对内核从函数bio_add_page开始执行到函数blk_update_request执行结束的中间过程,记录相关信息。

步骤说明进入tracefs目录 '/sys/kernel/debug/tracing'通过读取'available_filter_functions'文件,查看可trace函数列表脚本中的操作步骤:关闭系统trace输出,清空系统trace buffer,将模块加入过滤列表并配置功能,开启function tracer功能,打开系统trace输出,进行测试(trace日志会自动写入trace buffer)和转存日志文件,最后移除前面的设置。日志内容

以上为本篇内容,更多演示内容会在下篇内容进行介绍。欢迎感兴趣的朋友留言交流。————————————————————————————————————本文部分内容源引CSDN博主原创文章原文链接:https://blog.csdn.net/u012489236/article/details/119427091原文链接:https://blog.csdn.net/qq_38505858/article/details/125560945
2 阅读:42

科技布道师

简介:感谢大家的关注