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    |             }
相关推荐
Doro再努力1 小时前
Vim 快速上手实操手册:从入门到生产环境实战
linux·编辑器·vim
wypywyp1 小时前
8. ubuntu 虚拟机 linux 服务器 TCP/IP 概念辨析
linux·服务器·ubuntu
Doro再努力2 小时前
【Linux操作系统10】Makefile深度解析:从依赖推导到有效编译
android·linux·运维·服务器·编辑器·vim
senijusene2 小时前
Linux软件编程:IO编程,标准IO(1)
linux·运维·服务器
忧郁的橙子.2 小时前
02-本地部署Ollama、Python
linux·运维·服务器
醇氧2 小时前
【linux】查看发行版信息
linux·运维·服务器
No8g攻城狮3 小时前
【Linux】Windows11 安装 WSL2 并运行 Ubuntu 22.04 详细操作步骤
linux·运维·ubuntu
XiaoFan0123 小时前
免密批量抓取日志并集中输出
java·linux·服务器
souyuanzhanvip3 小时前
ServerBox v1.0.1316 跨平台 Linux 服务器管理工具
linux·运维·服务器
HalvmånEver4 小时前
Linux:线程互斥
java·linux·运维