6.ftrace实操--function graph tracer

此文章用来汇总通过ftrace查看函数调用栈的方法。

1、查看指定函数向上调用栈

bash 复制代码
# cat function.sh 
#
cd /sys/kernel/debug/tracing/ 
echo 0 > trace
echo function > current_tracer
# filter vfs_open function
echo vfs_open > ./set_ftrace_filter
echo 1 > ./options/func_stack_trace
echo 1 > tracing_on

cat /mnt/ftrace_script/function/test.file
sleep 1

echo 0 > tracing_on
cat trace
echo nop > ./current_tracer
echo 0 > ./options/func_stack_trace
echo !vfs_open >> ./set_ftrace_filter

可通过 cat /sys/kernel/debug/tracing/available_filter_functions | grep vfs_open查看是否支持要filter的函数。

ini 复制代码
# ./function.sh 

# tracer: function
#
# entries-in-buffer/entries-written: 328/328   #P:4
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-1563  [000] .... 21050.687018: vfs_open <-do_last
        modprobe-1563  [000] .... 21050.694614: <stack trace>
 => vfs_open
 => path_openat
 => do_filp_open
 => do_open_execat
 => __do_execve_file
 => do_execveat_common
 => do_execve
 => call_usermodehelper_exec_async
        modprobe-1563  [000] .... 21050.700709: vfs_open <-do_last
        modprobe-1563  [000] .... 21050.700768: <stack trace>
 => vfs_open
 => path_openat
 => do_filp_open
 => do_open_execat
 => open_exec
 => load_elf_binary
 => search_binary_handler
 => exec_binprm
 => __do_execve_file
 => do_execveat_common
 => do_execve
 => call_usermodehelper_exec_async

"set_ftrace_notrace"文件阻止这些函数被跟踪:

bash 复制代码
echo '*preempt*' '*lock*' > set_ftrace_notrace

2、查看函数向下的调用栈与执行时间

function_graph tracer与function tracer类似,不同之处在于它探测函数的入口和出口。

在函数的两端进行探测会导致一些特殊的特性,例如:

  • 测量函数的执行时间
  • 有一个可靠的调用堆栈来绘制函数调用图

这个tracer在以下几种情况是很有用的:

  • 想要找到一个奇怪的内核行为的原因,并需要看到在任何区域(或特定区域)发生了什么细节
  • 你正好遇到了奇怪的延迟,但很难找到它的起源
  • 想要快速找到特定函数的路径
  • 只想看看一个正在运行的内核里面发生了什么
c 复制代码
cd /sys/kernel/debug/tracing/ 
echo 0 > tracing_on
echo 0 > trace
echo function_graph > current_tracer
echo 1 > options/funcgraph-proc
echo vfs_read > set_graph_function
echo 1 > options/funcgraph-tail
echo 1 > tracing_on

cat /mnt/ftrace_script/function/test.file

echo 0 > tracing_on
cat trace
echo 0 > trace
echo nop > ./current_tracer
echo 0 > options/funcgraph-proc
echo !vfs_read >> set_graph_function
echo 0 > options/funcgraph-tail

输出结果:

scss 复制代码
ftrace test file
# tracer: function_graph
#
# CPU  TASK/PID         DURATION                  FUNCTION CALLS
# |     |    |           |   |                     |   |   |   |
 2)    exe-227     |               |  vfs_read() {
 2)    exe-227     |               |    rw_verify_area() {
 2)    exe-227     |               |      security_file_permission() {
 2)    exe-227     | + 15.040 us   |        __fsnotify_parent();
 2)    exe-227     | + 15.696 us   |        fsnotify();
 2)    exe-227     | + 78.768 us   |      } /* security_file_permission */
 2)    exe-227     | ! 109.552 us  |    } /* rw_verify_area */
 2)    exe-227     |               |    __vfs_read() {
 2)    exe-227     |               |      new_sync_read() {
 2)    exe-227     |               |        shmem_file_read_iter() {
 2)    exe-227     |               |          shmem_getpage_gfp.isra.47() {
 2)    exe-227     |               |            find_lock_entry() {
 2)    exe-227     |               |              find_get_entry() {
 2)    exe-227     | + 14.128 us   |                __rcu_read_lock();
 2)    exe-227     | + 15.232 us   |                PageHuge();
 2)    exe-227     | + 14.592 us   |                __rcu_read_unlock();
 2)    exe-227     | ! 107.856 us  |              } /* find_get_entry */
 2)    exe-227     | + 14.688 us   |              page_mapping();
 2)    exe-227     | ! 301.456 us  |            } /* find_lock_entry */
 2)    exe-227     | ! 336.768 us  |          } /* shmem_getpage_gfp.isra.47 */
 2)    exe-227     |               |          set_page_dirty() {
 2)    exe-227     | + 14.608 us   |            page_mapping();
 2)    exe-227     | + 15.760 us   |            __set_page_dirty_no_writeback();
 2)    exe-227     | + 77.168 us   |          } /* set_page_dirty */
 2)    exe-227     | + 14.928 us   |          unlock_page();
 2)    exe-227     | + 15.920 us   |          preempt_count_add();
 2)    exe-227     | + 16.208 us   |          preempt_count_sub();
 2)    exe-227     |               |          touch_atime() {
 2)    exe-227     |               |            atime_needs_update() {
 2)    exe-227     |               |              current_time() {
 2)    exe-227     | + 14.560 us   |                ktime_get_coarse_real_ts64();
 2)    exe-227     | + 14.560 us   |                timestamp_truncate();
 2)    exe-227     | + 72.240 us   |              } /* current_time */
 2)    exe-227     | ! 104.432 us  |            } /* atime_needs_update */
 2)    exe-227     | ! 134.544 us  |          } /* touch_atime */
 2)    exe-227     | ! 714.336 us  |        } /* shmem_file_read_iter */
 2)    exe-227     | ! 745.280 us  |      } /* new_sync_read */
 2)    exe-227     | ! 775.344 us  |    } /* __vfs_read */
 2)    exe-227     | + 14.496 us   |    __fsnotify_parent();
 2)    exe-227     | + 14.864 us   |    fsnotify();
 2)    exe-227     | # 1000.880 us |  } /* vfs_read */

有几列可以被动态地启用和禁用。可以根据自己的需要,使用任何想要的选项组合:

执行该功能的cpu编号默认为启用状态。有时候只跟踪一个cpu更好(参见"tracing_cpu_mask"文件),或者有时在cpu跟踪开关时可能会看到无序的函数调用。

bash 复制代码
隐藏:echo nofuncgraph-cpu > trace_options
显示:echo funcgraph-cpu > trace_options

持续时间(该函数的执行时间)显示在函数的右括号行上,如果是第一个叶节点,则显示在与当前函数相同的行上。默认是启用的。

bash 复制代码
隐藏:echo nofuncgraph-duration > trace_options
显示:echo funcgraph-duration > trace_options

当达到持续时间阈值时,开销字段在持续时间字段之前。

bash 复制代码
隐藏:echo nofuncgraph-overhead > trace_options
显示:echo funcgraph-overhead > trace_options
依赖于选项:funcgraph-duration

flags:

  • '+' 表示函数超过10个usec。
  • '!' 表示函数超过100个usec。
  • '#' 表示函数超过1000个usec。
  • '*' 表示函数超过10毫秒。
  • '@' 表示函数超过100毫秒。
  • '$' 表示函数超过1秒。

task/pid字段显示执行该函数的线程cmdline和pid。默认是禁用的。

bash 复制代码
隐藏:echo nofuncgraph-proc > trace_options
显示:echo funcgraph-proc > trace_options

绝对时间字段是系统时钟自启动以来给出的绝对时间戳。在函数的每次进入/退出时都会给出这个时间的快照。

bash 复制代码
隐藏:echo nofuncgraph-abstime > trace_options
显示:echo funcgraph-abstime > trace_options

如果函数的开头不在trace buffer中,则函数名总是显示在函数的右括号之后。

对于开头在跟踪缓冲区中的函数,可以启用在结束括号后显示函数名,以便使用grep更容易地搜索函数持续时间。默认是禁用的。

bash 复制代码
隐藏:echo nofuncgraph-tail > trace_options
显示:echo funcgraph-tail > trace_options

如果你想在__might_sleep()函数中添加注释,你只需要包含<linux/ftrace. h>;并在__might_sleep()::中调用trace_printk()

css 复制代码
trace_printk("I'm a comment!\n")
将会产生::

   1)               |             __might_sleep() {
   1)               |                /* I'm a comment! */
   1)   1.449 us    |             }
相关推荐
叶北辰CHINA28 分钟前
nginx反向代理,负载均衡,HTTP配置简述(说人话)
linux·运维·nginx·http·云原生·https·负载均衡
不惑_1 小时前
在 Ubuntu 安装 Python3.7(没有弯路)
linux·运维·ubuntu
玉树临风江流儿2 小时前
Linux驱动开发(速记版)--设备模型
linux·驱动开发
杰哥在此2 小时前
Python知识点:如何使用Multiprocessing进行并行任务管理
linux·开发语言·python·面试·编程
枫叶丹44 小时前
【在Linux世界中追寻伟大的One Piece】进程信号
linux·运维·服务器
刻词梨木5 小时前
ubuntu中挂载点内存不足,分配不合理后使用软链接的注意事项
linux·运维·ubuntu
灯火不休ᝰ5 小时前
[win7] win7系统的下载及在虚拟机中详细安装过程(附有下载文件)
linux·运维·服务器
powerfulzyh9 小时前
Ubuntu24.04远程开机
linux·ubuntu·远程工作
ulimpid9 小时前
Command | Ubuntu 个别实用命令记录(新建用户、查看网速等)
linux·ubuntu·command
HHoao9 小时前
Ubuntu启动后第一次需要很久才能启动GTK应用问题
linux·运维·ubuntu