https://linux.cn/article-9273-1.html

https://lwn.net/Articles/365835/

Documentation/trace/events.txt

trace/ftrace-design.txt

什么是 ftrace?

ftrace 是一个 Linux 内核特性,它可以让你去跟踪 Linux 内核的函数调用。为什么要这么做呢?好吧,假设你调试一个奇怪的问题,而你已经得到了你的内核版本中这个问题在源代码中的开始的位置,而你想知道这里到底发生了什么?

每次在调试的时候,我并不会经常去读内核源代码,但是,极个别的情况下会去读它!例如,本周在工作中,我有一个程序在内核中卡死了。查看到底是调用了什么函数,能够帮我更好的理解在内核中发生了什么,哪些系统涉及其中!(在我的那个案例中,它是虚拟内存系统)。

我认为 ftrace 是一个十分好用的工具(它肯定没有 strace 那样使用广泛,也比它难以使用),但是它还是值得你去学习。因此,让我们开始吧!

使用 ftrace 的第一步

不像 strace 和 perf,ftrace 并不是真正的 程序 – 你不能只运行 ftrace my_cool_function。那样太容易了!

如果你去读 使用 ftrace 调试内核,它会告诉你从 cd /sys/kernel/debug/tracing 开始,然后做很多文件系统的操作。

对于我来说,这种办法太麻烦——一个使用 ftrace 的简单例子像是这样:

  

cd /sys/kernel/debug/tracing
echo function > current_tracer
echo do_page_fault > set_ftrace_filter
cat trace

这个文件系统是跟踪系统的接口(“给这些神奇的文件赋值,然后该发生的事情就会发生”)理论上看起来似乎可用,但是它不是我的首选方式。

幸运的是,ftrace 团队也考虑到这个并不友好的用户界面,因此,它有了一个更易于使用的界面,它就是 trace-cmd!!!trace-cmd 是一个带命令行参数的普通程序。我们后面将使用它!我在 LWN 上找到了一个 trace-cmd 的使用介绍:trace-cmd: Ftrace 的一个前端

开始使用 trace-cmd:让我们仅跟踪一个函数

首先,我需要去使用 sudo apt-get install trace-cmd 安装 trace-cmd,这一步很容易。

对于第一个 ftrace 的演示,我决定去了解我的内核如何去处理一个页面故障。当 Linux 分配内存时,它经常偷懒,(“你并不是真的计划去使用内存,对吗?”)。这意味着,当一个应用程序尝试去对分配给它的内存进行写入时,就会发生一个页面故障,而这个时候,内核才会真正的为应用程序去分配物理内存。

我们开始使用 trace-cmd 并让它跟踪 do_page_fault 函数!

$ sudo trace-cmd record -p function -l do_page_fault
plugin 'function'
Hit Ctrl^C to stop recording

我将它运行了几秒钟,然后按下了 Ctrl+C。 让我大吃一惊的是,它竟然产生了一个 2.5MB 大小的名为 trace.dat 的跟踪文件。我们来看一下这个文件的内容!

$ sudo trace-cmd report
chrome-15144 [000] 11446.466121: function: do_page_fault
chrome-15144 [000] 11446.467910: function: do_page_fault
chrome-15144 [000] 11446.469174: function: do_page_fault
chrome-15144 [000] 11446.474225: function: do_page_fault
chrome-15144 [000] 11446.474386: function: do_page_fault
chrome-15144 [000] 11446.478768: function: do_page_fault
CompositorTileW-15154 [001] 11446.480172: function: do_page_fault
chrome-1830 [003] 11446.486696: function: do_page_fault
CompositorTileW-15154 [001] 11446.488983: function: do_page_fault
CompositorTileW-15154 [001] 11446.489034: function: do_page_fault
CompositorTileW-15154 [001] 11446.489045: function: do_page_fault

看起来很整洁 – 它展示了进程名(chrome)、进程 ID(15144)、CPU ID(000),以及它跟踪的函数。

通过察看整个文件,(sudo trace-cmd report | grep chrome)可以看到,我们跟踪了大约 1.5 秒,在这 1.5 秒的时间段内,Chrome 发生了大约 500 个页面故障。真是太酷了!这就是我们做的第一个 ftrace!

下一个 ftrace 技巧:我们来跟踪一个进程!

好吧,只看一个函数是有点无聊!假如我想知道一个程序中都发生了什么事情。我使用一个名为 Hugo 的静态站点生成器。看看内核为 Hugo 都做了些什么事情?

在我的电脑上 Hugo 的 PID 现在是 25314,因此,我使用如下的命令去记录所有的内核函数:

sudo trace-cmd record --help # I read the help!
sudo trace-cmd record -p function -P 25314 # record for PID 25314

sudo trace-cmd report 输出了 18,000 行。如果你对这些感兴趣,你可以看 这里是所有的 18,000 行的输出

18,000 行太多了,因此,在这里仅摘录其中几行。

当系统调用 clock_gettime 运行的时候,都发生了什么:

compat_SyS_clock_gettime
SyS_clock_gettime
clockid_to_kclock
posix_clock_realtime_get
getnstimeofday64
__getnstimeofday64
arch_counter_read
__compat_put_timespec

这是与进程调试相关的一些东西:

cpufreq_sched_irq_work
wake_up_process
try_to_wake_up
_raw_spin_lock_irqsave
do_raw_spin_lock
_raw_spin_lock
do_raw_spin_lock
walt_ktime_clock
ktime_get
arch_counter_read
walt_update_task_ravg
exiting_task

虽然你可能还不理解它们是做什么的,但是,能够看到所有的这些函数调用也是件很酷的事情。

“function graph” 跟踪

这里有另外一个模式,称为 function_graph。除了它既可以进入也可以退出一个函数外,其它的功能和函数跟踪器是一样的。这里是那个跟踪器的输出

  1. sudo trace-cmd record -p function_graph -P 25314

同样,这里只是一个片断(这次来自 futex 代码):

 futex_wake() {
| get_futex_key() {
| get_user_pages_fast() {
1.458 us | __get_user_pages_fast();
4.375 us | }
| __might_sleep() {
0.292 us | ___might_sleep();
2.333 us | }
0.584 us | get_futex_key_refs();
| unlock_page() {
0.291 us | page_waitqueue();
0.583 us | __wake_up_bit();
5.250 us | }
0.583 us | put_page();
+ 24.208 us | }

我们看到在这个示例中,在 futex_wake 后面调用了 get_futex_key。这是在源代码中真实发生的事情吗?我们可以检查一下!!这里是在 Linux 4.4 中 futex_wake 的定义 (我的内核版本是 4.4)。

为节省时间我直接贴出来,它的内容如下:

  1. static int
    futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
    {
    struct futex_hash_bucket *hb;
    struct futex_q *this, *next;
    union futex_key key = FUTEX_KEY_INIT;
    int ret;
    WAKE_Q(wake_q);
    if (!bitset)
    return -EINVAL;
    ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);

如你所见,在 futex_wake 中的第一个函数调用真的是 get_futex_key! 太棒了!相比阅读内核代码,阅读函数跟踪肯定是更容易的找到结果的办法,并且让人高兴的是,还能看到所有的函数用了多长时间。

如何知道哪些函数可以被跟踪

如果你去运行 sudo trace-cmd list -f,你将得到一个你可以跟踪的函数的列表。它很简单但是也很重要。

最后一件事:事件!

现在,我们已经知道了怎么去跟踪内核中的函数,真是太酷了!

还有一类我们可以跟踪的东西!有些事件与我们的函数调用并不相符。例如,你可能想知道当一个程序被调度进入或者离开 CPU 时,都发生了什么事件!你可能想通过“盯着”函数调用计算出来,但是,我告诉你,不可行!

由于函数也为你提供了几种事件,因此,你可以看到当重要的事件发生时,都发生了什么事情。你可以使用 sudo cat /sys/kernel/debug/tracing/available_events 来查看这些事件的一个列表。

我查看了全部的 schedswitch 事件。我并不完全知道 schedswitch 是什么,但是,我猜测它与调度有关。

  1. sudo cat /sys/kernel/debug/tracing/available_events
    sudo trace-cmd record -e sched:sched_switch
    sudo trace-cmd report

输出如下:

  1. 16169.624862: Chrome_ChildIOT:24817 [112] S ==> chrome:15144 [120]
    16169.624992: chrome:15144 [120] S ==> swapper/3:0 [120]
    16169.625202: swapper/3:0 [120] R ==> Chrome_ChildIOT:24817 [112]
    16169.625251: Chrome_ChildIOT:24817 [112] R ==> chrome:1561 [112]
    16169.625437: chrome:1561 [112] S ==> chrome:15144 [120]

    现在,可以很清楚地看到这些切换,从 PID 24817 -> 15144 -> kernel -> 24817 -> 1561 -> 15114。(所有的这些事件都发生在同一个 CPU 上)。

ftrace 是如何工作的?

ftrace 是一个动态跟踪系统。当我们开始 ftrace 内核函数时,函数的代码会被改变。让我们假设去跟踪 do_page_fault 函数。内核将在那个函数的汇编代码中插入一些额外的指令,以便每次该函数被调用时去提示跟踪系统。内核之所以能够添加额外的指令的原因是,Linux 将额外的几个 NOP 指令编译进每个函数中,因此,当需要的时候,这里有添加跟踪代码的地方。

这是一个十分复杂的问题,因为,当不需要使用 ftrace 去跟踪我的内核时,它根本就不影响性能。而当我需要跟踪时,跟踪的函数越多,产生的开销就越大。

(或许有些是不对的,但是,我认为的 ftrace 就是这样工作的)

更容易地使用 ftrace:brendan gregg 的工具及 kernelshark

正如我们在文件中所讨论的,你需要去考虑很多的关于单个的内核函数/事件直接使用 ftrace 都做了些什么。能够做到这一点很酷!但是也需要做大量的工作!

Brendan Gregg (我们的 Linux 调试工具“大神”)有个工具仓库,它使用 ftrace 去提供关于像 I/O 延迟这样的各种事情的信息。这是它在 GitHub 上全部的 perf-tools 仓库。

这里有一个权衡,那就是这些工具易于使用,但是你被限制仅能用于 Brendan Gregg 认可并做到工具里面的方面。它包括了很多方面!:)

另一个工具是将 ftrace 的输出可视化,做的比较好的是 kernelshark。我还没有用过它,但是看起来似乎很有用。你可以使用 sudo apt-get install kernelshark 来安装它。

工具博客转载-ftrace的更多相关文章

  1. java三篇博客转载 详解-vector,stack,queue,deque

    博客一:转载自http://shmilyaw-hotmail-com.iteye.com/blog/1825171 java stack的详细实现分析 简介 我们最常用的数据结构之一大概就是stack ...

  2. Latex博客转载

    \[{e^{ix}=cosx+isinx} \] \[[博客地址](https://www.cnblogs.com/Sinte-Beuve/p/6160905.html) \]

  3. 几篇不错的基础css博客转载

    CSS 巧用 :before和:after:http://web.jobbole.com/85083/ css清除元素间距:http://ouvens.github.io/frontend-css/2 ...

  4. c++博客转载

    C++ 中文件流(fstream)的使用方法及示例 http://blog.jobbole.com/108649/ qt中文乱码问题: https://blog.csdn.net/brave_hear ...

  5. 请允许我转载一篇关于套接字的博客:Socket

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  6. 一文搭建自己博客/文档系统:搭建,自动编译和部署,域名,HTTPS,备案等

    本文纯原创,搭建后的博客/文档网站可以参考: Java 全栈知识体系.如需转载请说明原处. 第一部分 - 博客/文档系统的搭建 搭建博客有很多选择,平台性的比如: 知名的CSDN, 博客园, 知乎,简 ...

  7. BIT祝威博客汇总(Blog Index)

    +BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...

  8. 微信小程序初见+nodejs服务端 (一个简单的博客)

    推荐网址: 腾讯云快速开发(nodejs前后端):https://developers.weixin.qq.com/miniprogram/dev/qcloud/qcloud.html#%E5%AF% ...

  9. 转载请注明:Windows 系统必备好用软件&工具合集跟推荐 | 老D博客

    Windows 系统必备好用软件&工具合集跟推荐 97 63,371 A+ 所属分类:工具软件 一.浏览器 二.下载软件 三.播放软件 五.电子邮件客户端 六.图片/照片 浏览查看工具 七.文 ...

随机推荐

  1. Linux设备驱动中的阻塞和非阻塞I/O <转载>

    Green 博客园 首页 新随笔 联系 订阅 管理 Linux设备驱动中的阻塞和非阻塞I/O   [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件 ...

  2. 多测师讲解pythonl _字符,列表,元组,字典,集合,归纳_高级讲师肖sir

  3. Linux最常用的命令大全

    Linux最常用的命令大全 按功能索引 目录处理命令 ls mkdir pwd cd rmdir cp mv rm 文件处理命令 touch cat tac more less head tail l ...

  4. 营口6378.7939(薇)xiaojie:营口哪里有xiaomei

    营口哪里有小姐服务大保健[微信:6378.7939倩儿小妹[营口叫小姐服务√o服务微信:6378.7939倩儿小妹[营口叫小姐服务][十微信:6378.7939倩儿小妹][营口叫小姐包夜服务][十微信 ...

  5. Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象. 但是,对于不同行业,对于同步的理解略有不同.比如:设备同步,是指在两个设备之间规定一个共同的时间参考:数据 ...

  6. spring boot:基于profile的多环境配置(spring boot 2.3.4)

    一,为什么要进行多环境配置? 1,没有人会在生产环境中进行开发和测试, 所以通常会有多个环境的划分: 工程师本地的开发环境 进行测试的测试环境 最终上线的生产环境 每个环境对应不同的数据库/缓存等数据 ...

  7. mysql锁 转

    参考文章:https://blog.csdn.net/puhaiyang/article/details/72284702 一.mysql锁的结构图 如上图所示,针对mysql的innodb存储引擎, ...

  8. linux(centos8):禁用selinux(临时关闭/永久关闭)

    一,selinux的用途 1,什么是selinux SELinux:即安全增强型 Linux(Security-Enhanced Linux) 它是一个 Linux 内核模块,也是 Linux 的一个 ...

  9. selenium自动登陆

    import osfrom selenium import webdriverimport time,jsonclass Cookie(object): def __init__(self,drive ...

  10. STM32芯片型号的命名规则

    意法半导体已经推出STM32基本型系列.增强型系列.USB基本型系列.增强型系列:新系列产品沿用增强型系列的72MHz处理频率.内存包括64KB到256KB闪存和20KB到64KB嵌入式SRAM.新系 ...