Linux动态追踪——ftrace

目录

摘要

1 初识

1.1 tracefs

1.2 文件描述

2 函数跟踪

2.1 函数的调用栈

2.2 函数调用栈

2.3 函数的子调用

3 事件跟踪

4 简化命令行工具

5 总结


摘要

        Linux下有多种动态追踪的机制,常用的有 ftrace、perf、eBPF 等,每种机制适应于不同的场景,今天学习一下ftrace的常见用法。

        ftrace 是一个内部跟踪器,旨在帮助开发人员查找内核内部发生的情况。ftrace 是几个分类跟踪实用程序的框架,其最常见的用途是函数跟踪、事件跟踪。

1 初识

1.1 tracefs

        ftrace 提供了类似于 procfs 的虚拟文件系统,以文件的形式为用户空间提供了交互接口。这样,我们不用依赖额外的工具,就能跟 ftrace 交互,完成跟踪的目标。

        ftracefs 挂载点通常位于 /sys/kernel/tracing 目录,如果你的这个目录下什么都没有,那么可以通过这个命令安装挂载点:

mount -t tracefs nodev /sys/kernel/tracing

        进入 tracing 目录查看,真是多:

[root@172 ~]# cd /sys/kernel/tracing/
[root@172 tracing]# ls
available_events            kprobe_events        set_ftrace_notrace  trace_marker_raw
available_filter_functions  kprobe_profile       set_ftrace_pid      trace_options
available_tracers           max_graph_depth      set_graph_function  trace_pipe
buffer_size_kb              options              set_graph_notrace   trace_stat
...

1.2 文件描述

        其中 available_tracers 描述了支持的跟踪器的种类,常用的是 function 和 function_graph

[root@172 tracing]# cat available_tracers 
hwlat blk function_graph wakeup_dl wakeup_rt wakeup function nop

        current_tracer 表示正在使用的跟踪器:

[root@172 tracing]# cat current_tracer 
nop

        available_filter_functions 为可跟踪的完整函数列表:

[root@172 tracing]# cat available_filter_functions  |grep "sys_open"
do_sys_open
__x64_sys_open
__ia32_sys_open
__x64_sys_openat
__ia32_sys_openat
__ia32_compat_sys_open
__ia32_compat_sys_openat
__x64_sys_open_by_handle_at
__ia32_sys_open_by_handle_at
__ia32_compat_sys_open_by_handle_at
proc_sys_open

        其它常见文件含义如下:

  • current_tracer:顾名思义为当前在用的跟踪器
  • function_profile_enabled:启用函数性能分析器
  • set_ftrace_filter:选择跟踪函数的列表
  • se_event_pid:设置跟踪进程的PID
  • tracing_on:启用跟踪
  • trace_options:跟踪的选项类型
  • trace_stat:函数性能分析输出的目录
  • trace:跟踪的输出文件

        ​​​​​​​看完了又好像啥都没看一样,还是看看实操什么样的!

2 函数跟踪

        前面写了,ftrace 支持好几种类型的跟踪器,这里实际使用一下看看效果如何。

2.1 函数的调用栈

        这里看下那个程序有调用到 fork 这个系统调用呢?通过 available_filter_functions 输出知道了其支持查看 _do_fork 这个函数的跟踪:

[root@172 tracing]# cat available_filter_functions | grep "fork"
_do_fork
...

        那我们就跟踪下 __do_fork 的调用:

# 设置跟踪器类型为 function
[root@172 tracing]# echo function > current_tracer 
# 设置要跟踪的函数名
[root@172 tracing]# echo _do_fork > set_ftrace_filter 
# 启用跟踪
[root@172 tracing]# echo 1 > tracing_on 
# 触发 fork 系统调用
[root@172 tracing]# ps aux | grep "bash" | grep -v "grep"
root        1485  0.0  0.7 236608  5940 pts/0    Ss   15:09   0:01 -bash

        查看 trace 输出:

[root@172 tracing]# cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |bash-1485  [000] ....  2832.519248: _do_fork <-do_syscall_64bash-1485  [000] ....  2832.519502: _do_fork <-do_syscall_64bash-1485  [000] ....  2837.109585: _do_fork <-do_syscall_64bash-1485  [000] ....  2837.113690: _do_fork <-do_syscall_64bash-1485  [000] ....  2838.637411: _do_fork <-do_syscall_64bash-1485  [000] ....  2838.639147: _do_fork <-do_syscall_64

        其中 TASK-PID 表示调用 _do_fork 的进程 id,CPU 000 表示该进程运行在0号 cpu,TIMESTAMP 为函数调用的时间戳,FUNCTION 显示了 _do_fork 由  do_syscall_64 调用。

        执行完毕后还需要关闭跟踪:

[root@172 tracing]# echo 0 > tracing_on
[root@172 tracing]# echo > set_ftrace_filter 
[root@172 tracing]# echo > current_tracer 
[root@172 tracing]# echo nop > current_tracer

2.2 函数调用栈

        有时候只知道函数被哪些进程调用,信息可能还不够全面,我们需要知道详细的调用栈,方便理清执行流程。这就依赖 options/func_stack_track 选项了。具体执行过程跟刚刚还是差不多的。

[root@172 tracing]# echo function > current_tracer 
[root@172 tracing]# echo 0 >tracing_on 
[root@172 tracing]# echo _do_fork > set_ftrace_filter
# 开启跟踪函数的调用栈
[root@172 tracing]# echo 1 > options/func_stack_trace 
[root@172 tracing]# echo 1 > tracing_on 
[root@172 tracing]# cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |bash-1485  [000] ....  4195.579130: _do_fork <-do_syscall_64bash-1485  [000] ....  4195.579157: <stack trace>=> 0xffffffffc0871061=> _do_fork=> do_syscall_64=> entry_SYSCALL_64_after_hwframebash-1485  [000] ....  4195.582865: _do_fork <-do_syscall_64bash-1485  [000] ....  4195.582882: <stack trace>=> 0xffffffffc0871061=> _do_fork=> do_syscall_64=> entry_SYSCALL_64_after_hwframe
[root@172 tracing]# echo 0 > tracing_on
[root@172 tracing]# echo 0 > options/func_stack_trace
[root@172 tracing]# echo > set_ftrace_filter 
[root@172 tracing]# echo nop > current_tracer

        这次的输出明显更全面了,可以看出调用栈最顶层的入口是 entry_SYSCALL_64_after_hwframe 函数。完事还是要记得关闭。

2.3 函数的子调用

        知道了函数的调用栈,没发现问题,可能调用都是合理的,这时候可能想知道这个函数内部做了些什么事情,有没有异常,这时就用到了 function_graph 跟踪器。

[root@172 tracing]# echo _do_fork > set_graph_function
[root@172 tracing]# echo function_graph > current_tracer
[root@172 tracing]# echo 1 > tracing_on
[root@172 tracing]# cat trace | head -n 20
# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |0)               |  _do_fork() {0)               |    copy_process.part.34() {0)   0.116 us    |      _raw_spin_lock_irq();0)               |      recalc_sigpending() {0)   0.099 us    |        recalc_sigpending_tsk();0)   1.068 us    |      }0)   0.475 us    |      tsk_fork_get_node();0)               |      kmem_cache_alloc_node() {0)               |        _cond_resched() {0)   0.109 us    |          rcu_all_qs();0)   1.074 us    |        }0)   0.105 us    |        should_failslab();0)   1.143 us    |        memcg_kmem_get_cache();0)   0.109 us    |        memcg_kmem_put_cache();0)   6.998 us    |      }0)               |      __memcg_kmem_charge() {
[root@172 tracing]# echo 0 > tracing_on 
[root@172 tracing]# echo nop > current_tracer
[root@172 tracing]# echo > set_graph_function

        输出中的 DURATION 列表示执行耗时,FUNCTION 下的调用层级也很明显

3 事件跟踪

        available_events 描述了 ftrace 支持跟踪的所有事件,这也是内核提前定义的一批静态跟踪点:

[root@172 tracing]# cat available_events | grep "kill"
syscalls:sys_exit_tkill
syscalls:sys_enter_tkill
syscalls:sys_exit_tgkill
syscalls:sys_enter_tgkill
syscalls:sys_exit_kill
syscalls:sys_enter_kill
[root@172 tracing]# cat available_events | grep "tcp"
tcp:tcp_probe
tcp:tcp_retransmit_synack
tcp:tcp_rcv_space_adjust
tcp:tcp_destroy_sock
tcp:tcp_receive_reset
tcp:tcp_send_reset
tcp:tcp_retransmit_skb
[root@172 tracing]# cat available_events | grep "net:"
net:netif_rx_ni_entry
net:netif_rx_entry
net:netif_receive_skb_entry
net:napi_gro_receive_entry
net:napi_gro_frags_entry
net:netif_rx
net:netif_receive_skb
net:net_dev_queue
net:net_dev_xmit_timeout
net:net_dev_xmit
net:net_dev_start_xmit

        支持的事件种类也比较多,有 syscall、net、tcp、udp 等等。netif_receive_skb 用于处理内核从网卡收到的网络包,其主要对收到的 skb 进行校验然后交给 IP 层处理。通过下面的命令查看 netif_receive_skb 支持的选项:

[root@172 tracing]# ls events/net/netif_receive_skb
enable  filter  format  hist  id  trigger

         让我们跟踪一下 netif_receive_skb 这个事件:

[root@172 tracing]# echo 1 > events/net/netif_receive_skb/enable
[root@172 tracing]# echo 1 > tracing_on 
[root@172 tracing]# cat trace
# tracer: nop
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |<idle>-0     [000] ..s.  7835.671429: netif_receive_skb: dev=eth0 skbaddr=0000000073ef12d9 len=40<idle>-0     [000] ..s.  7836.593411: netif_receive_skb: dev=eth0 skbaddr=0000000073ef12d9 len=92<idle>-0     [000] ..s.  7836.638960: netif_receive_skb: dev=eth0 skbaddr=00000000b6a6098d len=40
[root@172 tracing]# echo 0 > tracing_on 
[root@172 tracing]# echo 0 > events/net/netif_receive_skb/enable

4 简化命令行工具

        你可能觉得 tracefs 每次跟踪都涉及多个文件的操作,这也太麻烦了。实际上,也有一个同样烦恼于此的小哥提供了更简单的命令,可以一次性配置好几个文件,也就是 trace-cmd

        例如可以通过这样的命令来跟踪函数的调用栈:

# 执行跟踪命令一段时间
[root@172 /]# trace-cmd record -p function -l '_do_fork' --func-stackplugin 'function'
Hit Ctrl^C to stop recording
^CCPU0 data recorded at offset=0x4bf0004096 bytes in size
[root@172 /]# 
# 查看跟踪结果
[root@172 /]# trace-cmd report
cpus=1bash-1662  [000]   333.965070: function:             _do_forkbash-1662  [000]   333.965096: kernel_stack:         <stack trace>
=> __this_module (ffffffffc062e061)
=> _do_fork (ffffffff942b02c5)
=> do_syscall_64 (ffffffff9420419b)
=> entry_SYSCALL_64_after_hwframe (ffffffff94c000ad)

         跟踪函数的子调用:

[root@172 /]# 
[root@172 /]# trace-cmd record -p function_graph -g '_do_fork'plugin 'function_graph'
Hit Ctrl^C to stop recording
^CCPU0 data recorded at offset=0x4bf000208896 bytes in size
[root@172 /]# trace-cmd report | head -n20
cpus=1bash-1662  [000]   641.179614: funcgraph_entry:                   |  _do_fork() {bash-1662  [000]   641.179629: funcgraph_entry:                   |    copy_process.part.34() {bash-1662  [000]   641.179629: funcgraph_entry:        0.030 us   |      _raw_spin_lock_irq();bash-1662  [000]   641.179630: funcgraph_entry:                   |      recalc_sigpending() {bash-1662  [000]   641.179630: funcgraph_entry:        0.034 us   |        recalc_sigpending_tsk();bash-1662  [000]   641.179630: funcgraph_exit:         0.268 us   |      }bash-1662  [000]   641.179630: funcgraph_entry:        0.123 us   |      tsk_fork_get_node();bash-1662  [000]   641.179631: funcgraph_entry:                   |      kmem_cache_alloc_node() {

        跟踪静态事件:

[root@172 /]# trace-cmd record -e net:netif_receive_skb
Hit Ctrl^C to stop recording
^CCPU0 data recorded at offset=0x4bf0004096 bytes in size
[root@172 /]# trace-cmd report
cpus=1<idle>-0     [000]   770.613285: netif_receive_skb:    dev=eth0 skbaddr=0xffff8b4078ce4b00 len=40<idle>-0     [000]   771.040836: netif_receive_skb:    dev=eth0 skbaddr=0xffff8b4078ce4b00 len=112<idle>-0     [000]   771.473463: netif_receive_skb:    dev=eth0 skbaddr=0xffff8b4078ce4d00 len=203

5 总结

        事件跟踪主要依赖于内核中定义的静态事件点,这些事件点可以理解为内核中的特定位置,当某些特定事件发生时,例如系统调用、中断处理或进程状态改变等,这些事件点就会被触发。通过 tracefs 文件系统,开发人员可以启用这些事件点,从而收集有关内核某些部分运行情况的数据。事件跟踪的一个显著特点是它可以设定跟踪条件,使得跟踪过程更加精细化和有针对性。

        相比之下,函数跟踪则更加关注于程序执行过程中的函数调用情况。在函数跟踪中,ftrace 会在指定的函数入口添加 trace 函数,从而记录函数的调用栈和相关信息。这种跟踪方式使得开发人员能够观察到函数是如何被调用的,以及它们在执行过程中的行为。函数跟踪的一个优势在于它可以轻松地过滤出需要关注的函数,从而避免被大量无关信息淹没。

        总结来说,事件跟踪和函数跟踪在 ftrace 中各有侧重。事件跟踪主要关注内核中特定事件的发生和变化,而函数跟踪则更侧重于程序执行过程中的函数调用情况。根据具体的调试需求,开发人员可以选择使用合适的跟踪机制来获取所需的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/743668.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp h5 部署

uniapp 配置 服务器文件路径 打包文件结构 //nginx 配置 server {listen 8300;server_name bfqcwebsiteapp;charset utf-8;#允许跨域请求的域&#xff0c;* 代表所有add_header Access-Control-Allow-Origin *;#允许带上cookie请求add_header Access-Control-Allow-C…

docker harbor.v2.9.2搭建镜像无法下载问题解决

在通过部署docker harbor时&#xff0c;采用的是离线包的方式&#xff0c;当解压压缩包后&#xff0c;执行prepare脚本步骤中有一步是要获取prepare:v2.9.2版本镜像 结果执行脚本时报如下错误&#xff1a; Unable to find image goharbor/prepare:v2.9.2 locally 这时候我们就…

算法思想总结:二分查找算法

创作不易&#xff0c;感谢三连&#xff01;&#xff01; 一、二分查找算法思路总结 大家先看总结&#xff0c;然后再根据后面的题型去慢慢领悟 二、二分查找&#xff08;easy&#xff09; . - 力扣&#xff08;LeetCode&#xff09;二分查找 思路&#xff1a;&#xff08;模…

每日学习笔记:C++ STL 的forward_list

定义 特点 操作函数 元素查找、移除或安插 forward_list::emplace_after arg...指的是元素构造函数的参数&#xff08;0~N个&#xff09; #include <iostream> #include <memory> #include <list> #include <forward_list> using namespace std;class…

海思3516将BT1120改BT656输出大小为720*576

sample_comm_vi.c结构体 VI_DEV_ATTR_S DEV_ATTR_BT656D1_1MUX VI_DEV_ATTR_S DEV_ATTR_BT656D1_1MUX {/* interface mode */VI_MODE_BT656,/* multiplex mode */VI_WORK_MODE_1Multiplex,/* r_mask g_mask b_mask*/{0xFF0000, 0x0},//掩码根据自己实际写/* progess…

基于YOLOv8深度学习的野外火焰烟雾检测系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战、目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

如何有效避免团队内耗,提升团队整体效能

团队内耗是一个普遍存在的问题&#xff0c;它可能导致工作效率低下、沟通不畅、成员间的信任缺失&#xff0c;甚至可能导致整个团队的崩溃。 它可能源于成员间的误解、利益冲突&#xff0c;或是个人情绪的波动。 如何避免团队内耗&#xff0c;是每个团队管理者和成员都应该关…

java组合模式揭秘:如何构建可扩展的树形结构

组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构以表示整体/部分层次结构。组合模式使得客户端可以统一对待单个对象和组合对象&#xff0c;从而使得客户端可以处理更复杂的结构。 组合模式的主要组成部分包括&…

人工智能|机器学习——BIRCH聚类算法(层次聚类)

这里再来看看另外一种常见的聚类算法BIRCH。BIRCH算法比较适合于数据量大&#xff0c;类别数K也比较多的情况。它运行速度很快&#xff0c;只需要单遍扫描数据集就能进行聚类。 1.什么是流形学习 BIRCH的全称是利用层次方法的平衡迭代规约和聚类&#xff08;Balanced Iterative…

Prompt Engineering(提示工程)

Prompt 工程简介 在近年来&#xff0c;大模型&#xff08;Large Model&#xff09;如GPT、BERT等在自然语言处理领域取得了巨大的成功。这些模型通过海量数据的训练&#xff0c;具备了强大的语言理解和生成能力。然而&#xff0c;要想充分发挥这些大模型的潜力&#xff0c;仅仅…

【计算机视觉】目标跟踪| 光流算法详细介绍|附代码

0、前言 在上篇文章中https://blog.csdn.net/Yaoyao2024/article/details/136625461?spm1001.2014.3001.5501&#xff0c;我们对目标跟踪任务和目标跟踪算法有了大致的了解。今天我们就来详细介绍一下其中的生成式算法的一种&#xff1a;光流法。 在介绍光流法之前&#xff…

SinoDB V16.8 版本新特性

1、Oracle兼容 兼容 with as 语法 兼容 insert all/first 语法 兼容 () 形式的左外连接和右外连接语法 兼容 ROLLUP/CUBE/GROUPING SETS 语法 兼容 create or replace view/trigger/procedure/function/index 语法 兼容 rename procedure/function 语法 2、新增功能 条…

IMX8MM -- Yocto构建遇见的错误及解决方法:

IMX8MM Yocto构建遇见的错误及解决方法&#xff1a; 1 bison-3.0.4 error2 Opencv BB_NO_NETWORK Error &#xff1a;3 Yocto构建时出现U-boot 问题4 Yocto构建时出现Linux kernel编译问题5 wayland-native6 cross-localedef-native7 wayland-protocols8 mesa 硬件&#xff1a;…

Linux网络配置修改hosts映射文件关闭防火墙

Linux网络配置&系统管理 一、物理机、VMware软件、虚拟机之间的网络关系1.1 总体框架图1.2 为什么物理机、VM软件、客户机之间能够通信?1.3 查看客户机的IP地址ifconfig1.4 小节1.5 修改静态IP地址1.6 测试能不能ping通 二、修改主机名以及hosts映射文件2.1 修改主机名2.1…

什么是事件冒泡?Littlevgl中的事件冒泡是怎么样的?

什么是事件冒泡?Littlevgl中的事件冒泡是怎么样的&#xff1f; 事件冒泡(Event Bubbling)是指当一个元素上的事件被触发时&#xff0c;该事件会从最底层的元素开始逐级向上传播&#xff0c;直到最顶层的元素(通常是文档对象)被触发。 ​ 例如我们点击一个按钮时&#xff0c;…

前后端分离项目环境搭建

1. 使用到的技术和工具 springboot vue项目的搭建 工具 idea&#xff0c;mavennodejs 2. 后端框架搭建 利用maven创建springboot项目 3. 前端项目搭建 1. 安装相关工具 nodejs&#xff1a; 一个开源、跨平台的 JavaScript 运行时环境&#xff0c;可以理解成java当中需要…

fly-gesture-unlock 手势解锁库

最近要实现前端九宫格手势解锁功能&#xff0c;到 github 和 gitee 上没有找到质量比较好的库&#xff0c;自己对这个功能也是蛮感兴趣的&#xff0c;所以做了这个开源库&#xff0c;用于实现手势解锁功能&#xff0c;可以帮助大家快速完成业务逻辑&#xff0c;提供了完整的 DE…

Prompt提示工程上手指南:基础原理及实践(二)-Prompt主流策略

前言 上篇文章将Prompt提示工程大体概念和具体工作流程阐述清楚了&#xff0c;我们知道Prompt工程是指人们向生成性人工智能&#xff08;AI&#xff09;服务输入提示以生成文本或图像的过程中&#xff0c;对这些提示进行精炼的过程。生成人工智能是一个根据人类和机器产生的数…

python基于flask考研学习交流系统30vy7附源码django

考研在线学习与交流平台根据实际情况分为前后台两部分&#xff0c;前台部分主要是让用户使用的&#xff0c;包括用户的注册登录&#xff0c;首页&#xff0c;课程信息&#xff0c;在线讨论&#xff0c;系统公告&#xff0c;后台管理&#xff0c;个人中心等功能&#xff1b;后台…

Mysql锁与MVCC

文章目录 Mysql锁的类型锁使用MVCC快照读和当前读读视图【Read View】串行化的解决 exlpain字段解析ACID的原理日志引擎整合SpringBoot博客记录 Mysql锁的类型 MySQL中有哪些锁&#xff1a; 乐观锁&#xff08;Optimistic Locking&#xff09;&#xff1a;假设并发操作时不会发…