用户空间调试建议

本文档简要概述了从用户空间调试 Linux 内核的常用工具。有关针对驱动程序开发人员的调试建议,请访问此处。有关一般调试建议,请参阅通用建议文档

以下部分向您展示可用的工具。

动态调试

通过禁用/启用日志消息来过滤最终进入内核日志的内容的机制。

前提条件:CONFIG_DYNAMIC_DEBUG

动态调试只能针对

  • pr_debug()

  • dev_dbg()

  • print_hex_dump_debug()

  • print_hex_dump_bytes()

因此,该工具的可用性目前相当有限,因为没有统一的规则将调试打印添加到代码库中,导致这些打印的实现方式多种多样。

另请注意,大多数调试语句都实现为 dprintk() 的变体,必须通过相应模块中的参数激活,动态调试无法为您执行该步骤。

这是一个示例,它启用了文件中所有可用的pr_debug()

$ alias ddcmd='echo $* > /proc/dynamic_debug/control'
$ ddcmd '-p; file v4l2-h264.c +p'
$ grep =p /proc/dynamic_debug/control
 drivers/media/v4l2-core/v4l2-h264.c:372 [v4l2_h264]print_ref_list_b =p
 "ref_pic_list_b%u (cur_poc %u%c) %s"
 drivers/media/v4l2-core/v4l2-h264.c:333 [v4l2_h264]print_ref_list_p =p
 "ref_pic_list_p (cur_poc %u%c) %s\n"

何时应该使用它而不是 Ftrace?

  • 当代码包含有效的打印语句之一(见上文)或当您在开发过程中添加了多个pr_debug()语句时

  • 当时间不是问题时,意味着如果代码中多个pr_debug()语句不会导致延迟

  • 当您更关心接收特定的日志消息而不是跟踪函数的调用模式时

有关完整文档,请参阅动态调试

Ftrace

前提条件:CONFIG_DYNAMIC_FTRACE

此工具使用 tracefs 文件系统进行控制文件和输出文件。该文件系统将以 tracing 目录挂载,该目录可以在 /sys/kernel//sys/debug/kernel/ 中找到。

一些最重要的调试操作是

  • 您可以通过将函数名称添加到 set_ftrace_filter 文件(该文件接受在 available_filter_functions 文件中找到的任何函数名称)来执行函数跟踪,或者您可以通过将它们的名称添加到 set_ftrace_notrace 文件来专门禁用某些函数(更多信息请访问:动态 ftrace)。

  • 为了找出调用的来源,您可以在 options/func_stack_trace 下激活 func_stack_trace 选项。

  • 通过在 set_graph_function 文件中添加所需的函数,可以跟踪函数调用的子项并显示返回值(需要配置 FUNCTION_GRAPH_RETVAL);更多信息请访问 带有函数图跟踪器的动态 ftrace

有关完整的 Ftrace 文档,请参阅ftrace - 函数跟踪器

或者,您还可以通过使用事件跟踪来跟踪特定事件,可以按照此处所述定义:创建自定义 Ftrace 跟踪点

有关完整的 Ftrace 事件跟踪文档,请参阅事件跟踪

读取 ftrace 日志

可以像读取任何其他文件一样读取 trace 文件(cattailheadvim 等),文件的大小受 buffer_size_kb 限制(echo 1000 > buffer_size_kb)。trace_pipe 的行为类似于 trace 文件,但是每当您从文件中读取内容时,内容都会被消耗。

Kernelshark

一个 GUI 界面,用于以图形和列表视图的形式可视化来自trace-cmd应用程序输出的跟踪。

有关完整文档,请参阅https://kernelshark.org/Documentation.html

Perf & 替代方案

上面提到的工具提供了检查内核代码、结果、变量值等的方法。有时您必须首先找出要查看的位置,对于这些情况,一系列性能跟踪工具可以帮助您确定问题。

为什么要进行性能分析?

当出现以下原因时,性能分析是一个很好的第一步:

  • 您无法定义问题

  • 您不知道它在哪里发生

  • 正在运行的系统不应中断,或者它是远程系统,您无法在其中安装新的模块/内核

如何使用 Linux 工具进行简单分析?

对于性能分析的开始,您可以从常用工具开始,例如

  • top / htop / atop获取系统负载的概述,查看特定进程的峰值

  • mpstat -P ALL查看 CPU 之间的负载分布

  • iostat -x观察输入和输出设备的利用率和性能

  • vmstat系统内存使用情况概述

  • pidstat类似于 vmstat ,但按进程,将其缩小到目标

  • strace -tp $PID一旦您知道该进程,您就可以找出它如何与内核通信

这些应该有助于充分缩小要查看的区域。

使用 perf 进行更深入的研究

perf 工具提供了一系列指标和事件,以进一步缩小问题范围。

前提条件:在您的系统上构建或安装 perf

收集统计数据,以查找 /usr 中所有以 gcc 开头的文件

# perf stat -d find /usr -name 'gcc*' | wc -l

 Performance counter stats for 'find /usr -name gcc*':

   1277.81 msec    task-clock             #    0.997 CPUs utilized
   9               context-switches       #    7.043 /sec
   1               cpu-migrations         #    0.783 /sec
   704             page-faults            #  550.943 /sec
   766548897       cycles                 #    0.600 GHz                         (97.15%)
   798285467       instructions           #    1.04  insn per cycle              (97.15%)
   57582731        branches               #   45.064 M/sec                       (2.85%)
   3842573         branch-misses          #    6.67% of all branches             (97.15%)
   281616097       L1-dcache-loads        #  220.390 M/sec                       (97.15%)
   4220975         L1-dcache-load-misses  #    1.50% of all L1-dcache accesses   (97.15%)
   <not supported> LLC-loads
   <not supported> LLC-load-misses

 1.281746009 seconds time elapsed

 0.508796000 seconds user
 0.773209000 seconds sys


52

事件和指标的可用性取决于您正在运行的系统。

有关完整文档,请参阅https://perf.wiki.kernel.org/index.php/Main_Page

Perfetto

一套用于测量和分析应用程序和系统性能的工具。你可以使用它来

  • 识别瓶颈

  • 优化代码

  • 使软件运行得更快更高效。

perfetto 和 perf 有什么区别?

  • perf 是 Linux 内核的一部分,并专门为 Linux 内核设计的工具,具有 CLI 用户界面。

  • perfetto 是跨平台的性能分析堆栈,其功能已扩展到用户空间,并提供 WEB 用户界面。

有关完整文档,请参阅 https://perfetto.dev/docs/

内核崩溃分析工具

要捕获崩溃转储,请使用 KdumpKexec。以下是一些分析数据的建议。

有关完整文档,请参阅 Kdump 文档 - 基于 kexec 的崩溃转储解决方案

为了在代码中找到相应的行,可以使用 faddr2line;请注意,你需要启用 CONFIG_DEBUG_INFO 才能使其工作。

使用 faddr2line 的替代方法是使用 objdump (及其针对不同平台的衍生版本,如 aarch64-linux-gnu-objdump)。以下面这行为例

[  +0.000240]  rkvdec_device_run+0x50/0x138 [rockchip_vdec].

我们可以通过执行以下操作来找到相应的代码行

aarch64-linux-gnu-objdump -dS drivers/staging/media/rkvdec/rockchip-vdec.ko | grep rkvdec_device_run\>: -A 40
0000000000000ac8 <rkvdec_device_run>:
 ac8:       d503201f        nop
 acc:       d503201f        nop
{
 ad0:       d503233f        paciasp
 ad4:       a9bd7bfd        stp     x29, x30, [sp, #-48]!
 ad8:       910003fd        mov     x29, sp
 adc:       a90153f3        stp     x19, x20, [sp, #16]
 ae0:       a9025bf5        stp     x21, x22, [sp, #32]
    const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc;
 ae4:       f9411814        ldr     x20, [x0, #560]
    struct rkvdec_dev *rkvdec = ctx->dev;
 ae8:       f9418015        ldr     x21, [x0, #768]
    if (WARN_ON(!desc))
 aec:       b4000654        cbz     x20, bb4 <rkvdec_device_run+0xec>
    ret = pm_runtime_resume_and_get(rkvdec->dev);
 af0:       f943d2b6        ldr     x22, [x21, #1952]
    ret = __pm_runtime_resume(dev, RPM_GET_PUT);
 af4:       aa0003f3        mov     x19, x0
 af8:       52800081        mov     w1, #0x4                        // #4
 afc:       aa1603e0        mov     x0, x22
 b00:       94000000        bl      0 <__pm_runtime_resume>
    if (ret < 0) {
 b04:       37f80340        tbnz    w0, #31, b6c <rkvdec_device_run+0xa4>
    dev_warn(rkvdec->dev, "Not good\n");
 b08:       f943d2a0        ldr     x0, [x21, #1952]
 b0c:       90000001        adrp    x1, 0 <rkvdec_try_ctrl-0x8>
 b10:       91000021        add     x1, x1, #0x0
 b14:       94000000        bl      0 <_dev_warn>
    *bad = 1;
 b18:       d2800001        mov     x1, #0x0                        // #0
 ...

意思是,在崩溃转储的这一行中

[  +0.000240]  rkvdec_device_run+0x50/0x138 [rockchip_vdec]

我可以将 0x50 作为偏移量,必须将其添加到相应函数的基本地址,我可以在这一行中找到该地址

0000000000000ac8 <rkvdec_device_run>:

0xac8 + 0x50 = 0xb18 的结果是。当我在函数中搜索该地址时,我得到以下行

*bad = 1;
b18:      d2800001        mov     x1, #0x0

版权所有 ©2024 : Collabora