Ftrace简介 Ftrace是Linux进行代码级实践分析最有效的工具之一,比如我们进行一个系统调用,出来的时间过长,我们想知道时间花哪里去了,利用Ftrace就可以追踪到一级级的时间分布。 Ftrace 的整体构架如下: ? Ftrace 有两大组成部分,一是 framework,另外就是一系列的 tracer 。 下面我们用Ftrace来跟踪test_proc_show()这个函数。 我们把启动ftrace的所有命令写到一个脚本function.sh里面: #! Ftrace结果怎么读? Ftrace结果怎么读?答案非常简单:如果是叶子函数,就直接在这个函数的前面显示它占用的时间,如果是非叶子,要等到 }的时候,再显示时间,如下图: ? vim对Ftrace进行折叠 上面那个Ftrace文件太大了,大到看不清。
/** * timer_stat - ftrace interface timer_stat * @timer: pointer to struct timer_list */ TRACE_EVENT timer; __entry->start_pid = timer->start_pid; __entry->slack = timer->slack; ), TP_printk("ftrace
这个函数定义在arch/arm64/kernel/entry-ftrace.S文件里面。最终函数调用到了ftrace_caller函数。 最终通过ftrace_modify_code来修改ftrace_graph_call原来所在位置的代码(步骤2中产生的跳转指令,这样可以直接跳转到ftrace_graph_caller这个函数) #ifdef CONFIG_FUNCTION_GRAPH_TRACER .global ftrace_graph_call ftrace_graph_call: // ftrace_graph_caller (ftrace_caller) 由于我们在使能function graph的时候在ftrace_enable_ftrace_graph_caller里面把ftrace_graph_call地址所在的nop 四、小结 本文介绍了ftrace的function graph tracer,通过在函数的调用开始及调用结束分别调用了prepare_ftrace_return及ftrace_return_to_handler
之前介绍通过命令行配置和使用ftrace功能,但是实际中,我们也会希望抓C/C++程序中某段代码的调度情况。笔者前不久就遇到这种问题,某个函数调用时延概率超过100ms,是为什么? 这时候就需要在他们代码中使能ftrace抓执行此函数时候,任务的调度情况。 观察某段代码执行过程中的情况,ftrace提供了trace markers功能,可通过写入trace_marker接口在ftrace中留下记录。 */ write(fd_trace, "0", 2); close(fd_mark); close(fd_trace); } 可参考如上代码,在自己程序中动态使能和关闭ftrace
启用 ftrace ftrace 现在已经是内核中的一部分了,你不再需要事先安装它了。也就是说,如果你在使用最近的 Linux 系统,那么 ftrace 是已经启用了的。 为了验证 ftrace 是否可用,运行 mount 命令并查找 tracefs。如果你看到类似下面的输出,表示 ftrace 已经启用,你可以轻松地尝试本文中下面的例子。 如果你直接运行 ftrace,不会运行任何特定的 ftrace 命令。相反的,基本操作是通过标准 Linux 命令来写入或读取一些文件。 #### all functions enabled ####$$ echo ext4_* > set_ftrace_filter$$ cat set_ftrace_filterext4_has_free_clustersext4 $ sudo echo $PID > set_ftrace_pid
tracing]# echo sched_switch > current_tracer [root@linux tracing]# echo 1 > tracing_on # 让内核运行一段时间,这样 ftrace root@linux tracing]# echo 0 > tracing_on [root@linux tracing]# cat trace | head -10 # 让内核运行一段时间,这样 ftrace
0.背景 ftrace的功能非常强大,可以在系统的各个关键点上采集数据用以追踪系统的运行情况。 关于ftrace的详细操作和原理分析可以参考Linux ftrace一文。 本文的主要目的主要是利用ftrace来做新增代码的性能分析和优化,应用的主要场景如下: 我们在现有的代码中增加了一批新函数A_*()。 但是这些接口对普通用户来说太多太复杂了,我们可以使用对ftrace功能进行二次封装的一些命令来操作。 trace-cmd就是ftrace封装命令其中的一种。 实际对应set_ftrace_filter,这种方式插桩的开销较小,只会追踪顶层func的执行时间且支持*等通配符的设置。 -g func。
Ftrace还提供了强大的过滤、快照snapshot、实例(instance)等功能,可以灵活配置。 内核配置Ftrace后,如果功能不打开,对性能几乎没有影响。 ftrace 框架 整个ftrace框架可以分为几部分:ftrace核心框架,RingBuffer,debugfs,Tracepoint,各种Tracer。 ftrace框架是整个ftrace功能的纽带,包括对内核的修改,Tracer的注册,RingBuffer的控制等等。 RingBuffer是静态动态ftrace的载体。 这个文件更多的是用于调试ftrace,但也可以用于查看是否有任何函数附加了回调。不仅ftrace框架使用ftrace函数tracing,其他子系统也可能使用。 set_ftrace_filter 和 set_ftrace_notrace 在编译内核时配置了动态 ftrace (选中 CONFIG_DYNAMIC_FTRACE 选项)后使用。
的内核注册 对于ftrace的framwork层,首先需要建立debugfs的一系列的访问节点,是通过如下的流程完成的 完成了核心的注册后,我们来看看ftrace是如何完成各个功能的,对于任何一个trace 当未选中CONFIG_DYNAMIC_FTRACE时,其采用如下的方案 每个函数调用都会根据不同的体系结构的实现调用_mcount函数 如果ftrace使能了某些跟踪器,ftrace_trace_function 指针不再指向ftrace_stub,而是指向具体的跟踪函数 否则就执行到体系结构相关的ftrace_stub从函数返回,而该接口为空函数 也就是说开启ftrace调用函数时,都会先调用_mcount, 总是至少会执行两条指令,即使ftrace_trace_function没有被指向某个跟踪函数。 2.1.2 动态插桩 static ftrace一旦使能,对kernel中所有的函数(除开notrace、online、其他特殊函数)进行插桩,这带来的性能开销是惊人的,有可能导致人们弃用ftrace功能
1 ftrace基础用法 ftrace 通过 debugfs 向用户态提供访问接口。 set_ftrace_filter:用于指定跟踪的函数 set_ftrace_notrace:用于指定不跟踪的函数 set_ftrace_pid:用于指定要跟踪特定进程的函数 Disable 同时ftrace允许你对一个特定的进程进行跟踪,在/sys/kernel/debug/tracing目录下,文件set_ftrace_pid的值要更新为你想跟踪的进程的PID。 #echo 1 > tracing_on 如何跟踪一个命令,但是这个命令执行时间很短 我们可以设置ftrace过滤器控制相关文件: set_ftrace_filter function tracer 但是这些接口对普通用户来说太多太复杂了,我们可以使用对ftrace功能进行二次封装的一些命令来操作。 trace-cmd就是ftrace封装命令其中的一种。
虽然Ftrace在2008年就加入了内核,但很多应用开发工程师仍然不知道它的存在。本文就给你介绍一下Ftrace的基本使用。 Ftrace初体验 先用一个例子体验一下Ftrace的使用简单,且功能强大。 函数跟踪 Ftrace 实际上代表的就是function trace(函数跟踪),因此函数追踪是Ftrace最初的一个主要功能。 取消 set_ftrace_pid 的设置: # echo > set_ftrace_pid Ftrace function_graph 文章开始例子已经展示过,function_graph 可以打印出函数的调用图 写在最后 Ftrace 就包含在内核源码中 kernel/trace,理解了 Ftrace 内核不再是黑箱,你会有豁然开朗的感觉,内核源码忽然有条理了起来。让我们从 Ftrace 开始内核探索之旅吧。
tracing # echo nop > current_tracer ----清空跟踪器 /sys/kernel/debug/tracing # echo drm_open > set_ftrace_filter function exec_file" exit -1 fi cd /sys/kernel/debug/tracing/ echo nop > current_tracer echo $1 > set_ftrace_filter debug/tracing # echo 1 > options/funcgraph-tail ----增加函数尾部注释 /sys/kernel/debug/tracing # echo > set_ftrace_filter function_graph > current_tracer echo $1 > set_graph_function echo 1 > options/funcgraph-tail echo > set_ftrace_filter
NULL) { if (iter->tr) { seq_printf(m, "# tracer: %s\n", iter->trace->name); seq_puts(m, "#\n"); test_ftrace_alive event; entry = iter->ent; test_cpu_buff_start(iter); /* (1.2.1) 根据ent->type,找到对应的trace_entry */ event = ftrace_find_event
之前使用ftrace的时候需要一系列的配置,使用起来有点繁琐,这里推荐一个ftrace的一个前端工具,它就是trace-cmd trace-cmd安装教程 安装trace-cmd及其依赖库 git clone set 设置ftrace参数配置。 trace-cmd show ['OPTIONS'] reset 对ftrace的设置和ring buffer复位。 *Instances:* List all configured ftrace instances. *Error log:* Dump the content of ftrace error_log file.
trace-cmd是设置读取ftrace的命令行工具,kernelshark既可以记录数据,也可以图形化分析结果。 /tracing/trace reset - disable all kernel tracing and clear the trace buffers----------------------对ftrace 2.2 trace-cmd record trace-cmd record用于录制ftrace信息,通过如下选项可以指定只跟踪特定traceevents,或者跟踪特定pid、或者跟踪特定funtion/ 的设置set_ftrace_filter、set_graph_function、set_ftrace_notrace、buffer_size_kb、tracing_cpumask。 小结 trace-cmd作为ftrace的前端,对ftrace的各种设置进行包装,同时能对结果进行处理,极大地提高了ftrace的使用效率。
一、什么是ftrace ftrace(FunctionTracer)是Linux内核的一个跟踪框架,它从2008年10月9日发布的内核版本2.6.27开始并入Linux内核主线[1]。 … 图1:ftrace是一个功能强大的内核函数追踪框架[3] 使用ftrace需要目标Linux操作系统在编译时启用CONFIG_FUNCTION_TRACER内核配置选项(该选项默认启用)。 这个空白区可以在需要的时候被替换为对ftrace相关函数的调用,从而实现对特定内核函数的调用追踪,而不会过度影响其它内核函数的运行性能。 关于ftrace的详细内部机制,受限于篇幅,本文不详细介绍。 | FTRACE_OPS_FL_IPMODIFY | FTRACE_OPS_FL_RECURSION; err = ftrace_set_filter_ip(&hook->FTraceOPS 修改ip的跳转方法导致经典方案中对hook子程的执行发生在ftrace相关函数返回之后(而非ftrace相关函数栈内),因此ftrace自带的防递归功能无法作用于经典方案。
由于x29保存了上一级caller的栈顶sp指针,因此不在需要入栈保存,如示例中fun2执行时,此时x29指向fun1的栈顶sp 编译阶段 以 blk_update_request 为例,看下其开启 Ftrace 函数 ftrace_caller 将调用用户注册的 trace 函数。 总结 编译阶段。 (1). ftrace_init:会将可 trace 函数中的 【bl 0 <_mcount>】 替换为 【nop】 指令; (2). 执行 echo blk_update_request > set_ftrace_filter:会使能 blk_update_request 的钩子函数替换标记(nop 替换为 ftrace_caller 执行 echo function > current_tracer:将 ftrace_caller 中 ftrace_call 被替换为 ftrace_ops_no_ops,最终会调用到 function_trace_call
一、前情提要 在前一篇文章《Linux内核跟踪:ftrace hook入门手册(上)》中,我们对部分ftrace hook经典方案中的实现细节进行了优化。本文会深入说明这些优化的原理和目的。 hook是通过编译时处理,在各个内核函数实现代码的开头插桩call指令,所以ftrace hook介入系统调用是在do_syscall_64之后: 图3:ftrace hook子程中打印的部分内核调用堆栈 hook子程并非在ftrace框架内调用,而是在ftrace框架返回到系统调用时跳转到hook子程(而没有回到真正的系统调用函数)。 *ops, struct ftrace_regs *fregs) { struct pt_regs *kernel_regs = ftrace_get_regs(fregs); struct /ftrace-hook/.
由于x29保存了上一级caller的栈顶sp指针,因此不在需要入栈保存,如示例中fun2执行时,此时x29指向fun1的栈顶sp 编译阶段 以 blk_update_request 为例,看下其开启 Ftrace 函数 ftrace_caller 将调用用户注册的 trace 函数。 总结 编译阶段。 (1). ftrace_init:会将可 trace 函数中的 【bl 0 <_mcount>】 替换为 【nop】 指令; (2). 执行 echo blk_update_request > set_ftrace_filter:会使能 blk_update_request 的钩子函数替换标记(nop 替换为 ftrace_caller 执行 echo function > current_tracer:将 ftrace_caller 中 ftrace_call 被替换为 ftrace_ops_no_ops,最终会调用到 function_trace_call
ftrace 现在已经是内核中的一部分了,你不再需要事先安装它了。也就是说,如果你在使用最近的 Linux 系统,那么 ftrace 是已经启用了的。 为了验证 ftrace 是否可用,运行 mount 命令并查找 tracefs。如果你看到类似下面的输出,表示 ftrace 已经启用,你可以轻松地尝试本文中下面的例子。 # mount | grep tracefsnone on /sys/kernel/tracing type tracefs (rw,relatime,seclabel) 要想使用 ftrace,你首先需要进入上面 如果你直接运行 ftrace,不会运行任何特定的 ftrace 命令。相反的,基本操作是通过标准 Linux 命令来写入或读取一些文件。 #### all functions enabled ####$$ echo ext4_* > set_ftrace_filter$$ cat set_ftrace_filterext4_has_free_clustersext4