linux性能工具--ftrace基础篇

我们做内核开发的时候,我们经常要去跟踪linux内核的函数调用关系,对于我们来说ftrace是一个十分好用的工具,值得我们好好学习。ftrace不只是一个函数跟踪工具,它的跟踪能力之强大,还能调试和分析诸如延迟、意外代码路径、性能问题等一大堆问题。它也是一种很好的学习工具。本章的主要是学习:

  • ftrace是什么
  • ftrace来解决什么问题

1 什么是ftrace

首先,在学习ftrace之前,我们要知道它是什么?根据linux ftrace的详细介绍,ftrace是一个linux内部的一个trace工具,用于帮助开发者和系统设计者知道内核当前正在干什么,从而更好的去分析性能问题。

1.1 ftrace的由来

ftrace是由Steven Rostedy和Ingo Molnar在内核2.6.27版本中引入的,那个时候,systemTap已经开始崭露头角,其它的trace工具包括LTTng等已经发展多年,那么为什么人们还需要开发一个trace工具呢?

SystemTap项目是 Linux 社区对 SUN Dtrace 的反应,目标是达到甚至超越 Dtrace 。因此 SystemTap 设计比较复杂,Dtrace 作为 SUN 公司的一个项目开发了多年才最终稳定发布,况且得到了 Solaris 内核中每个子系统开发人员的大力支持。 SystemTap 想要赶超 Dtrace,困难不仅是一样,而且更大,因此她始终处在不断完善自身的状态下,在真正的产品环境,人们依然无法放心的使用她。不当的使用和 SystemTap 自身的不完善都有可能导致系统崩溃。

Ftrace的设计目标简单,本质上是一种静态代码插装技术不需要支持某种编程接口让用户自定义 trace 行为。静态代码插装技术更加可靠,不会因为用户的不当使用而导致内核崩溃。 ftrace 代码量很小,稳定可靠。同时Ftrace 有重大的创新:

  • Ftrace 只需要在函数入口插入一个外部调用:mcount
  • Ftrace 巧妙的拦截了函数返回的地址,从而可以在运行时先跳到一个事先准备好的统一出口,记录各类信息,然后再返回原来的地址
  • Ftrace 在链接完成以后,把所有插入点地址都记录到一张表中,然后默认把所有插入点都替换成为空指令(nop),因此默认情况下 Ftrace 的开销几乎是 0
  • Ftrace 可以在运行时根据需要通过 Sysfs 接口使能和使用,即使在没有第三方工具的情况下也可以方便使用

1.2 ftrace 原理

ftrace的名字由function trace而来。function trace是利用gcc编译器在编译时在每个函数的入口地址放置一个probe点,这个probe点会调用一个probe函数(gcc默认调用名为mcount的函数),这样这个 probe函数会对每个执行的内核函数进行跟踪(其实有少数几个内核函数不会被跟踪),并打印log到一个内核中的环形缓存(ring buffer)中,而用户可以通过debugfs来访问这个环形缓存中的内容。

各类tracer往ftrace主框架注册,不同的trace则在不同的probe点把信息通过probe函数给送到ring buffer中,再由暴露在用户态debufs实现相关控制。其主要的框架图如下图所示

在这里插入图片描述

其主要由两部分构成

  • ftrace Framework core: 其主要包括利用 debugfs 系统在 /debugfs 下建立 tracing 目录,对用户空间输出 trace 信息,并提供了一系列的控制文件
  • 一系列的 tracer: 每个 tracer 完成不同的功能,ftrace 的 trace 信息保存在 ring buffer(内存缓冲区) 中,它们统一由 framework 管理

对于ftrace有两种主要的跟踪机制往缓冲区写数据

  • **动态探针:**可以动态跟踪内核函数的调用栈,包括function tracr,function graph trace两个tracer。其原理是利用mcount机制,在内核编译时,在每个函数入口保留数个字节,然后在使用ftrace时,将保留的字节替换为需要的指令,比如跳转到需要的执行探测操作的代码。
  • **静态探针:**是在内核代码中调用ftrace提供的相应接口实现,称之为静态是因为,是在内核代码中写死的,静态编译到内核代码中的,在内核编译后,就不能再动态修改。在开启ftrace相关的内核配置选项后,内核中已经在一些关键的地方设置了静态探测点,需要使用时,即可查看到相应的信息。

ftrace利用了gcc的profile特性,gcc 的 -pg 选项将在每个函数的入口处加入对mcount的代码调用。

在这里插入图片描述

如果ftrace编写了自己的mcount stub函数,则可借此实现trace功能。但是,在每个内核函数入口加入trace代码,必然影响内核的性能,为了减小对内核性能的影响,ftrace支持动态trace功能。
当COFNIG_DYNAMIC_FTRACE被选中后,内核编译时会调用recordmcount.pl脚本,将每个函数的地址写入一个特殊的段:__mcount_loc

2 ftrace 控制机制

要使用 ftrace,首先就是需要将系统的 debugfs 或者 tracefs 给挂载到某个地方,幸运的是,几乎所有的 Linux 发行版,都开启了 debugfs/tracefs 的支持,所以我们也没必要去重新编译内核了。

在比较老的内核版本,譬如 CentOS 7 的上面,debugfs 通常被挂载到 /sys/kernel/debug 上面(debug 目录下面有一个 tracing 目录),而比较新的内核,则是将 tracefs 挂载到 /sys/kernel/tracing,无论是什么,我都喜欢将 tracing 目录直接 link 到 /tracing。后面都会假设直接进入了 /tracing 目录,在讲解 ftrace 的 tracer 之前,我们先来看看 tracing 目录下的文件,它们提供了对 ftrace trace 过程的控制。

在这里插入图片描述

tracing 目录下的文件分成了下面四类:

  1. 提示类:显示当前系统可用的event,tracer 列表
  2. 控制类:控制 ftrace 的跟踪参数
  3. 显示类:显示 trace 信息
  4. 辅助类:一些不明或者不重要的辅助信息

2.1 提示类

ftrace文件作用
available_events可用事件列表,也可查看 events/ 目录
available_filter_functions当前内核导出的可以跟踪的函数
dyn_ftrace_total_info显示available_filter_functins中跟中函数的数目
available_tracers可用的 tracer,不同的 tracer 有不同的功能
events\1. 查看可用事件列表以及事件参数(事件包含的内核上下文信息)
cat events/sched/sched_switch/format
2.设置事件的过滤条件
echo ‘next_comm ~ “cs”‘ > events/sched/sched_switch/filter

2.2 控制类

使用tracerftrace文件作用
通用tracing_on用于控制跟踪打开或停止,0停止跟踪,1继续跟踪
通用tracing_cpumask设置允许跟踪特定CPU
通用tracing_max_latency记录Tracer的最大延时
通用tracing_thresh延时记录Trace的阈值,当延时超过此值时才开始记录Trace。单位是ms,只有非0才起作用
通用events1. 查看可用事件列表以及事件参数(事件包含的内核上下文信息)
cat events/sched/sched_switch/format
2.设置事件的过滤条件
echo ‘next_comm ~ “cs”‘ > events/sched/sched_switch/filter
通用set_event设置跟踪的 event 事件,与通过events目录内的 filter 文件设置一致
通用current_tracer1. 设置或者显示当前使用的跟踪器列表
2. 系统缺省为nop,可以通过写入nop重置跟踪器
3. 使用echo将跟踪器名字写入即可打开
echo function_graph > current_tracer
通用buffer_size_kb设置单个CPU所使用的跟踪缓存的大小
如果跟踪太多,旧的信息会被新的跟踪信息覆盖掉
不想被覆盖需要先将current_trace设置为nop才可以
通用buffer_total_size_kb显示所有CPU ring buffer 大小之和
通用trace_optionstrace 过程的复杂控制选项 控制Trace打印内容或者操作跟踪器 也可通过 options/目录设置
通用options/显示 trace_option 的设置结果
也可以直接设置,作用同 trace_options
funcfunction_profile_enabled打开此选项,trace_stat就会显示function的统计信息
echo 0/1 > function_profile_enabled
funcset_ftrace_pid设置跟踪的pid
funcset_ftrace_filter用于显示指定要跟踪的函数
funcset_ftrace_notrace用于指定不跟踪的函数,缺省为空
graphmax_graph_depth函数嵌套的最大深度
graphset_graph_function设置要清晰显示调用关系的函数
缺省对所有函数都生成调用关系
Stackstack_max_size当使用stack跟踪器时,记录产生过的最大stack size
Stackstack_trace显示stack的back trace
Stackstack_trace_filter设置stack tracer不检查的函数名称

2.3 输出类

ftrace 文件作用
printk_formats提供给工具读取原始格式trace的文件
trace查看 ring buffer 内跟踪信息
echo > trace可以清空当前RingBuffer
trace_pipe输出和trace一样的内容,但输出Trace同时将RingBuffer清空
可避免RingBuffer的溢出
保存文件内容: cat trace_pipe > trace.txt &
snapshot是对trace的snapshot
echo 0清空缓存,并释放对应内存
echo 1进行对当前trace进行snapshot,如没有内存则分配
echo 2清空缓存,不释放也不分配内存
trace_clock显示当前Trace的timestamp所基于的时钟,默认使用local时钟
local:默认时钟;可能无法在不同CPU间同步
global:不同CUP间同步,但是可能比local慢
counter:跨CPU计数器,需要分析不同CPU间event顺序比较有效
trace_marker从用户空间写入标记到trace中,用于用户空间行为和内核时间同步
trace_stat每个CPU的Trace统计信息
per_cpu/trace等文件的输出是综合所有CPU的,如果你关心单个CPU可以进入per_cpu目录,里面有这些文件的分CPU版本
enabled_functions显示有回调附着的函数名称
saved_cmdlines放pid对应的comm名称作为ftrace的cache,这样ftrace中不光能显示pid还能显示comm
saved_cmdlines_sizesaved_cmdlines的数目

3 ftrace的基础用法

3.1 内核配置

ftrace 提供了不同的跟踪器,以用于不同的场合,比如跟踪内核函数调用、对上下文切换进行跟踪、查看中断被关闭的时长、跟踪内核态中的延迟以及性能问题等。

系统开发人员可以使用 ftrace 对内核进行跟踪调试,以找到内核中出现的问题的根源,方便对其进行修复。

使用 ftrace ,首先要将其编译进内核,内核源码目录下的 kernel/trace/Makefile 文件给出了 ftrace 相关的编译选项

CONFIG_FTRACE=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_FUNCTION_TRACER=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_SCHED_TRACER=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_PREEMPT_TRACER=y

    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.2 ftrace三板斧

  1. 设置 tracer 类型
  2. 设置 tracer 参数
  3. 使能 tracer

4 总结

Ftrace 由 RedHat 的 Steve Rostedt 负责维护。到 2.6.30 为止,ftrace 提供了不同的跟踪器,以用于不同的场合,比如跟踪内核函数调用、对上下文切换进行跟踪、查看中断被关闭的时长、跟踪内核态中的延迟以及性能问题等。

功能功能描述
Function tracer Function graph tracer跟踪函数调用
Schedule switch tracer跟踪进程调度情况
Wakeup tracer跟踪进程的调度延迟,即高优先级进程从进入 ready 状态到获得 CPU 的延迟时间。该 tracer 只针对实时进程。
Irqsoff tracer当中断被禁止时,系统无法相应外部事件,比如键盘和鼠标,时钟也无法产生 tick 中断。这意味着系统响应延迟,irqsoff 这个 tracer 能够跟踪并记录内核中哪些函数禁止了中断,对于其中中断禁止时间最长的,irqsoff 将在 log 文件的第一行标示出来,从而使开发人员可以迅速定位造成响应延迟的罪魁祸首
Preemptoff tracer和前一个 tracer 类似,preemptoff tracer 跟踪并记录禁止内核抢占的函数,并清晰地显示出禁止抢占时间最长的内核函数。
Preemptirqsoff tracer同上,跟踪和记录禁止中断或者禁止抢占的内核函数,以及禁止时间最长的函数
Branch tracer跟踪内核程序中的 likely/unlikely 分支预测命中率情况。 Branch tracer 能够记录这些分支语句有多少次预测成功。从而为优化程序提供线索。
Hardware branch tracer利用处理器的分支跟踪能力,实现硬件级别的指令跳转记录。在 x86 上,主要利用了 BTS 这个特性。
Initcall tracer记录系统在 boot 阶段所调用的 init call
Mmiotrace tracer记录 memory map IO 的相关信息
Power tracer记录系统电源管理相关的信息
Sysprof tracer缺省情况下,sysprof tracer 每隔 1 msec 对内核进行一次采样,记录函数调用和堆栈信息
Kernel memory tracer内存 tracer 主要用来跟踪 slab allocator 的分配情况。包括 kfree,kmem_cache_alloc 等 API 的调用情况,用户程序可以根据 tracer 收集到的信息分析内部碎片情况,找出内存分配最频繁的代码片断,等等。
Workqueue statistical tracer这是一个 statistic tracer,统计系统中所有的 workqueue 的工作情况,比如有多少个 work 被插入 workqueue,多少个已经被执行等。开发人员可以以此来决定具体的 workqueue 实现,比如是使用
Event tracer跟踪系统事件,比如 timer,系统调用,中断等

在这里插入图片描述

Ftrace 的实现依赖于其他很多内核特性,比如 tracepoint[3],debugfs[2],kprobe[4],IRQ-Flags[5] 等

5 参考文档

https://hotttao.github.io/2020/01/03/linux_perf/03_ftrace/

http://tinylab.org/ftrace-principle-and-practice/

https://www.cnblogs.com/arnoldlu/p/7211249.html

在Linux下做性能分析2:ftrace

文章知识点与官方知识档案匹配,可进一步学习相关知识
CS入门技能树Linux入门初识Linux 31425 人正在系统学习中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值