使用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,这是为了将缓冲区内容暂时清除。仅通过切换过滤器是不能清除缓冲区内容的,因此需要这样手动清除缓冲区内容。