使用 ftrace 跟踪 Linux 内核

大家好!我是大聪明-PLUS

跟踪是查找软件中的错误的一种有用技术,而ftrace是 Linux 内核内置的跟踪框架。

但在开始讨论 ftrace 之前,让我们先定义一下什么是跟踪。

什么是追踪?

跟踪是日志记录的一种特殊用途,用于记录有关程序执行流程的信息。

您知道什么时候在代码中添加打印消息来调试吗?您正在使用自己的"跟踪系统"跟踪应用程序。添加到代码中的调试消息是静态跟踪点,您的"跟踪系统"可能会将调试消息发送到程序的标准输出或日志文件。

嗯,这确实有效。但扩展性不好。每次你想跟踪代码的某个部分,你都必须添加新的调试消息并重新构建代码。而且你无法控制消息的去向。如果你想保存它们以便稍后分析怎么办?如果你想过滤消息怎么办?而且代码会变得一团糟,充斥着大量的打印语句(你必须非常小心,不要提交任何带有调试消息的代码,对吧?)。

事实上,大多数时候我们不需要在代码中添加调试消息,因为已经有跟踪工具和框架可以为我们做到这一点。

这就是 ftrace 的用武之地......

什么是 ftrace?

Ftrace是Linux内核的一个跟踪框架。它于2008年被添加到内核中,此后得到了长足的发展。

Ftrace 是函数跟踪器 的缩写,主要用于观察和记录内核函数的执行流程。它由 Steven Rostedt 创建,源自Ingo Molnar 的另外两个工具: latency tracer和 Steven 的 logdev实用程序。

使用 ftrace,您可以真正了解内核的运行情况。您可以跟踪函数调用,从而深入了解内核的工作原理。您可以找出运行用户空间应用程序时调用了哪些内核函数。您可以分析函数,测量执行时间,并找出瓶颈和性能问题。您可以识别内核空间中的挂起。您可以测量运行实时任务所需的时间,并找出延迟问题。您可以测量内核空间中的堆栈使用情况,并找出可能的堆栈溢出。您可以做很多事情来监控和查找内核中的错误!

黑魔法?或许有点儿像

但它是怎么运作的呢?

ftrace 如何工作?

跟踪主要有两种类型:静态跟踪和动态跟踪。

静态追踪是通过在源代码中添加静态探针来实现的。它们的处理负载较低,但追踪的代码有限,且是在构建时定义的。

动态追踪是通过在代码中注入动态探针来实现的,允许在运行时定义需要追踪的代码。它有一定的处理负载,但需要追踪的源代码范围要大得多。

Ftrace 结合使用静态探测(函数跟踪、事件跟踪等)和动态探测(kprobes、uprobes 等)。

为了跟踪函数调用,ftrace 将使用 GCC 的-pg选项构建内核。

当使用-pg构建内核时,GCC 会将机器指令添加到每个非内联函数的序言中,这些指令会将执行重定向到执行实际跟踪的 ftrace 的跳马和跟踪器插件。

下面的反汇编代码是gpiod_set_value 函数的开头部分。第 10 行对*__gnu_mcount_nc* 的调用是由 GCC 添加的,ftrace 将使用它来跟踪该函数(这与gprof用于分析用户空间应用程序的技术相同)。

|----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ` 1 2 3 4 5 6 7 8 9 10 11 12 ` | `$ arm-linux-gdb -q vmlinux Reading symbols from vmlinux...done. (gdb) disassemble /m gpiod_set_value Dump of assembler code for function gpiod_set_value: 3133 { 0xc03a83ac : mov r12, sp 0xc03a83b0 : push {r4, r5, r11, r12, lr, pc} 0xc03a83b4 : sub r11, r12, #4 0xc03a83b8 : push {lr} ; (str lr, [sp, #-4]!) 0xc03a83bc : bl 0xc001b420 0xc03a83c0 : mov r5, r1 0xc03a83c8 : mov r4, r0` |

Ftrace 还能够跟踪内核中的事件。

事件是开发人员添加的静态跟踪点,用于监视内核子系统,如调度程序、电源管理、中断、网络、gpio 等。只需在 Linux 内核源代码中搜索以*trace_*开头的函数,您就会发现几个使用跟踪事件的地方:

复制代码
`$ grep -R trace_ drivers/gpio/*
drivers/gpio/gpiolib.c: trace_gpio_direction(desc_to_gpio(desc), 1, status);
drivers/gpio/gpiolib.c: trace_gpio_value(desc_to_gpio(desc), 0, val);
drivers/gpio/gpiolib.c: trace_gpio_direction(desc_to_gpio(desc), 0, ret);
drivers/gpio/gpiolib.c: trace_gpio_value(desc_to_gpio(desc), 1, value);
drivers/gpio/gpiolib.c:                 trace_gpio_value(desc_to_gpio(desc), 1, value);
drivers/gpio/gpiolib.c: trace_gpio_direction(desc_to_gpio(desc), value, err);
drivers/gpio/gpiolib.c: trace_gpio_direction(desc_to_gpio(desc), !value, err);
drivers/gpio/gpiolib.c: trace_gpio_value(desc_to_gpio(desc), 0, value);
drivers/gpio/gpiolib.c:                 trace_gpio_value(desc_to_gpio(desc), 0, value);`

那么如何与 ftrace 交互呢?

当启用跟踪时,所有收集到的跟踪数据将由 ftrace 存储在内存中的环形缓冲区中。

有一个名为 tracefs 的虚拟文件系统(通常挂载在*/sys/kernel/tracing*中)用于配置 ftrace 并收集跟踪数据。所有操作都通过此目录中的简单文件操作完成。

这就是我喜欢 ftrace 的原因之一。由于跟踪系统的接口是文件系统,你可以使用echocat等简单工具来跟踪 Linux 内核!

那么如何使用它呢?

如何使用 ftrace?

首先,我们应该在 Linux 内核中启用 ftrace(CONFIG_FTRACE)以及我们计划使用的所有跟踪器和选项。这是内核版本 4.18 的 menuconfig 屏幕,其中启用了大多数 ftrace 选项:

启用 ftrace 后,我们可以挂载 tracefs 虚拟文件系统:

复制代码
`# mount -t tracefs tracefs /sys/kernel/tracing`

这是 ftrace 提供的文件系统接口:

复制代码
`# ls /sys/kernel/tracing/
README                      set_ftrace_filter
available_events            set_ftrace_notrace
available_filter_functions  set_ftrace_pid
available_tracers           set_graph_function
buffer_size_kb              set_graph_notrace
buffer_total_size_kb        snapshot
current_tracer              stack_max_size
dyn_ftrace_total_info       stack_trace
enabled_functions           stack_trace_filter
events                      timestamp_mode
free_buffer                 trace
function_profile_enabled    trace_clock
hwlat_detector              trace_marker
instances                   trace_marker_raw
max_graph_depth             trace_options
options                     trace_pipe
per_cpu                     trace_stat
printk_formats              tracing_cpumask
saved_cmdlines              tracing_max_latency
saved_cmdlines_size         tracing_on
saved_tgids                 tracing_thresh
set_event                   uprobe_events
set_event_pid               uprobe_profile`

我们可以打印可用跟踪器的列表:

复制代码
`# cat available_tracers
hwlat   blk      function_graph   wakeup_dl   wakeup_rt 
wakeup  irqsoff  function         nop`

有函数跟踪器(functionfunction_graph )、延迟跟踪器(wakeup_dlwakeup_rtirqsoffwakeuphwlat )、I/O 跟踪器(blk)等等!

要启用跟踪器,我们只需将其名称写入current_tracer

复制代码
`# echo function > current_tracer`

我们可以使用tracetrace_pipe文件读取跟踪缓冲区:

复制代码
`# cat trace
# tracer: function
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
          -0     [001] d...    23.695208: _raw_spin_lock_irqsave`
相关推荐
xx.ii2 小时前
43.shell脚本循环与函数
linux·运维·自动化
Kira Skyler2 小时前
抓虫:unshared后执行命令dump
linux
晨欣2 小时前
Umi-OCR:Windows7和Linux上可免费离线使用的OCR应用!
linux·运维·ocr
siriuuus3 小时前
Linux 网络配置解析、IP地址配置及常用网络命令
linux·网络
ZYMFZ3 小时前
Linux 防火墙 Iptables
linux·运维·服务器
口嗨农民工4 小时前
linux 时间相关的命令
linux·运维·服务器
evo-master5 小时前
网络编程-HTTP
linux·网络
轻松Ai享生活5 小时前
一文搞懂应用程序 core dump 和内核 core dump
linux
云飞云共享云桌面6 小时前
1台电脑10个画图设计用怎么实现
linux·运维·服务器·网络·数据库·自动化·电脑