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    |             }
相关推荐
广而不精zhu小白2 小时前
CentOS Stream 9 挂载Windows共享FTP文件夹
linux·windows·centos
一休哥助手2 小时前
全面解析 Linux 系统监控与性能优化
linux·运维·性能优化
二进制杯莫停2 小时前
掌控网络流量的利器:tcconfig
linux
watl02 小时前
【Android】unzip aar删除冲突classes再zip
android·linux·运维
赵大仁3 小时前
在 CentOS 7 上安装 Node.js 20 并升级 GCC、make 和 glibc
linux·运维·服务器·ide·ubuntu·centos·计算机基础
vvw&3 小时前
Docker Build 命令详解:在 Ubuntu 上构建 Docker 镜像教程
linux·运维·服务器·ubuntu·docker·容器·开源
冷曦_sole3 小时前
linux-21 目录管理(一)mkdir命令,创建空目录
linux·运维·服务器
最后一个bug3 小时前
STM32MP1linux根文件系统目录作用
linux·c语言·arm开发·单片机·嵌入式硬件
dessler3 小时前
Docker-Dockerfile讲解(二)
linux·运维·docker
卫生纸不够用3 小时前
子Shell及Shell嵌套模式
linux·bash