使用ftrace追踪函数调用
顾名思义,ftrace原本是记录函数调用时间而开发出来的。首先介绍它的使用方法。作为示例,尝试追踪Linux的进程调度程序是从哪个函数调用的。首先根据available_tracers的内容确认是否支持记录函数调用的函数追踪器。
[~]#cd/sys/kernel/debug/tracing
[tracing]#cat available_tracers
blk function_graph wakeup_rt wakeup irqsoff function sched_switch nop
函数追踪器为表8-8中的function。available_tracers包含function,因此可见在这个内核中可以使用函数追踪器。
一旦将函数追踪器启用,ftrace就会记录所有函数的运行情况。但是本次只想查看调度程序函数schedule()的调用情况,因此事先使用追踪函数过滤器设置为仅记录schedule()。[tracing]#echo schedule>set_ftrace_flter设置好追踪函数过滤器后,将函数追踪器funciton写入current_tracer特殊文件。
[tracing]#echo function>current_tracer
追踪结果可以从trace特殊文件读出。这时的结果如下所示。
[tracing]#head trace
tracer:function
#
TASK-PID CPU#TIMESTAMP FUNCTION
|||||
tee-7470[000]16107.974550:schedule<-do_exit
<idle>-0[000]16107.975318:schedule<-cpu_idle
bash-5210[000]16107.976277:schedule<-schedule_timeout
events/0-9[000]16107.976371:schedule<-worker_thread
<idle>-0[001]16108.054539:schedule<-cpu_idle
flush-8:0-284[001]16108.054557:schedule<-schedule_timeout
可以看出进程调度程序是从几个不同的函数调用的。
可以使用多个函数名称或通配符向过滤器指定模式、模块。例如,按照下列方式,就可以记录函数名以irq开头的所有函数调用。
[tracing]#echo'irq*'>set_ftrace_flter
另外,在参数前面加上:mod:,还可以仅追踪特定的内核驱动程序模块中包含的函数。在下例中,仅追踪btrfs模块中包含的函数。
[tracing]#echo:mod:btrfs>set_ftrace_flter
为了如前所述仅获取以irq开头的函数,需要更换过滤器。
[tracing]#echo'irq*'>set_ftrace_flter
[tracing]#echo 0>trace
[tracing]#head trace
tracer:function
#
TASK-PID CPU#TIMESTAMP FUNCTION
|||||
bash-1911[000]55477.514345:irq_enter<-smp_apic_timer_interrupt
bash-1911[000]55477.514677:irq_exit<-smp_apic_timer_interrupt
bash-1911[000]55477.514939:irq_enter<-smp_apic_timer_interrupt
bash-1911[000]55477.514995:irq_exit<-smp_apic_timer_interrupt
<idle>-0[000]55477.515953:irq_enter<-smp_apic_timer_interrupt
<idle>-0[000]55477.516041:irq_exit<-smp_apic_timer_interrupt
可以看出记录了以irq开头的函数。切换了过滤器后,就向trace写入0,这是为了将缓冲区内容暂时清除。仅通过切换过滤器是不能清除缓冲区内容的,因此需要这样手动清除缓冲区内容。