如何使用ftrace进行内核调试


1.内核配置

编译内核的时候,将以下config写入选择为y,编入内核:

CONFIG_FUNCTION_TRACER 
 CONFIG_FUNCTION_GRAPH_TRACER 
 CONFIG_CONTEXT_SWITCH_TRACER 
 CONFIG_NOP_TRACER 
 CONFIG_SCHED_TRACER 

2.用户空间接口


     ftrace 通过 debugfs 向用户态提供访问接口。配置内核时激活 debugfs 后会创建目录 /sys/kernel/debug ,debugfs 文件系统就是挂载到该目录。要挂载该目录,需要将如下内容添加到 /etc/fstab 文件:

        debugfs  /sys/kernel/debug  debugfs  defaults  0  0 

      或者可以在运行时挂载:

        mount  -t  debugfs  nodev  /debug 

      进入其中的tracing目录,可以看到类似于下面的文件(这些文件会因为我们编译内核时候选定的选项不同而略有差别)


      /debug/tracing 目录下文件和目录比较多,有些是各种跟踪器共享使用的,有些是特定于某个跟踪器使用的。在操作这些数据文件时,通常使用 echo 命令来修改其值,也可以在程序中通过文件读写相关的函数来操作这些文件的值(但是不可以用vim编辑器对这些文件进行编辑)。下面只对部分文件进行描述,读者可以参考内核源码包中 Documentation/trace 目录下的文档以及 kernel/trace 下的源文件以了解其余文件的用途。

  •  README文件提供了一个简短的使用说明,展示了 ftrace 的操作命令序列。可以通过 cat 命令查看该文件以了解概要的操作流程。
  • current_tracer用于设置或显示当前使用的跟踪器;使用 echo 将跟踪器名字写入该文件可以切换到不同的跟踪器。系统启动后,其缺省值为 nop ,即不做任何跟踪操作。在执行完一段跟踪任务后,可以通过向该文件写入 nop 来重置跟踪器。
  • available_tracers记录了当前编译进内核的跟踪器的列表,可以通过 cat 查看其内容;其包含的跟踪器与图 3 中所激活的选项是对应的。写 current_tracer 文件时用到的跟踪器名字必须在该文件列出的跟踪器名字列表中。有blk mmiotrace function等
  • trace文件提供了查看获取到的跟踪信息的接口。可以通过 cat 等命令查看该文件以查看跟踪到的内核活动记录,也可以将其内容保存为记录文件以备后续查看。
  • tracing_enabled用于控制 current_tracer 中的跟踪器是否可以跟踪内核函数的调用情况。写入 0 会关闭跟踪活动,写入 1 则激活跟踪功能;其缺省值为 1 。
  • set_graph_function设置要清晰显示调用关系的函数,显示的信息结构类似于 C 语言代码,这样在分析内核运作流程时会更加直观一些。在使用 function_graph 跟踪器时使用;缺省为对所有函数都生成调用关系序列,可以通过写该文件来指定需要特别关注的函数。
  • buffer_size_kb用于设置单个 CPU 所使用的跟踪缓存的大小。跟踪器会将跟踪到的信息写入缓存,每个 CPU 的跟踪缓存是一样大的。跟踪缓存实现为环形缓冲区的形式,如果跟踪到的信息太多,则旧的信息会被新的跟踪信息覆盖掉。注意,要更改该文件的值需要先将 current_tracer 设置为 nop 才可以。
  • tracing_on用于控制跟踪的暂停。有时候在观察到某些事件时想暂时关闭跟踪,可以将 0 写入该文件以停止跟踪,这样跟踪缓冲区中比较新的部分是与所关注的事件相关的;写入 1 可以继续跟踪。
  • available_filter_functions记录了当前可以跟踪的内核函数。对于不在该文件中列出的函数,无法跟踪其活动。
  • set_ftrace_filter和 set_ftrace_notrace在编译内核时配置了动态 ftrace (选中 CONFIG_DYNAMIC_FTRACE 选项)后使用。前者用于显示指定要跟踪的函数,后者则作用相反,用于指定不跟踪的函数。如果一个函数名同时出现在这两个文件中,则这个函数的执行状况不会被跟踪。这些文件还支持简单形式的含有通配符的表达式,这样可以用一个表达式一次指定多个目标函数;具体使用在后续文章中会有描述。注意,要写入这两个文件的函数名必须可以在文件 available_filter_functions 中看到。缺省为可以跟踪所有内核函数,文件 set_ftrace_notrace 的值则为空。
  • available_events 可以监控的事件,例如writeback等

4.ftrace跟踪器


      ftrace 当前包含多个跟踪器,用于跟踪不同类型的信息,比如进程调度、中断关闭等。可以查看文件 available_tracers 获取内核当前支持的跟踪器列表。在编译内核时,也可以看到内核支持的跟踪器对应的选项

  • nop跟踪器不会跟踪任何内核活动,将 nop 写入 current_tracer 文件可以删除之前所使用的跟踪器,并清空之前收集到的跟踪信息,即刷新 trace 文件。
  • function跟踪器可以跟踪内核函数的执行情况;可以通过文件 set_ftrace_filter 显示指定要跟踪的函数
  • function_graph跟踪器可以显示类似 C 源码的函数调用关系图,这样查看起来比较直观一些;可以通过文件 set_grapch_function 显示指定要生成调用流程图的函数。
  • sched_switch跟踪器可以对内核中的进程调度活动进行跟踪
  • irqsoff跟踪器和 preemptoff跟踪器分别跟踪关闭中断的代码和禁止进程抢占的代码,并记录关闭的最大时长preemptirqsoff跟踪器则可以看做它们的组合。
ftrace 还支持其它一些跟踪器,比如 initcall、ksym_tracer、mmiotrace、sysprof 等。ftrace 框架支持扩展添加新的跟踪器。读者可以参考内核源码包中 Documentation/trace 目录下的文档以及 kernel/trace 下的源文件,以了解其它跟踪器的用途和如何添加新的跟踪器。


5.ftrace操作


     使用 ftrace 提供的跟踪器来调试或者分析内核时需要如下操作:

  • 切换到目录 /debug/tracing/ 下
  • 查看 available_tracers 文件,获取当前内核支持的跟踪器列表
  • 关闭 ftrace 跟踪,即将 0 写入文件 tracing_enabled
  • 激活 ftrace_enabled ,否则 function 跟踪器的行为类似于 nop;另外,激活该选项还可以让一些跟踪器比如 irqsoff 获取更丰富的信息。建议使用 ftrace 时将其激活。要激活 ftrace_enabled ,可以通过 proc 文件系统接口来设置:
    echo 1 > /proc/sys/kernel/ftrace_enabled 

  • 将所选择的跟踪器的名字写入文件 current_tracer
  • 将要跟踪的函数写入文件 set_ftrace_filter ,将不希望跟踪的函数写入文件 set_ftrace_notrace。通常直接操作文件 set_ftrace_filter 就可以了
  • 激活 ftrace 跟踪,即将 1 写入文件 tracing_enabled。还要确保文件 tracing_on 的值也为 1,该文件可以控制跟踪的暂停
  • 如果是对应用程序进行分析的话,启动应用程序的执行,ftrace 会跟踪应用程序运行期间内核的运作情况
  • 通过将 0 写入文件 tracing_on 来暂停跟踪信息的记录,此时跟踪器还在跟踪内核的运行,只是不再向文件 trace 中写入跟踪信息;或者将 0 写入文件 tracing_enabled 来关闭跟踪
  • 查看文件 trace 获取跟踪信息,对内核的运行进行分析调试
      具体而言,需要执行的命令如下:

#:echo      0                                           tracing_on
#:echo         1                                           tracing_on
#:echo          yourwantedtracer            current_tracer(default=nop)
#:echo          filenamepattern               set_ftrace_filter(default=all)
#echo 0 tracing_on  //关闭tracing信息


7.ftrace 跟踪器实例讲解



 [root@linux tracing]# echo 0 > tracing_on
 [root@linux tracing]# echo 1 > tracing_on
 [root@linux tracing]# echo function > current_tracer 
 [root@linux tracing]# echo 1 > tracing_on 
 [root@linux tracing]# echo 1 > tracing_enabled 

 # 让内核运行一段时间,这样 ftrace 可以收集一些跟踪信息,之后再停止跟踪

 [root@linux tracing]# echo 0 > tracing_enabled 
 [root@linux tracing]# cat trace | head -10 
 # tracer: function 
 # 
 #         TASK-PID    CPU#    TIMESTAMP  FUNCTION 
 #            | |       |          |         | 
          <idle>-0     [000] 20654.426521: _raw_spin_lock <-scheduler_tick 
          <idle>-0     [000] 20654.426522: task_tick_idle <-scheduler_tick 
          <idle>-0     [000] 20654.426522: cpumask_weight <-scheduler_tick 
          <idle>-0     [000] 20654.426523: cpumask_weight <-scheduler_tick 
          <idle>-0     [000] 20654.426523: run_posix_cpu_timers <-update_process_times 
 <idle>-0 [000] 20654.426524: hrtimer_forward <-tick_sched_timer 

      trace 文件给出的信息格式很清晰。首先,字段“tracer:”给出了当前所使用的跟踪器的名字,这里为 function 跟踪器。然后是跟踪信息记录的格式,TASK 字段对应任务的名字,PID 字段则给出了任务的进程 ID,字段 CPU# 表示运行被跟踪函数的 CPU 号,这里可以看到 idle 进程运行在 0 号 CPU 上,其进程 ID 是 0 ;字段 TIMESTAMP 是时间戳,其格式为“<secs>.<usecs>,表示执行该函数时对应的时间戳;FUNCTION 一列则给出了被跟踪的函数,函数的调用者通过符号 “<-” 标明,这样可以观察到函数的调用关系。
其他跟踪器简介
function_graph:用于生成带有{}的类似于C语言格式的函数调用关系图
sched_switch 跟踪器可以对进程的调度切换以及之间的唤醒操作进行跟踪

8.跟踪特定的函数


       在实际工作中,我们往往需要跟中特定的函数,或者是某一个模块下面的几个函数
跟踪ipv6模块的函数
 [root@linux tracing]# echo ':mod:ipv6' > set_ftrace_filter 
 [root@linux tracing]# cat set_ftrace_filter | head -5 
 ipv6_opt_accepted 
 inet6_net_exit 
 ipv6_gro_complete 
 inet6_create 
 ipv6_addr_copy 


9.使用trace_printk打印跟踪信息


     内核头文件 include/linux/kernel.h 中描述了 ftrace 提供的工具函数的原型,这些函数包括 trace_printk、tracing_on/tracing_off 等。本文通过示例模块程序向读者展示如何在代码中使用这些工具函数。


你可能感兴趣的:(内核测试,ftrace)