前言 本文为原创,可能会存在一些知识点或理解上的问题,欢迎切磋和交流 ^_^
在定位内核问题时,往往需要深入到代码层面进行分析。在使用ftrace之前,我往往采用的是最笨的方法,即在认为可能走到的函数接口里打点,重新编包,进行替换验证,看函数是否有走到打点的流程里,通过这种添加调试日志方法进行分析函数调用关系,效率不能太低!编译一把内核包所花费的时间是是可想而知的!
有一天,在网上搜一些内核调试工具,看到ftrace这么个东东,简单操作了一下,溜的很,于是有了这篇文章的由来。
通过查看内核文档documentation/trace/ftrace.txt,可以知道ftrace是做啥的,如下图所示(翻译水平有限,感受一下原汁原味的介绍吧)。
ftrace是Function Trace的简写,该工具能够深入到代码级别,对内核进行跟踪和分析。
ftrace工作在debugfs文件系统上,所以要使用ftrace,首先要进入到/sys/kernel/debug/tracing目录下进行参数配置,该目录内容的样子是长这样的。
其中,着重用到的几个文件如下(具体作用通过内核文档进行翻译过来)
当写入vfs_read函数到该文件时,再cat一下,则跟踪器只跟踪vfs_read函数,如下图所示。
可用的跟踪程序--available_tracers
可以使用如上命令查看该文件下支持的跟踪程序,一般用到的有如下三个(其他几个暂未用到)
我们使用ftrace工具跟踪vfs_read()函数,为方便调试起见,在执行open()前睡眠10s。
echo > $debugfs/tracing/set_ftrace_pid表示清空set_ftrace_pid
echo 1 > $debugfs/tracing/tracing_on表示启用ring缓冲区
echo `pidof read` > $debugfs/tracing/set_ftrace_pid 表示跟踪执行进程名称为read的进程号的进程
echo function_graph > $debugfs/tracing/current_tracer表示启用function_graph跟踪器
echo vfs_read > $debugfs/tracing/set_graph_function表示特别跟踪并显示vfs_read函数调用关系
echo 0 > $debugfs/tracing/tracing_on表示关闭ring缓冲区
cat ${debugfs}/tracing/trace > /root/DEMO/ftrace_example/vfs_read_ftrace.txt获取trace缓冲区内容并写到本地磁盘
===============================================================================
注意:
◆echo 1 > tracing_on,使能ring缓冲区打开,就会使得缓冲区打印大量无用函数调用,之前在用的时候,总是无缘无故打印几w行函数,查看起来很臃肿,后来再加入延时后,发现可以降低跟踪的函数行数。所以应该先关闭使能ring缓冲区,当设置好配置选项后,延时一段时间,再打开。
◆脚本类似如下:
◆脚本操作步骤:
(1)echo 0 > tracing_on 关闭使能ring缓存区
(2)echo nop > current_trace 清除跟踪器信息
(3)echo function_graph > current_trace 打开跟踪器
(4)echo function > set_graph_function 设置跟踪函数
(5)dd if=/dev/zero of=image ./bin 执行程序
(6)sleep xS 间隔一段时间
(7)echo 1 > tracing_on 打开使能ring缓冲区
===============================================================================
最后生成vfs_read_ftrace.txt文件,打开文件如下图所示
通过分析该文件,即可清晰知道vfs_read函数执行流程,每一个函数执行所花费时间。
但是,但是,但是,还没有完!(重要的事情说三遍)
该文件一共28927行!这么长个文件,该如何进行分析,是个问题!
通过vim进行配置,编写vim配置文件.fungraph-vim,具体内容如下图
===============================================================================
特别说明:该vim配置文件和方法引用自宋宝华老师文章:《关于Ftrace的一个完整案例》
===============================================================================
执行命令如下:
vim -S ~/.fungraph-vim vfs_read_ftrace.txt
即可将该文件进行折叠,通过空格键即可输出每个折叠的函数,方便查看和分析
左侧DURATION一栏用于显示函数执行占用的时间,关系图如下图所示。
如果有函数延时较大,会有相应特殊符号表示,如下表表示。
特殊符号 |
表示延时时间 |
‘$’ |
greater than 1 second |
‘@’ |
greater than 100 milisecond |
‘*’ |
greater than 10 milisecond |
‘#’ |
greater than 1000 microsecond |
‘!’ |
greater than 100 microsecond |
‘+’ |
greater than 10 microsecond |
‘ ’ |
less than or equal to 10 microsecond |
简单说,trace-cmd是用于操作ftrace的命令行工具,帮助信息如下图所示(不一一翻译)。
应用demo还是上述read文件,通过trace-cmd工具调试获取vfs_read()函数调用关系。执行程序截图如下所示。
其中命令为:trace-cmd record -p function_graph -g vfs_read -P 13947
通过帮助信息,可以知道其中每个选项作用。命令执行完后,按ctrl+C终止该命令,生成trace.dat文件。
通过trace-cmd report命令输出跟踪到本地磁盘文件,即可获取跟踪调用函数关系。
4.1.跟踪器function_graph在低内核版本(比如3.10.0内核版本)中设置不了,导致系统重启
通过对比不同内核版本,trace配置并无差别,且ftrace中available_tracers支持function_graph跟踪器。
该疑问目前仍不清楚,如有知道的朋友,可随时沟通和交流。
4.2.有同事在使用ftrace跟踪函数调用关系过程中,说trace文件非常大,不方便定位想要看的那个函数调用关系
trace跟踪文件非常之大,是因为没有设置跟踪条件以及添加时延,导致跟踪所有的函数并且打印出来。该问题解决需要设置跟踪条件,针对某一具体函数执行流程进行trace,并且在设置配置后,使能ring缓冲区。
4.3.有同事在使用ftrace工具跟踪内核ko过程中,不知道做了什么操作,导致cat trace没有输出
出现该问题推测是因为设置的ftrace跟踪器配置未清除干净,而加载调试的内核ko由于使用未卸载,所以再次cat trace时没有任何输出,解决该问题比较暴力的方法是重启系统,或者先卸载掉内核ko,重置trace跟踪器条件。
https://linux.cn/article-9273-1.html
https://linux.cn/article-9838-1.html
https://www.ibm.com/developerworks/cn/linux/l-cn-ftrace/index.html
http://www.voidcn.com/article/p-movbzbwr-ym.html