前段时间遇到个问题,有个后继音频数据处理线程调度不及时导致音频输出延迟,音视频不同步。
因此从系统上入手,采用ftrace进行debug,来看有哪些线程会去抢占音频数据处理线程。
ftrace 提供了不同的跟踪器,以用于不同的场合,比如跟踪内核函数调用、对上下文切换进行跟踪、查看中断被关闭的时长、跟踪内核态中的延迟以及性能问题等。系统开发人员可以使用 ftrace 对内核进行跟踪调试,以找到内核中出现的问题的根源,方便对其进行修复。
1.首先得打开ftrace相关的config,并重新编译内核。
可以通过make menuconfig或者修改.config文件。
编译完成后,cat /boot/configxxx | grep | FTRACE 查看
2.如果需要跟踪某些ko,则需要重新在打开ftrace的内核下重新编译。
3.mount debugfs,ftrace使用debugfs作为配置工具 。
mount -t debugfs nodev /sys/kernel/debug
/sys/kernel/debug/trace 目录下文件和目录比较多,有些是各种跟踪器共享使用的,有些是特定于某个跟踪器使用的。在操作这些数据文件时,通常使用 echo 命令来修改其值,也可以在程序中通过文件读写相关的函数来操作这些文件的值。下面只对部分文件进行描述,可以参考内核源码包中 Documentation/trace 目录下的文档以及 kernel/trace 下的源文件以了解其余文件的用途。
- README文件提供了一个简短的使用说明,展示了 ftrace 的操作命令序列。可以通过 cat 命令查看该文件以了解概要的操作流程。
- current_tracer用于设置或显示当前使用的跟踪器;使用 echo 将跟踪器名字写入该文件可以切换到不同的跟踪器。系统启动后,其缺省值为 nop ,即不做任何跟踪操作。在执行完一段跟踪任务后,可以通过向该文件写入 nop 来重置跟踪器。
- available_tracers记录了当前编译进内核的跟踪器的列表,可以通过 cat 查看其内容;写 current_tracer 文件时用到的跟踪器名字必须在该文件列出的跟踪器名字列表中。
- trace文件提供了查看获取到的跟踪信息的接口。可以通过 cat 等命令查看该文件以查看跟踪到的内核活动记录,也可以将其内容保存为记录文件以备后续查看。
- set_graph_function设置要清晰显示调用关系的函数,显示的信息结构类似于 C 语言代码,这样在分析内核运作流程时会更加直观一些。在使用 function_graph 跟踪器时使用;缺省为对所有函数都生成调用关系序列,可以通过写该文件来指定需要特别关注的函数。
echo function_graph > current_tracer echo __do_fault > set_graph_function //跟踪__do_fault
- 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 的值则为空。甚至可以对函数的名字使用通配符。我需要用所有的vmalloc_函数,通过echo vmalloc_* > set_ftrace_filter进行设
- set_event 也可以在系统特定事件触发的时候打开跟踪。为了启用某个事件,你需要:echo sys_enter_nice >> set_event(注意你是将事件的名字追加到文件中去,使用>>追加定向器,不是>)。要禁用某个事件,需要在名字前加上一个“!”号:echo '!sys_enter_nice' >> set_event。以下三种方式都可以启用事件
echo sched:sched_switch >> /debug/tracing/set_event echo sched_switch >> /debug/tracing/set_event echo 1 > /debug/tracing/events/sched/sched_switch/enable
- available_events可以在available_events文件中找到所有可用的系统事件.
4.在出现问题前,开启ftrace 来跟踪内核活动。可以写个如下的脚本start_ftrace.sh实现:
#!/bin/bash
#mount -t debugfs nodev /sys/kernel/debug
echo nop > /sys/kernel/debug/tracing/current_tracer
echo 0 > /sys/kernel/debug/tracing/tracing_on
echo > /sys/kernel/debug/tracing/trace
#echo "function" > /sys/kernel/debug/tracing/current_tracer
echo "sched_switch sched_wakeup sched_wakeup_new sched_migrate_task irq_handler_entry irq_handler_exit softirq_raise softirq_entry softirq_exit" > /sys/kernel/debug/tracing/set_event
echo "workqueue_execute_start workqueue_execute_end block_rq_issue block_rq_insert block_rq_complete" >> /sys/kernel/debug/tracing/set_event
echo 20480 > /sys/kernel/debug/tracing/buffer_size_kb
echo 1 > /sys/kernel/debug/tracing/tracing_on
echo "frace start!"
5.出现问题后,停止ftrace。如下stop_ftrace.sh
#!/bin/bash
echo "stop ftrace!"
echo 0 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace > ./ftrace.log
#echo nop > /sys/kernel/debug/tracing/current_tracer
echo > /sys/kernel/debug/tracing/trace
6.查看trace结果ftrace.log.