“Ftrace”的版本间的差异

来自百问网嵌入式Linux wiki
 
标签visualeditor-switched
 
第1行: 第1行:
 +
 +
=Ftrace=
 +
==文章目的==
 +
: 本文提供了开始使用Linux内核工具所需的基本信息:ftrace [1 ]。
 +
 +
==简介==
 +
: 下表简要介绍了该工具及其可用性,具体取决于软件包:
 +
* 是:该工具已经存在(可以使用或激活),也可以在软件包中集成和激活。
 +
* 没有:该工具不存在且无法集成,或者存在但无法在软件包中激活。
 +
{| class="wikitable"
 +
!colspan="3" | 工具
 +
|-
 +
| 名称
 +
| 类别
 +
| 目的
 +
|-
 +
|ftrace
 +
|追踪工具
 +
|ftrace [1 ](函数跟踪程序)是功能强大的内核跟踪实用程序,例如,它可以跟踪每个内核函数调用和内核事件,而无需在内核源代码中添加任何额外的代码 没有 没有 是 没有 没有 是
 +
|-
 +
!colspan="3" | STM32MPU嵌入式软件发行版
 +
|-
 +
| 入门资料包
 +
| 开发者资料包
 +
| 发行版资料包
 +
|-
 +
|没有
 +
|没有
 +
|是
 +
|-
 +
!colspan="3" | 适用于 Android 的STM32MPU嵌入式软件发行版
 +
|-
 +
| 入门资料包
 +
| 开发者资料包
 +
| 发行版资料包
 +
|-
 +
|没有
 +
|没有
 +
|是
 +
|}
 +
 +
: 注意:在Linux内核4.1之前,所有ftrace跟踪控制文件都在debugfs文件系统中,该文件系统通常位于 /sys/kernel/debug/tracing 中。现在,它位于/ sys/kernel/tracing中,并且独立于debugfs。
 +
: 为了向后兼容,在安装 debugfs 文件系统时,tracefs 文件系统会自动安装在: /sys/kernel/debug/tracing.。
 +
 +
: 位于tracefs文件系统中的所有文件也位于该debugfs文件系统目录中。
 +
 +
: {{redtext|请注意,符号表中存在的所有函数都可用于ftrace。要知道符号列表中是否有可用的函数,可以使用命令 "nm vmlinux | grep <function_name>"}}
 +
 +
==在目标板上安装跟踪和调试工具==
 +
: ftrace是一项内核功能,在OpenSTLinux发行版中默认情况下未启用,因为这会影响Linux内核大小(vmlinux大约增加1.5%),并且还会对整体性能产生影响,因为其触发了跟踪内核事件和函数调用。
 +
: 为了使用ftrace所需的“内核功能跟踪程序” ,Linux内核配置必须使用Linux内核menuconfig工具激活 CONFIG_FUNCTION_TRACER 和 CONFIG_FUNCTION_GRAPH_TRACER 配置:
 +
<syntaxhighlight lang="bash">
 +
Symbol: FUNCTION_TRACER
 +
Location:
 +
  Kernel Hacking --->
 +
    Tracers -->
 +
      [*] Kernel Function Tracer
 +
 +
Symbol: FUNCTION_GRAPH_TRACER
 +
Location:
 +
  Kernel Hacking --->
 +
    Tracers -->
 +
      [*] Kernel Function Tracer
 +
      [*] Kernel Function Graph Tracer
 +
</syntaxhighlight>
 +
 +
===使用STM32MPU嵌入式软件发行版===
 +
====开发人员软件包====
 +
: 不建议使用Developer Package启用ftrace内核配置,因为所有外部模块需要重新编译(例如GPU STM32MP1的gcnano驱动程序),而Developer Package则无法实现,因为它不需要提供所有资料来源。
 +
: 这就是为什么将此设置为“开发人员包”不支持的原因。
 +
 +
====分发包====
 +
: 启用所需的Linux内核配置
 +
: 要在Linux内核配置中启用CONFIG_FUNCTION_TRACER和CONFIG_FUNCTION_GRAPH_TRACER,请参阅 [https://wiki.st.com/stm32mpu/wiki/Menuconfig_or_how_to_configure_kernel Menuconfig或如何配置内核] 一文,以获取有关在Distribution Package上下文中修改配置和重新编译Linux内核镜像的说明。
 +
: 还必须重新编译不属于Linux内核源代码树的外部Linux内核模块(如果存在)。
 +
: GPU STM32MP1的gcnano驱动程序示例:
 +
<syntaxhighlight lang="bash">
 +
PC $> bitbake gcnano-driver-stm32mp
 +
</syntaxhighlight>
 +
 +
: 重新构建完整的OpenSTLinux镜像,以便重新编译所有依赖项并具有正确的rootfs(包括外部Linux内核模块)
 +
<syntaxhighlight lang="bash">
 +
PC $> bitbake st-image-weston
 +
</syntaxhighlight>
 +
 +
: 注意:如前所述,启用ftrace配置时,未压缩的Linux内核镜像的大小会增加。
 +
: 根据目标板的内存配置(在设备树中定义),内核镜像的增加可能与放置在其后的某些保留区域重叠。
 +
: 在这种情况下,突出显示了编译错误。
 +
: 如果此重叠影响很小(意味着某些功能不再起作用,但并不关键),则可以通过使用Linux内核Menuconfig工具(Menuconfig或如何配置内核)激活Linux内核配置CONFIG_SECTION_MISMATCH_WARN_ONLY来避免编译错误。)
 +
<syntaxhighlight lang="bash">
 +
Symbol: SECTION_MISMATCH_WARN_ONLY
 +
Location:
 +
  Kernel Hacking --->
 +
    Compile-time checks and compiler options -->
 +
      [*] Make section mismatch errors non-fatal
 +
</syntaxhighlight>
 +
 +
===使用适用于 Android 的 STM32MPU 嵌入式软件发行版===
 +
====分发包====
 +
: 启用所需的Linux内核配置
 +
: 要在Linux内核配置中启用CONFIG_FUNCTION_TRACER和CONFIG_FUNCTION_GRAPH_TRACER,请参阅[https://wiki.st.com/stm32mpu/wiki/How_to_customize_kernel_for_Android 如何为Android定制内核] 一文,以获取有关修改配置的说明
 +
: 在Android分发包中重新编译Linux内核镜像和模块。
 +
<syntaxhighlight lang="bash">
 +
PC $> build_kernel vmlinux -i
 +
PC $> build_kernel modules -i
 +
</syntaxhighlight>
 +
 +
: 还必须重新编译不属于Linux内核源代码树的外部Linux内核模块(如果存在的话)。
 +
GPU STM32MP1的gcnano驱动程序示例:
 +
<syntaxhighlight lang="bash">
 +
PC $> build_kernel gpu -i
 +
</syntaxhighlight>
 +
 +
: 重建完整的Android镜像,以便重新编译所有依赖关系并考虑Linux内核镜像和模块的新的预构建镜像:
 +
<syntaxhighlight lang="bash">
 +
PC $> make -j
 +
</syntaxhighlight>
 +
 +
: 注意:如前所述,启用ftrace配置时,未压缩的Linux内核镜像的大小会增加。
 +
: 根据目标板的内存配置(在设备树中定义),内核镜像的增加可能会覆盖后面放置的一些保留区域。
 +
: 在这种情况下,突出显示了编译错误。
 +
: 如果此重叠影响很小(意味着某些功能不再起作用,但并不关键),则可以通过使用Linux内核Menuconfig工具激活Linux内核配置CONFIG_SECTION_MISMATCH_WARN_ONLY来绕过编译错误(如何为Android定制内核))
 +
<syntaxhighlight lang="bash">
 +
Symbol: SECTION_MISMATCH_WARN_ONLY
 +
Location:
 +
  Kernel Hacking --->
 +
    Compile-time checks and compiler options -->
 +
      [*] Make section mismatch errors non-fatal
 +
</syntaxhighlight>
 +
 +
==使用入门==
 +
===在运行时使用ftrace===
 +
: 首先,你需要从目标启用/激活 ftrace 功能。
 +
 +
: 目标启动并登录后,安装 tracefs:
 +
<syntaxhighlight lang="bash">
 +
Board $> mount -t tracefs nodev /sys/kernel/tracing
 +
</syntaxhighlight>
 +
 +
: 注意:以下信息与 Android 发行版有关
 +
:: 需要启用root访问权限
 +
:: 使用ADB Shell可以使用ADB链接:
 +
<syntaxhighlight lang="bash">
 +
PC $> adb root
 +
PC $> adb shell
 +
Board $> ...
 +
</syntaxhighlight>
 +
:: 使用UART控制台shell:
 +
<syntaxhighlight lang="bash">
 +
Board $> su
 +
Board $> ...
 +
</syntaxhighlight>
 +
 +
: 在那一步,所有的"ftrace”功能都发生在文件系统目录路径 /sys/kernel/tracing 中。
 +
: 要找出可用的跟踪器,只需在跟踪目录中放置 available_tracers 文件即可:
 +
<syntaxhighlight lang="bash">
 +
Board $> cat /sys/kernel/tracing/available_tracers
 +
function_graph function nop
 +
</syntaxhighlight>
 +
 +
: 内核构建配置可以添加更多的跟踪器。请参阅 深入学习 一节。
 +
 +
===过滤器选项===
 +
: 注意:{{redtext|ftrace使用函数/ graph_function过滤器,而不是驱动程序过滤器。因此,跟踪* myDriver *函数不会从myDriver跟踪myHelper函数。}}
 +
: 你可以使用以下命令获取可用的过滤器功能的列表:
 +
<syntaxhighlight lang="bash">
 +
Board $> cat /sys/kernel/tracing/available_filter_functions
 +
</syntaxhighlight>
 +
 +
====功能跟踪器模式====
 +
: 开始跟踪会话
 +
<syntaxhighlight lang="bash">
 +
Board $> echo 1 > /sys/kernel/tracing/tracing_on
 +
</syntaxhighlight>
 +
 +
: 要启用函数跟踪器,只需将函数写入 current_tracer 文件。然后,你可以验证当前值:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo function > /sys/kernel/tracing/current_tracer
 +
Board $> cat /sys/kernel/tracing/current_tracer
 +
  function
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="bash">
 +
Board $> cat /sys/kernel/tracing/trace | head -20
 +
# tracer: function
 +
#
 +
# entries-in-buffer/entries-written: 144045/33695515  #P:2
 +
#
 +
#                              _-----=> irqs-off
 +
#                            / _----=> need-resched
 +
#                            | / _---=> hardirq/softirq
 +
#                            || / _--=> preempt-depth
 +
#                            ||| /    delay
 +
#          TASK-PID  CPU#  ||||    TIMESTAMP  FUNCTION
 +
#              | |      |  ||||      |        |
 +
            date-3591  [001] ...3  3278.796042: memblock_is_map_memory <-pfn_valid
 +
            date-3591  [001] ...3  3278.796046: unlock_page <-filemap_map_pages
 +
            date-3591  [001] ...3  3278.796051: alloc_set_pte <-filemap_map_pages
 +
            date-3591  [001] ...3  3278.796053: add_mm_counter_fast <-alloc_set_pte
 +
            date-3591  [001] ...3  3278.796055: page_add_file_rmap <-alloc_set_pte
 +
            date-3591  [001] ...3  3278.796057: __sync_icache_dcache <-alloc_set_pte
 +
            date-3591  [001] ...3  3278.796059: pfn_valid <-__sync_icache_dcache
 +
            date-3591  [001] ...3  3278.796061: memblock_is_map_memory <-pfn_valid
 +
            date-3591  [001] ...3  3278.796064: unlock_page <-filemap_map_pages
 +
</syntaxhighlight>
 +
 +
: 要应用功能过滤器,你可以在 /sys/kernel/tracing/set_ftrace_filter 中设置值,然后检查跟踪的新内容:
 +
<syntaxhighlight lang="bash">
 +
# Here we take the example with all uart functions
 +
Board $> echo "*uart*" > /sys/kernel/tracing/set_ftrace_filter
 +
 +
# Clean the existing trace
 +
Board $> echo > /sys/kernel/tracing/trace
 +
 +
# Display new trace content (in that case, please do some actions in the console to get some traces)
 +
Board $> cat /sys/kernel/tracing/trace | head -20
 +
# tracer: function
 +
#
 +
#                              _-----=> irqs-off
 +
#                            / _----=> need-resched
 +
#                            | / _---=> hardirq/softirq
 +
#                            || / _--=> preempt-depth
 +
#                            ||| /    delay
 +
#          TASK-PID  CPU#  ||||    TIMESTAMP  FUNCTION
 +
#              | |      |  ||||      |        |
 +
              sh-343  [000] ....  9313.041827: uart_ioctl <-tty_ioctl
 +
              sh-343  [000] ....  9313.041855: uart_ioctl <-tty_ioctl
 +
              sh-343  [000] ....  9313.041866: uart_chars_in_buffer <-tty_wait_until_sent
 +
              sh-343  [000] ....  9313.041870: uart_wait_until_sent <-tty_wait_until_sent
 +
              sh-343  [000] ....  9313.041875: uart_set_termios <-tty_set_termios
 +
              sh-343  [000] ....  9313.041968: uart_write_room <-tty_write_room
 +
              sh-343  [000] ....  9313.041974: uart_write <-n_tty_write
 +
              sh-343  [000] d..1  9313.041979: __uart_start <-uart_write
 +
              sh-343  [000] d..1  9313.041987: uart_write_wakeup <-stm32_transmit_chars
 +
              sh-343  [000] d.h2  9313.042007: uart_write_wakeup <-stm32_transmit_chars
 +
              sh-343  [000] d.h2  9313.042022: uart_write_wakeup <-stm32_transmit_chars
 +
</syntaxhighlight>
 +
: Linux文档ftrace [2 ]中提供了有关过滤选项和配置的更多信息。
 +
 +
: 要清空跟踪,请参阅段落 "擦除跟踪”
 +
: 要清除过滤器,以便再次记录所有功能:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo > /sys/kernel/tracing/set_ftrace_filter
 +
</syntaxhighlight>
 +
 +
====图形功能跟踪器模式====
 +
: 开始跟踪会话:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo 1 > /sys/kernel/tracing/tracing_on
 +
</syntaxhighlight>
 +
 +
: 要启用功能跟踪器,只需将function_graph写入current_tracer文件。然后,你可以验证当前值:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo function_graph > /sys/kernel/tracing/current_tracer
 +
Board $> cat /sys/kernel/tracing/current_tracer
 +
  function_graph
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="bash">
 +
Board $> cat /sys/kernel/tracing/trace | head -20
 +
# tracer: function_graph
 +
#
 +
# CPU  DURATION                  FUNCTION CALLS
 +
# |    |  |                    |  |  |  |
 +
  1)  1.015 us    |        _spin_lock_irqsave();
 +
  1)  0.476 us    |        internal_add_timer();
 +
  1)  0.423 us    |        wake_up_idle_cpu();
 +
  1)  0.461 us    |        _spin_unlock_irqrestore();
 +
  1)  4.770 us    |      }
 +
  1)  5.725 us    |    }
 +
  1)  0.450 us    |    mutex_unlock();
 +
  1) + 24.243 us  |  }
 +
  1)  0.483 us    |  _spin_lock_irq();
 +
  1)  0.517 us    |  _spin_unlock_irq();
 +
  1)              |  prepare_to_wait() {
 +
  1)  0.468 us    |    _spin_lock_irqsave();
 +
  1)  0.502 us    |    _spin_unlock_irqrestore();
 +
  1)  2.411 us    |  }
 +
  1)  0.449 us    |  kthread_should_stop();
 +
  1)              |  schedule() {
 +
</syntaxhighlight>
 +
 +
: 要应用图形函数过滤器,可以在 /sys/kernel/tracing/set_graph_function 中设置值,然后检查跟踪的新内容:
 +
<syntaxhighlight lang="bash">
 +
# Here we take the example with all uart functions
 +
Board $> echo "*uart*" > /sys/kernel/tracing/set_graph_function
 +
 +
# Clean the existing trace
 +
Board $> echo > /sys/kernel/tracing/trace
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="bash">
 +
# Display the new trace content (in that case, please do some action in the console to get some traces)
 +
Board $> cat /sys/kernel/tracing/trace | head -20
 +
# tracer: function_graph
 +
#
 +
# CPU  DURATION                  FUNCTION CALLS
 +
# |    |  |                    |  |  |  |
 +
1)              |  uart_ioctl() {
 +
1)  0.875 us    |    mutex_lock();
 +
1)  0.792 us    |    mutex_unlock();
 +
1) + 15.542 us  |  }
 +
1)              |  uart_ioctl() {
 +
1)  0.583 us    |    mutex_lock();
 +
1)  0.584 us    |    mutex_unlock();
 +
1)  9.792 us    |  }
 +
1)              |  uart_chars_in_buffer() {
 +
1)              |    _raw_spin_lock_irqsave() {
 +
1)  0.667 us    |      preempt_count_add();
 +
1)  5.458 us    |    }
 +
1)              |    _raw_spin_unlock_irqrestore() {
 +
1)  0.583 us    |      preempt_count_sub();
 +
1)  5.000 us    |    }
 +
1) + 19.459 us  |  }
 +
1)  1.541 us    |  uart_wait_until_sent();
 +
1)              |  uart_set_termios() {
 +
1)  0.583 us    |    mutex_lock();
 +
1)  0.583 us    |    mutex_unlock();
 +
1) + 10.291 us  |  }
 +
1)              |  uart_write_room() {
 +
1)              |    _raw_spin_lock_irqsave() {
 +
1)  0.666 us    |      preempt_count_add();
 +
1)  5.333 us    |    }
 +
1)              |    _raw_spin_unlock_irqrestore() {
 +
1)  0.583 us    |      preempt_count_sub();
 +
1)  5.000 us    |    }
 +
1) + 19.625 us  |  }
 +
1)              |  uart_write() {
 +
1)              |    _raw_spin_lock_irqsave() {
 +
1)  0.625 us    |      preempt_count_add();
 +
1)  5.209 us    |    }
 +
1)              |    __uart_start() {
 +
1)              |      stm32_start_tx() {
 +
1)              |        stm32_transmit_chars() {
 +
</syntaxhighlight>
 +
: 有关ftrace [2 ]的Linux文档,有关过滤选项和配置的更多信息。
 +
 +
: 要清空跟踪,请参阅段落 "擦除跟踪”
 +
: 要清除此特殊过滤器,以便再次记录所有功能:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo > /sys/kernel/tracing/set_graph_function
 +
</syntaxhighlight>
 +
 +
===缓冲区大小===
 +
: 为每个CPU分配一个缓冲区。为了进行跟踪分析,你可以更改此缓冲区的大小(增加或减少)。
 +
 +
: 可以读取每个CPU的给定大小值,或总计(值以千字节为单位):
 +
<syntaxhighlight lang="bash">
 +
# Per CPU
 +
Board $> cat /sys/kernel/tracing/buffer_size_kb
 +
1411
 +
or
 +
Board $> cat /sys/kernel/tracing/per_cpu/cpuX/buffer_size_kb
 +
1411
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="bash">
 +
# Total for all CPUs: combined size of all the trace buffers
 +
Board $> cat /sys/kernel/tracing/buffer_total_size_kb
 +
2822
 +
</syntaxhighlight>
 +
 +
: 要更改该值({{redtext|请注意,跟踪缓冲区是在页面中分配的(内核用于分配的你存块,通常大小为4 KB)}})
 +
<syntaxhighlight lang="bash">
 +
# Same value for each CPU (here 1000*4096/1024=4000)
 +
Board $> echo 4000 > /sys/kernel/tracing/buffer_size_kb
 +
or
 +
# Change buffer size value for a specific CPU X (here 1000*4096/1024=4000)
 +
Board $> echo 4000 > /sys/kernel/tracing/per_cpu/cpuX/buffer_size_kb
 +
</syntaxhighlight>
 +
 +
===在启动时使用ftrace===
 +
: 你可以从内核启动中使用ftrace,这对于调试启动问题非常有用。
 +
 +
: 为此,你必须使用内核命令行参数:
 +
:: - 如果要添加过滤器,则可选 {{redtext|ftrace}}以及{{redtext|ftrace_filter}}或{{redtext|ftrace_graph_filter}}。
 +
 +
====使用STM32MPU嵌入式软件包====
 +
: 例如,要修改内核bootargs,可以通过以下方式进行:
 +
 +
:: 从Linux内核控制台挂载引导分区,然后使用vi编辑器更新extlinux.conf文件(请参见手册页[3 ]或简介页[4 ])。例如:
 +
<syntaxhighlight lang="bash">
 +
Board $> mount /dev/mmcblk0p4 /boot
 +
# As example for SDCard boot on STM32MP15 Evaluation board, otherwise /boot/<bootdevice>_<platform>-<boardId>_extlinux/extlinux.conf
 +
Board $> vi /boot/mmc0_stm32mp157c-ev1_extlinux/extlinux.conf
 +
</syntaxhighlight>
 +
 +
:: 通过添加ftrace参数来更新内核命令行:
 +
::: - 功能跟踪器模式
 +
<syntaxhighlight lang="bash">
 +
root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function ftrace_filter=*uart*
 +
 +
</syntaxhighlight>
 +
 +
::: - function_graph追踪模式
 +
<syntaxhighlight lang="bash">
 +
root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function_graph ftrace_graph_filter=*uart*
 +
</syntaxhighlight>
 +
 +
:: 保存并退出文件更新,然后重新启动主板
 +
:: 或者
 +
:: 编辑来自microSD?卡的extlinux.conf文件(如果用作引导设备)
 +
 +
: 注意:需要管理员权限
 +
:: -将microSD卡插入主机PC
 +
:: -检查是否安装了引导分区(即 /media/$USER/bootfs)
 +
:: -编辑与你的设置相对应的extlinux文件(即 /media/$USER/bootfs/mmc0_stm32mp157c-ev1_extlinux/extlinux.conf)
 +
:: -按照所需的ftrace跟踪器配置修改命令行(请参见上文)
 +
:: -保存修改,然后将microSD卡插入目标
 +
:: -引导并检查内核命令行
 +
 +
====使用适用于Android的STM32MPU嵌入式软件包====
 +
: 例如,要修改内核bootargs,可以通过以下方式来完成,这需要重建启动镜像:
 +
 +
: 编辑文件 device/stm/<STM32Series>/<BoardId>/Boardconfig.mk
 +
: 通过在BOARD_KERNEL_CMDLINE变量中添加ftrace参数来更新内核命令行:
 +
:: - 功能跟踪器模式
 +
<syntaxhighlight lang="bash">
 +
...
 +
# =========================================================== #
 +
# Kernel command line                                        #
 +
# =========================================================== #
 +
BOARD_KERNEL_CMDLINE := console=ttySTM0,115200 androidboot.console=/dev/ttySTM0 consoleblank=0 earlyprintk
 +
BOARD_KERNEL_CMDLINE += skip_initramfs ro rootfstype=ext4 rootwait
 +
BOARD_KERNEL_CMDLINE += init=/init firmware_class.path=/vendor/firmware
 +
BOARD_KERNEL_CMDLINE += androidboot.hardware=stm
 +
BOARD_KERNEL_CMDLINE += ftrace=function ftrace_filter=*uart*
 +
...
 +
</syntaxhighlight>
 +
:: - function_graph追踪模式
 +
<syntaxhighlight lang="bash">
 +
...
 +
# =========================================================== #
 +
# Kernel command line                                        #
 +
# =========================================================== #
 +
BOARD_KERNEL_CMDLINE := console=ttySTM0,115200 androidboot.console=/dev/ttySTM0 consoleblank=0 earlyprintk
 +
BOARD_KERNEL_CMDLINE += skip_initramfs ro rootfstype=ext4 rootwait
 +
BOARD_KERNEL_CMDLINE += init=/init firmware_class.path=/vendor/firmware
 +
BOARD_KERNEL_CMDLINE += androidboot.hardware=stm
 +
BOARD_KERNEL_CMDLINE += ftrace=function_graph ftrace_graph_filter=*uart*
 +
...
 +
</syntaxhighlight>
 +
: 重建并重新加载启动镜像
 +
 +
 +
====检查跟踪====
 +
: 引导后,要检查跟踪,必须先挂载tracefs:
 +
<syntaxhighlight lang="bash">
 +
Board $> mount -t tracefs nodev /sys/kernel/tracing
 +
</syntaxhighlight>
 +
 +
: 注意:以下信息与 Android 发行版有关
 +
:: 需要启用root访问权限
 +
:: 使用ADB Shell可以使用ADB链接:
 +
<syntaxhighlight lang="bash">
 +
PC $> adb root
 +
PC $> adb shell
 +
Board $> ...
 +
</syntaxhighlight>
 +
:: 使用UART控制台shell:
 +
<syntaxhighlight lang="bash">
 +
Board $> su
 +
Board $> ...
 +
</syntaxhighlight>
 +
 +
: 然后查看跟踪内容(即函数跟踪):
 +
<syntaxhighlight lang="bash">
 +
Board $> cat /sys/kernel/tracing/trace | head -20
 +
# tracer: function
 +
#
 +
#                              _-----=> irqs-off
 +
#                            / _----=> need-resched
 +
#                            | / _---=> hardirq/softirq
 +
#                            || / _--=> preempt-depth
 +
#                            ||| /    delay
 +
#          TASK-PID  CPU#  ||||    TIMESTAMP  FUNCTION
 +
#              | |      |  ||||      |        |
 +
        systemd-1    [000] ....    1.087213: uart_register_driver <-usart_init
 +
        systemd-1    [000] ....    1.087847: uart_get_rs485_mode <-stm32_serial_probe
 +
        systemd-1    [000] ....    1.088436: uart_add_one_port <-stm32_serial_probe
 +
        systemd-1    [000] ....    1.098000: uart_parse_options <-stm32_console_setup
 +
        systemd-1    [000] ....    1.098007: uart_set_options <-stm32_console_setup
 +
        systemd-1    [000] ....    1.098014: uart_get_baud_rate <-stm32_set_termios
 +
        systemd-1    [000] d..1    1.098019: uart_update_timeout <-stm32_set_termios
 +
        systemd-1    [000] d..1    1.098090: uart_console_write <-stm32_console_write
 +
        systemd-1    [000] d..1    1.105231: uart_console_write <-stm32_console_write
 +
        systemd-1    [000] d..1    1.114697: uart_console_write <-stm32_console_write
 +
        systemd-1    [000] d..1    1.120300: uart_console_write <-stm32_console_write
 +
</syntaxhighlight>
 +
 +
====捕获(从启动)oops到串行控制台====
 +
: 在启动时启用ftrace的一个有趣的应用程序是通过在内核命令行上放置以下参数来捕获导致不稳定的函数调用:
 +
<syntaxhighlight lang="bash">
 +
root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function ftrace_dump_on_oops
 +
</syntaxhighlight>
 +
: 当发生oops时,ftrace缓冲区将自动转储到控制台消息中。
 +
 +
===删除痕迹===
 +
: 使用以下命令可以擦除ftrace的跟踪内容:
 +
<syntaxhighlight lang="bash">
 +
Board $> echo > /sys/kernel/tracing/trace
 +
</syntaxhighlight>
 +
==深入学习==
 +
===为ftrace添加打印信息===
 +
: 除了打印Linux内核功能之外,还可以使用trace_printk函数使用ftrace跟踪特定的调试信息。
 +
: 它可以像printk()一样使用,也可以在任何上下文中使用(中断代码,NMI代码和调度程序代码)。
 +
: trace_printk不会输出到控制台,但会写入ftrace环形缓冲区,并且可以通过跟踪文件读取。
 +
 +
: 要使用trace_printk函数,必须在源代码中包含linux/ftrace.h:
 +
<syntaxhighlight lang="bash">
 +
...
 +
#include <linux/ftrace.h>
 +
...
 +
</syntaxhighlight>
 +
 +
: 然后使用trace_printk语法作为printk(请参见以下示例):
 +
<syntaxhighlight lang="bash">
 +
...
 +
trace_printk("%s: %d uart_tx_stopped(port) %i\n", __FUNCTION__, __LINE__, uart_tx_stopped(port));
 +
...
 +
</syntaxhighlight>
 +
 +
===堆栈跟踪===
 +
: 从内核文档中提取了ftrace [2 ]。
 +
: 由于内核具有固定大小的堆栈,因此重要的是不要在功能上浪费它。内核开发人员必须知道函数在堆栈上分配了什么。如果它们增加太大的大小,则系统可能处于堆栈溢出的危险中,并且会发生损坏,通常会导致系统死机。
 +
: 有一些工具可以检查此情况,通常使用中断定期检查其使用情况。但是,如果你可以在每个函数调用中执行检查,这将非常有用。由于ftrace提供了一个函数跟踪程序,因此可以方便地在每次函数调用时检查堆栈大小。这是通过堆栈跟踪器启用的。
 +
 +
: Linux内核配置选项CONFIG_STACK_TRACER启用ftrace堆栈跟踪功能。
 +
<syntaxhighlight lang="bash">
 +
Symbol: STACK_TRACER
 +
Location:
 +
  Kernel Hacking --->
 +
    Tracers -->
 +
      [*] Trace max stack
 +
</syntaxhighlight>
 +
 +
: 要启用它,请将 '1' 写入 /proc/sys/kernel/stack_tracer_enabled 中。
 +
<syntaxhighlight lang="bash">
 +
Board $> echo 1 > /proc/sys/kernel/stack_tracer_enabled
 +
</syntaxhighlight>
 +
 +
: 你还可以通过在内核命令行参数中添加"stacktrace”,在内核命令行中启用它以在启动过程中跟踪内核的堆栈大小。
 +
<syntaxhighlight lang="bash">
 +
root =/dev/mmcblk0p5 rootwait读写控制台= ttyS3,115200 stacktrace
 +
</syntaxhighlight>
 +
 +
: 启动后,要检查跟踪,你必须先安装 tracefs,然后显示跟踪内容:
 +
<syntaxhighlight lang="bash">
 +
Board $> mount -t tracefs nodev /sys/kernel/tracing
 +
 +
Board $> cat /sys/kernel/tracing/stack_max_size
 +
2928
 +
 +
Board $> cat /sys/kernel/tracing/stack_trace
 +
        Depth    Size  Location    (82 entries)
 +
      -----    ----  --------
 +
0)    4328      4  __rcu_read_unlock+0x14/0x68
 +
1)    4324    180  select_task_rq_fair+0x8ac/0xb7c
 +
2)    4144      64  try_to_wake_up+0x100/0x3fc
 +
3)    4080      16  wake_up_process+0x20/0x24
 +
4)    4064      24  swake_up_locked.part.0+0x20/0x38
 +
5)    4040      24  swake_up+0x38/0x48
 +
6)    4016      16  rcu_gp_kthread_wake+0x4c/0x50
 +
7)    4000      24  rcu_report_qs_rsp+0x50/0x84
 +
8)    3976    120  rcu_report_qs_rnp+0x258/0x2ec
 +
9)    3856      80  rcu_process_callbacks+0x290/0x43c
 +
10)    3776      96  __do_softirq+0x12c/0x3ec
 +
11)    3680      16  irq_exit+0xd0/0x118
 +
12)    3664      48  __handle_domain_irq+0x90/0xfc
 +
13)    3616      40  gic_handle_irq+0x5c/0xa0
 +
14)    3576      68  __irq_svc+0x6c/0xa8
 +
15)    3508      28  unwind_get_byte+0x20/0x74
 +
16)    3480    160  unwind_frame+0x1a8/0x6b0
 +
17)    3320      32  walk_stackframe+0x34/0x40
 +
18)    3288      56  __save_stack_trace+0xa4/0xa8
 +
19)    3232      16  save_stack_trace+0x30/0x34
 +
20)    3216      72  create_object+0x120/0x278
 +
21)    3144      40  kmemleak_alloc+0x8c/0xd4
 +
22)    3104      64  kmem_cache_alloc+0x184/0x2f0
 +
23)    3040      64  __kernfs_new_node+0x58/0x15c
 +
24)    2976      24  kernfs_new_node+0x2c/0x48
 +
25)    2952      24  __kernfs_create_file+0x28/0xb8
 +
26)    2928      56  sysfs_add_file_mode_ns+0xc4/0x1a0
 +
27)    2872      24  sysfs_create_file_ns+0x4c/0x58
 +
28)    2848      56  kobject_add_internal+0x174/0x358
 +
29)    2792      40  kobject_add+0x50/0x98
 +
30)    2752      32  irq_sysfs_add+0x44/0x60
 +
31)    2720      72  __irq_alloc_descs+0x174/0x234
 +
32)    2648      48  irq_domain_alloc_descs+0x64/0xe4
 +
33)    2600      56  irq_create_mapping+0x108/0x1fc
 +
34)    2544      56  irq_create_fwspec_mapping+0x140/0x318
 +
35)    2488      88  irq_create_of_mapping+0x5c/0x64
 +
36)    2400    168  of_irq_get+0x68/0x78
 +
37)    2232      24  stpmu1_regulator_parse_dt+0x68/0x80
 +
38)    2208      96  regulator_register+0x218/0x970
 +
39)    2112      32  devm_regulator_register+0x54/0x84
 +
40)    2080    136  stpmu1_regulator_probe+0x350/0x5f4
 +
41)    1944      32  platform_drv_probe+0x60/0xbc
 +
42)    1912      64  driver_probe_device+0x2f4/0x488
 +
43)    1848      32  __device_attach_driver+0xac/0x14c
 +
44)    1816      40  bus_for_each_drv+0x54/0xa4
 +
45)    1776      40  __device_attach+0xc0/0x150
 +
46)    1736      16  device_initial_probe+0x1c/0x20
 +
47)    1720      32  bus_probe_device+0x94/0x9c
 +
48)    1688      64  device_add+0x3c0/0x5d0
 +
49)    1624      16  of_device_add+0x44/0x4c
 +
50)    1608      40  of_platform_device_create_pdata+0x84/0xb4
 +
51)    1568    104  of_platform_bus_create+0x160/0x2f8
 +
52)    1464      56  of_platform_populate+0x9c/0x134
 +
53)    1408      32  stpmu1_probe+0x6c/0xac
 +
54)    1376      40  i2c_device_probe+0x290/0x2dc
 +
55)    1336      64  driver_probe_device+0x2f4/0x488
 +
56)    1272      32  __device_attach_driver+0xac/0x14c
 +
57)    1240      40  bus_for_each_drv+0x54/0xa4
 +
58)    1200      40  __device_attach+0xc0/0x150
 +
59)    1160      16  device_initial_probe+0x1c/0x20
 +
60)    1144      32  bus_probe_device+0x94/0x9c
 +
61)    1112      64  device_add+0x3c0/0x5d0
 +
62)    1048      24  device_register+0x24/0x28
 +
63)    1024      48  i2c_new_device+0x14c/0x2f4
 +
64)      976      96  of_i2c_register_device+0x134/0x1dc
 +
65)      880      40  of_i2c_register_devices+0x8c/0x100
 +
66)      840      48  i2c_register_adapter+0x184/0x404
 +
67)      792      48  i2c_add_adapter+0xa4/0x138
 +
68)      744    160  stm32f7_i2c_probe+0x954/0xd08
 +
69)      584      32  platform_drv_probe+0x60/0xbc
 +
70)      552      64  driver_probe_device+0x2f4/0x488
 +
71)      488      32  __driver_attach+0x110/0x12c
 +
72)      456      40  bus_for_each_dev+0x5c/0xac
 +
73)      416      16  driver_attach+0x2c/0x30
 +
74)      400      48  bus_add_driver+0x1d0/0x274
 +
75)      352      24  driver_register+0x88/0x104
 +
76)      328      16  __platform_driver_register+0x50/0x58
 +
77)      312      16  stm32f7_i2c_driver_init+0x24/0x28
 +
78)      296    112  do_one_initcall+0x54/0x178
 +
79)      184      72  kernel_init_freeable+0x1dc/0x274
 +
80)      112      24  kernel_init+0x18/0x124
 +
81)      88      88  ret_from_fork+0x14/0x24
 +
</syntaxhighlight>
 +
 +
===更多示踪剂===
 +
: 更多跟踪器可用于ftrace。请参阅Linux内核文档中的ftrace [2 ]。
 +
{| class="wikitable"
 +
|-
 +
! 跟踪器名称 !! 描述
 +
|-
 +
|blk || 块跟踪器。blktrace用户应用程序 使用的跟踪器
 +
|-
 +
|hwlat || 硬件延迟跟踪器。它用于检测硬件是否产生任何延迟
 +
|-
 +
|irqsoff || 跟踪禁用中断的区域,并以最长的最大延迟保存跟踪
 +
|-
 +
|preemptoff || 与irqsoff类似,但跟踪并记录禁用抢占的时间
 +
|-
 +
|preemptirqsoff || 与irqsoff和preemptoff类似,但是跟踪并记录禁用irqs和/或抢占的最大时间
 +
|-
 +
|wakeup || 跟踪并记录唤醒后优先级最高的任务安排所需的最大延迟
 +
|-
 +
|wakeup_rt || 跟踪并记录仅RT任务所需的最大延迟(就像当前的“唤醒”一样)
 +
|-
 +
|wakeup_dl || 跟踪并记录唤醒SCHED_DEADLINE任务所需的最大延迟(如"wakeup”和"wakeup_rt”一样)
 +
|-
 +
|mmiotrace || 一种特殊的跟踪器,用于跟踪二进制模块。它跟踪模块对硬件的所有调用
 +
|-
 +
|branch || 在跟踪内核中可能/不太可能发生的调用时可以配置此跟踪器
 +
|-
 +
|nop || 这是“空的”追踪器
 +
|}
 +
 +
===辅助工具===
 +
: 尽管 [https://wiki.st.com/stm32mpu/wiki/Debugfs debugfs] 接口非常简单,但使用起来也很尴尬。建议使用一些工具来简化ftrace的用户体验。
 +
* [https://wiki.st.com/stm32mpu/wiki/Trace-cmd_and_kernelshark_trace_viewer trace-cmd命令行阅读器和kernelshark跟踪查看器]
 +
:: trace-cmd是一种命令行工具,可以与ftrace配合使用并与之交互,而不是将命令回显到特定文件中并从另一个文件读取结果。它提出了一个高级用户命令界面来简化ftrace的使用。
 +
:: 与trace-cmd相关联的kernelshark工具提出了一个跟踪查看器,可用于分析跟踪。
 +
* [https://wiki.st.com/stm32mpu/wiki/LTTng Linux跟踪工具套件(LTTng)和Trace Compass查看器]
 +
:: LTTng是部分基于ftrace的Linux开源跟踪框架,该框架还通过命令行提出了高级用户界面。我们将主机PC端的Trace Compass与日志查看器关联。
 +
 +
==参考==
 +
* 1. [https://elinux.org/Ftrace https://elinux.org/Ftrace]
 +
* 2. [https://github.com/STMicroelectronics/linux/blob/v4.19-stm32mp/Documentation/trace/ftrace.rst Documentation/trace/ftrace.rst]
 +
* 3. [http://ex-vi.sourceforge.net/vi.html http://ex-vi.sourceforge.net/vi.html]
 +
* 4. [http://ex-vi.sourceforge.net/viin/paper.html http://ex-vi.sourceforge.net/viin/paper.html]
 +
 +
* 有用的外部链接
 +
{| class="wikitable"
 +
|-
 +
! 文件链接 !! 文件类型 !! 描述
 +
|-
 +
| [https://www.kernel.org/doc/Documentation/trace/ftrace.txt ftrace(kernel.org文档)] || 标准 || Linux内核来源的文档
 +
|-
 +
| [http://lwn.net/Articles/365835/ 使用Ftrace调试内核-第1部分] || 用户指南 || [http://lwn.net http://lwn.net]
 +
|-
 +
| [http://lwn.net/Articles/366796/ 使用Ftrace调试内核-第2部分] || 用户指南 || [http://lwn.net http://lwn.net]
 +
|-
 +
| [http://lwn.net/Articles/379903 使用TRACE_EVENT()宏(带有CREATE_TRACE_POINTS)] || 训练 || [http://lwn.net http://lwn.net]
 +
|-
 +
| [https://wiki.linaro.org/WorkingGroups/PowerManagement/Resources/Tools/load-perf-analyses#Using_ftrace 使用ftrace加载性能分析] || 用户指南 || Linaro
 +
|}
 +
 
[[Category:Linux_Operating_System]]
 
[[Category:Linux_Operating_System]]
 
[[Category:Linux_tracing_tools]]
 
[[Category:Linux_tracing_tools]]

2019年12月26日 (四) 16:05的最新版本

Ftrace

文章目的

本文提供了开始使用Linux内核工具所需的基本信息:ftrace [1 ]。

简介

下表简要介绍了该工具及其可用性,具体取决于软件包:
  • 是:该工具已经存在(可以使用或激活),也可以在软件包中集成和激活。
  • 没有:该工具不存在且无法集成,或者存在但无法在软件包中激活。
工具
名称 类别 目的
ftrace 追踪工具 ftrace [1 ](函数跟踪程序)是功能强大的内核跟踪实用程序,例如,它可以跟踪每个内核函数调用和内核事件,而无需在内核源代码中添加任何额外的代码 没有 没有 是 没有 没有 是
STM32MPU嵌入式软件发行版
入门资料包 开发者资料包 发行版资料包
没有 没有
适用于 Android 的STM32MPU嵌入式软件发行版
入门资料包 开发者资料包 发行版资料包
没有 没有
注意:在Linux内核4.1之前,所有ftrace跟踪控制文件都在debugfs文件系统中,该文件系统通常位于 /sys/kernel/debug/tracing 中。现在,它位于/ sys/kernel/tracing中,并且独立于debugfs。
为了向后兼容,在安装 debugfs 文件系统时,tracefs 文件系统会自动安装在: /sys/kernel/debug/tracing.。
位于tracefs文件系统中的所有文件也位于该debugfs文件系统目录中。
请注意,符号表中存在的所有函数都可用于ftrace。要知道符号列表中是否有可用的函数,可以使用命令 "nm vmlinux

在目标板上安装跟踪和调试工具

ftrace是一项内核功能,在OpenSTLinux发行版中默认情况下未启用,因为这会影响Linux内核大小(vmlinux大约增加1.5%),并且还会对整体性能产生影响,因为其触发了跟踪内核事件和函数调用。
为了使用ftrace所需的“内核功能跟踪程序” ,Linux内核配置必须使用Linux内核menuconfig工具激活 CONFIG_FUNCTION_TRACER 和 CONFIG_FUNCTION_GRAPH_TRACER 配置:
	Symbol: FUNCTION_TRACER
	Location:
	  Kernel Hacking --->
	    Tracers -->
	      [*] Kernel Function Tracer

	Symbol: FUNCTION_GRAPH_TRACER
	Location:
	  Kernel Hacking --->
	    Tracers -->
	      [*] Kernel Function Tracer
	      [*] Kernel Function Graph Tracer

使用STM32MPU嵌入式软件发行版

开发人员软件包

不建议使用Developer Package启用ftrace内核配置,因为所有外部模块需要重新编译(例如GPU STM32MP1的gcnano驱动程序),而Developer Package则无法实现,因为它不需要提供所有资料来源。
这就是为什么将此设置为“开发人员包”不支持的原因。

分发包

启用所需的Linux内核配置
要在Linux内核配置中启用CONFIG_FUNCTION_TRACER和CONFIG_FUNCTION_GRAPH_TRACER,请参阅 Menuconfig或如何配置内核 一文,以获取有关在Distribution Package上下文中修改配置和重新编译Linux内核镜像的说明。
还必须重新编译不属于Linux内核源代码树的外部Linux内核模块(如果存在)。
GPU STM32MP1的gcnano驱动程序示例:
	PC $> bitbake gcnano-driver-stm32mp
重新构建完整的OpenSTLinux镜像,以便重新编译所有依赖项并具有正确的rootfs(包括外部Linux内核模块)
	PC $> bitbake st-image-weston
注意:如前所述,启用ftrace配置时,未压缩的Linux内核镜像的大小会增加。
根据目标板的内存配置(在设备树中定义),内核镜像的增加可能与放置在其后的某些保留区域重叠。
在这种情况下,突出显示了编译错误。
如果此重叠影响很小(意味着某些功能不再起作用,但并不关键),则可以通过使用Linux内核Menuconfig工具(Menuconfig或如何配置内核)激活Linux内核配置CONFIG_SECTION_MISMATCH_WARN_ONLY来避免编译错误。)
	Symbol: SECTION_MISMATCH_WARN_ONLY
	Location:
	  Kernel Hacking --->
	    Compile-time checks and compiler options -->
	      [*] Make section mismatch errors non-fatal

使用适用于 Android 的 STM32MPU 嵌入式软件发行版

分发包

启用所需的Linux内核配置
要在Linux内核配置中启用CONFIG_FUNCTION_TRACER和CONFIG_FUNCTION_GRAPH_TRACER,请参阅如何为Android定制内核 一文,以获取有关修改配置的说明
在Android分发包中重新编译Linux内核镜像和模块。
	PC $> build_kernel vmlinux -i
	PC $> build_kernel modules -i
还必须重新编译不属于Linux内核源代码树的外部Linux内核模块(如果存在的话)。

GPU STM32MP1的gcnano驱动程序示例:

	PC $> build_kernel gpu -i
重建完整的Android镜像,以便重新编译所有依赖关系并考虑Linux内核镜像和模块的新的预构建镜像:
	PC $> make -j
注意:如前所述,启用ftrace配置时,未压缩的Linux内核镜像的大小会增加。
根据目标板的内存配置(在设备树中定义),内核镜像的增加可能会覆盖后面放置的一些保留区域。
在这种情况下,突出显示了编译错误。
如果此重叠影响很小(意味着某些功能不再起作用,但并不关键),则可以通过使用Linux内核Menuconfig工具激活Linux内核配置CONFIG_SECTION_MISMATCH_WARN_ONLY来绕过编译错误(如何为Android定制内核))
	Symbol: SECTION_MISMATCH_WARN_ONLY
	Location:
	  Kernel Hacking --->
	    Compile-time checks and compiler options -->
	      [*] Make section mismatch errors non-fatal

使用入门

在运行时使用ftrace

首先,你需要从目标启用/激活 ftrace 功能。
目标启动并登录后,安装 tracefs:
	Board $> mount -t tracefs nodev /sys/kernel/tracing
注意:以下信息与 Android 发行版有关
需要启用root访问权限
使用ADB Shell可以使用ADB链接:
		PC $> adb root
		PC $> adb shell
		Board $> ...
使用UART控制台shell:
		Board $> su
		Board $> ...
在那一步,所有的"ftrace”功能都发生在文件系统目录路径 /sys/kernel/tracing 中。
要找出可用的跟踪器,只需在跟踪目录中放置 available_tracers 文件即可:
	Board $> cat /sys/kernel/tracing/available_tracers
	 function_graph function nop
内核构建配置可以添加更多的跟踪器。请参阅 深入学习 一节。

过滤器选项

注意:ftrace使用函数/ graph_function过滤器,而不是驱动程序过滤器。因此,跟踪* myDriver *函数不会从myDriver跟踪myHelper函数。
你可以使用以下命令获取可用的过滤器功能的列表:
	Board $> cat /sys/kernel/tracing/available_filter_functions

功能跟踪器模式

开始跟踪会话
	Board $> echo 1 > /sys/kernel/tracing/tracing_on
要启用函数跟踪器,只需将函数写入 current_tracer 文件。然后,你可以验证当前值:
	Board $> echo function > /sys/kernel/tracing/current_tracer
	Board $> cat /sys/kernel/tracing/current_tracer
	  function
	Board $> cat /sys/kernel/tracing/trace | head -20
	 # tracer: function
	 #
	 # entries-in-buffer/entries-written: 144045/33695515   #P:2
	 #
	 #                              _-----=> irqs-off
	 #                             / _----=> need-resched
	 #                            | / _---=> hardirq/softirq
	 #                            || / _--=> preempt-depth
	 #                            ||| /     delay
	 #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
	 #              | |       |   ||||       |         |
	             date-3591  [001] ...3  3278.796042: memblock_is_map_memory <-pfn_valid
	             date-3591  [001] ...3  3278.796046: unlock_page <-filemap_map_pages
	             date-3591  [001] ...3  3278.796051: alloc_set_pte <-filemap_map_pages
	             date-3591  [001] ...3  3278.796053: add_mm_counter_fast <-alloc_set_pte
	             date-3591  [001] ...3  3278.796055: page_add_file_rmap <-alloc_set_pte
	             date-3591  [001] ...3  3278.796057: __sync_icache_dcache <-alloc_set_pte
	             date-3591  [001] ...3  3278.796059: pfn_valid <-__sync_icache_dcache
	             date-3591  [001] ...3  3278.796061: memblock_is_map_memory <-pfn_valid
	             date-3591  [001] ...3  3278.796064: unlock_page <-filemap_map_pages
要应用功能过滤器,你可以在 /sys/kernel/tracing/set_ftrace_filter 中设置值,然后检查跟踪的新内容:
	# Here we take the example with all uart functions
	Board $> echo "*uart*" > /sys/kernel/tracing/set_ftrace_filter

	# Clean the existing trace
	Board $> echo > /sys/kernel/tracing/trace

	# Display new trace content (in that case, please do some actions in the console to get some traces)
	Board $> cat /sys/kernel/tracing/trace | head -20
	# tracer: function
	#
	#                              _-----=> irqs-off
	#                             / _----=> need-resched
	#                            | / _---=> hardirq/softirq
	#                            || / _--=> preempt-depth
	#                            ||| /     delay
	#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
	#              | |       |   ||||       |         |
	              sh-343   [000] ....  9313.041827: uart_ioctl <-tty_ioctl
	              sh-343   [000] ....  9313.041855: uart_ioctl <-tty_ioctl
	              sh-343   [000] ....  9313.041866: uart_chars_in_buffer <-tty_wait_until_sent
	              sh-343   [000] ....  9313.041870: uart_wait_until_sent <-tty_wait_until_sent
	              sh-343   [000] ....  9313.041875: uart_set_termios <-tty_set_termios
	              sh-343   [000] ....  9313.041968: uart_write_room <-tty_write_room
	              sh-343   [000] ....  9313.041974: uart_write <-n_tty_write
	              sh-343   [000] d..1  9313.041979: __uart_start <-uart_write
	              sh-343   [000] d..1  9313.041987: uart_write_wakeup <-stm32_transmit_chars
	              sh-343   [000] d.h2  9313.042007: uart_write_wakeup <-stm32_transmit_chars
	              sh-343   [000] d.h2  9313.042022: uart_write_wakeup <-stm32_transmit_chars
Linux文档ftrace [2 ]中提供了有关过滤选项和配置的更多信息。
要清空跟踪,请参阅段落 "擦除跟踪”
要清除过滤器,以便再次记录所有功能:
	Board $> echo > /sys/kernel/tracing/set_ftrace_filter

图形功能跟踪器模式

开始跟踪会话:
	Board $> echo 1 > /sys/kernel/tracing/tracing_on
要启用功能跟踪器,只需将function_graph写入current_tracer文件。然后,你可以验证当前值:
	Board $> echo function_graph > /sys/kernel/tracing/current_tracer
	Board $> cat /sys/kernel/tracing/current_tracer
	  function_graph
	Board $> cat /sys/kernel/tracing/trace | head -20
	 # tracer: function_graph
	 #
	 # CPU  DURATION                  FUNCTION CALLS
	 # |     |   |                     |   |   |   |
	  1)   1.015 us    |        _spin_lock_irqsave();
	  1)   0.476 us    |        internal_add_timer();
	  1)   0.423 us    |        wake_up_idle_cpu();
	  1)   0.461 us    |        _spin_unlock_irqrestore();
	  1)   4.770 us    |      }
	  1)   5.725 us    |    }
	  1)   0.450 us    |    mutex_unlock();
	  1) + 24.243 us   |  }
	  1)   0.483 us    |  _spin_lock_irq();
	  1)   0.517 us    |  _spin_unlock_irq();
	  1)               |  prepare_to_wait() {
	  1)   0.468 us    |    _spin_lock_irqsave();
	  1)   0.502 us    |    _spin_unlock_irqrestore();
	  1)   2.411 us    |  }
	  1)   0.449 us    |  kthread_should_stop();
	  1)               |  schedule() {
要应用图形函数过滤器,可以在 /sys/kernel/tracing/set_graph_function 中设置值,然后检查跟踪的新内容:
	# Here we take the example with all uart functions
	Board $> echo "*uart*" > /sys/kernel/tracing/set_graph_function

	# Clean the existing trace
	Board $> echo > /sys/kernel/tracing/trace
	# Display the new trace content (in that case, please do some action in the console to get some traces)
	Board $> cat /sys/kernel/tracing/trace | head -20
	# tracer: function_graph
	#
	# CPU  DURATION                  FUNCTION CALLS
	# |     |   |                     |   |   |   |
	 1)               |  uart_ioctl() {
	 1)   0.875 us    |    mutex_lock();
	 1)   0.792 us    |    mutex_unlock();
	 1) + 15.542 us   |  }
	 1)               |  uart_ioctl() {
	 1)   0.583 us    |    mutex_lock();
	 1)   0.584 us    |    mutex_unlock();
	 1)   9.792 us    |  }
	 1)               |  uart_chars_in_buffer() {
	 1)               |    _raw_spin_lock_irqsave() {
	 1)   0.667 us    |      preempt_count_add();
	 1)   5.458 us    |    }
	 1)               |    _raw_spin_unlock_irqrestore() {
	 1)   0.583 us    |      preempt_count_sub();
	 1)   5.000 us    |    }
	 1) + 19.459 us   |  }
	 1)   1.541 us    |  uart_wait_until_sent();
	 1)               |  uart_set_termios() {
	 1)   0.583 us    |    mutex_lock();
	 1)   0.583 us    |    mutex_unlock();
	 1) + 10.291 us   |  }
	 1)               |  uart_write_room() {
	 1)               |    _raw_spin_lock_irqsave() {
	 1)   0.666 us    |      preempt_count_add();
	 1)   5.333 us    |    }
	 1)               |    _raw_spin_unlock_irqrestore() {
	 1)   0.583 us    |      preempt_count_sub();
	 1)   5.000 us    |    }
	 1) + 19.625 us   |  }
	 1)               |  uart_write() {
	 1)               |    _raw_spin_lock_irqsave() {
	 1)   0.625 us    |      preempt_count_add();
	 1)   5.209 us    |    }
	 1)               |    __uart_start() {
	 1)               |      stm32_start_tx() {
	 1)               |        stm32_transmit_chars() {
有关ftrace [2 ]的Linux文档,有关过滤选项和配置的更多信息。
要清空跟踪,请参阅段落 "擦除跟踪”
要清除此特殊过滤器,以便再次记录所有功能:
	Board $> echo > /sys/kernel/tracing/set_graph_function

缓冲区大小

为每个CPU分配一个缓冲区。为了进行跟踪分析,你可以更改此缓冲区的大小(增加或减少)。
可以读取每个CPU的给定大小值,或总计(值以千字节为单位):
	# Per CPU
	Board $> cat /sys/kernel/tracing/buffer_size_kb
	1411
	or
	Board $> cat /sys/kernel/tracing/per_cpu/cpuX/buffer_size_kb
	1411
	# Total for all CPUs: combined size of all the trace buffers
	Board $> cat /sys/kernel/tracing/buffer_total_size_kb
	2822
要更改该值(请注意,跟踪缓冲区是在页面中分配的(内核用于分配的你存块,通常大小为4 KB)
	# Same value for each CPU (here 1000*4096/1024=4000)
	Board $> echo 4000 > /sys/kernel/tracing/buffer_size_kb
	or
	# Change buffer size value for a specific CPU X (here 1000*4096/1024=4000)
	Board $> echo 4000 > /sys/kernel/tracing/per_cpu/cpuX/buffer_size_kb

在启动时使用ftrace

你可以从内核启动中使用ftrace,这对于调试启动问题非常有用。
为此,你必须使用内核命令行参数:
- 如果要添加过滤器,则可选 ftrace以及ftrace_filterftrace_graph_filter

使用STM32MPU嵌入式软件包

例如,要修改内核bootargs,可以通过以下方式进行:
从Linux内核控制台挂载引导分区,然后使用vi编辑器更新extlinux.conf文件(请参见手册页[3 ]或简介页[4 ])。例如:
	Board $> mount /dev/mmcblk0p4 /boot
	# As example for SDCard boot on STM32MP15 Evaluation board, otherwise /boot/<bootdevice>_<platform>-<boardId>_extlinux/extlinux.conf
	Board $> vi /boot/mmc0_stm32mp157c-ev1_extlinux/extlinux.conf
通过添加ftrace参数来更新内核命令行:
- 功能跟踪器模式
	root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function ftrace_filter=*uart*
- function_graph追踪模式
	root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function_graph ftrace_graph_filter=*uart*
保存并退出文件更新,然后重新启动主板
或者
编辑来自microSD?卡的extlinux.conf文件(如果用作引导设备)
注意:需要管理员权限
-将microSD卡插入主机PC
-检查是否安装了引导分区(即 /media/$USER/bootfs)
-编辑与你的设置相对应的extlinux文件(即 /media/$USER/bootfs/mmc0_stm32mp157c-ev1_extlinux/extlinux.conf)
-按照所需的ftrace跟踪器配置修改命令行(请参见上文)
-保存修改,然后将microSD卡插入目标
-引导并检查内核命令行

使用适用于Android的STM32MPU嵌入式软件包

例如,要修改内核bootargs,可以通过以下方式来完成,这需要重建启动镜像:
编辑文件 device/stm/<STM32Series>/<BoardId>/Boardconfig.mk
通过在BOARD_KERNEL_CMDLINE变量中添加ftrace参数来更新内核命令行:
- 功能跟踪器模式
	...
	# =========================================================== #
	# Kernel command line                                         #
	# =========================================================== #
	BOARD_KERNEL_CMDLINE := console=ttySTM0,115200 androidboot.console=/dev/ttySTM0 consoleblank=0 earlyprintk
	BOARD_KERNEL_CMDLINE += skip_initramfs ro rootfstype=ext4 rootwait
	BOARD_KERNEL_CMDLINE += init=/init firmware_class.path=/vendor/firmware
	BOARD_KERNEL_CMDLINE += androidboot.hardware=stm
	BOARD_KERNEL_CMDLINE += ftrace=function ftrace_filter=*uart*
	...
- function_graph追踪模式
	...
	# =========================================================== #
	# Kernel command line                                         #
	# =========================================================== #
	BOARD_KERNEL_CMDLINE := console=ttySTM0,115200 androidboot.console=/dev/ttySTM0 consoleblank=0 earlyprintk
	BOARD_KERNEL_CMDLINE += skip_initramfs ro rootfstype=ext4 rootwait
	BOARD_KERNEL_CMDLINE += init=/init firmware_class.path=/vendor/firmware
	BOARD_KERNEL_CMDLINE += androidboot.hardware=stm
	BOARD_KERNEL_CMDLINE += ftrace=function_graph ftrace_graph_filter=*uart*
	...
重建并重新加载启动镜像


检查跟踪

引导后,要检查跟踪,必须先挂载tracefs:
	Board $> mount -t tracefs nodev /sys/kernel/tracing
注意:以下信息与 Android 发行版有关
需要启用root访问权限
使用ADB Shell可以使用ADB链接:
		PC $> adb root
		PC $> adb shell
		Board $> ...
使用UART控制台shell:
		Board $> su
		Board $> ...
然后查看跟踪内容(即函数跟踪):
	Board $> cat /sys/kernel/tracing/trace | head -20
	# tracer: function
	#
	#                              _-----=> irqs-off
	#                             / _----=> need-resched
	#                            | / _---=> hardirq/softirq
	#                            || / _--=> preempt-depth
	#                            ||| /     delay
	#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
	#              | |       |   ||||       |         |
	         systemd-1     [000] ....     1.087213: uart_register_driver <-usart_init
	         systemd-1     [000] ....     1.087847: uart_get_rs485_mode <-stm32_serial_probe
	         systemd-1     [000] ....     1.088436: uart_add_one_port <-stm32_serial_probe
	         systemd-1     [000] ....     1.098000: uart_parse_options <-stm32_console_setup
	         systemd-1     [000] ....     1.098007: uart_set_options <-stm32_console_setup
	         systemd-1     [000] ....     1.098014: uart_get_baud_rate <-stm32_set_termios
	         systemd-1     [000] d..1     1.098019: uart_update_timeout <-stm32_set_termios
	         systemd-1     [000] d..1     1.098090: uart_console_write <-stm32_console_write
	         systemd-1     [000] d..1     1.105231: uart_console_write <-stm32_console_write
	         systemd-1     [000] d..1     1.114697: uart_console_write <-stm32_console_write
	         systemd-1     [000] d..1     1.120300: uart_console_write <-stm32_console_write

捕获(从启动)oops到串行控制台

在启动时启用ftrace的一个有趣的应用程序是通过在内核命令行上放置以下参数来捕获导致不稳定的函数调用:
	root=/dev/mmcblk0p5 rootwait rw console=ttyS3,115200 ftrace=function ftrace_dump_on_oops
当发生oops时,ftrace缓冲区将自动转储到控制台消息中。

删除痕迹

使用以下命令可以擦除ftrace的跟踪内容:
	Board $> echo > /sys/kernel/tracing/trace

深入学习

为ftrace添加打印信息

除了打印Linux内核功能之外,还可以使用trace_printk函数使用ftrace跟踪特定的调试信息。
它可以像printk()一样使用,也可以在任何上下文中使用(中断代码,NMI代码和调度程序代码)。
trace_printk不会输出到控制台,但会写入ftrace环形缓冲区,并且可以通过跟踪文件读取。
要使用trace_printk函数,必须在源代码中包含linux/ftrace.h:
	...
	#include <linux/ftrace.h>
	...
然后使用trace_printk语法作为printk(请参见以下示例):
	...
	trace_printk("%s: %d uart_tx_stopped(port) %i\n", __FUNCTION__, __LINE__, uart_tx_stopped(port));
	...

堆栈跟踪

从内核文档中提取了ftrace [2 ]。
由于内核具有固定大小的堆栈,因此重要的是不要在功能上浪费它。内核开发人员必须知道函数在堆栈上分配了什么。如果它们增加太大的大小,则系统可能处于堆栈溢出的危险中,并且会发生损坏,通常会导致系统死机。
有一些工具可以检查此情况,通常使用中断定期检查其使用情况。但是,如果你可以在每个函数调用中执行检查,这将非常有用。由于ftrace提供了一个函数跟踪程序,因此可以方便地在每次函数调用时检查堆栈大小。这是通过堆栈跟踪器启用的。
Linux内核配置选项CONFIG_STACK_TRACER启用ftrace堆栈跟踪功能。
	Symbol: STACK_TRACER
	Location:
	  Kernel Hacking --->
	    Tracers -->
	      [*] Trace max stack
要启用它,请将 '1' 写入 /proc/sys/kernel/stack_tracer_enabled 中。
	Board $> echo 1 > /proc/sys/kernel/stack_tracer_enabled
你还可以通过在内核命令行参数中添加"stacktrace”,在内核命令行中启用它以在启动过程中跟踪内核的堆栈大小。
	root =/dev/mmcblk0p5 rootwait读写控制台= ttyS3,115200 stacktrace
启动后,要检查跟踪,你必须先安装 tracefs,然后显示跟踪内容:
	Board $> mount -t tracefs nodev /sys/kernel/tracing

	Board $> cat /sys/kernel/tracing/stack_max_size
	2928

	Board $> cat /sys/kernel/tracing/stack_trace
	        Depth    Size   Location    (82 entries)
	       -----    ----   --------
	 0)     4328       4   __rcu_read_unlock+0x14/0x68
	 1)     4324     180   select_task_rq_fair+0x8ac/0xb7c
	 2)     4144      64   try_to_wake_up+0x100/0x3fc
	 3)     4080      16   wake_up_process+0x20/0x24
	 4)     4064      24   swake_up_locked.part.0+0x20/0x38
	 5)     4040      24   swake_up+0x38/0x48
	 6)     4016      16   rcu_gp_kthread_wake+0x4c/0x50
	 7)     4000      24   rcu_report_qs_rsp+0x50/0x84
	 8)     3976     120   rcu_report_qs_rnp+0x258/0x2ec
	 9)     3856      80   rcu_process_callbacks+0x290/0x43c
	10)     3776      96   __do_softirq+0x12c/0x3ec
	11)     3680      16   irq_exit+0xd0/0x118
	12)     3664      48   __handle_domain_irq+0x90/0xfc
	13)     3616      40   gic_handle_irq+0x5c/0xa0
	14)     3576      68   __irq_svc+0x6c/0xa8
	15)     3508      28   unwind_get_byte+0x20/0x74
	16)     3480     160   unwind_frame+0x1a8/0x6b0
	17)     3320      32   walk_stackframe+0x34/0x40
	18)     3288      56   __save_stack_trace+0xa4/0xa8
	19)     3232      16   save_stack_trace+0x30/0x34
	20)     3216      72   create_object+0x120/0x278
	21)     3144      40   kmemleak_alloc+0x8c/0xd4
	22)     3104      64   kmem_cache_alloc+0x184/0x2f0
	23)     3040      64   __kernfs_new_node+0x58/0x15c
	24)     2976      24   kernfs_new_node+0x2c/0x48
	25)     2952      24   __kernfs_create_file+0x28/0xb8
	26)     2928      56   sysfs_add_file_mode_ns+0xc4/0x1a0
	27)     2872      24   sysfs_create_file_ns+0x4c/0x58
	28)     2848      56   kobject_add_internal+0x174/0x358
	29)     2792      40   kobject_add+0x50/0x98
	30)     2752      32   irq_sysfs_add+0x44/0x60
	31)     2720      72   __irq_alloc_descs+0x174/0x234
	32)     2648      48   irq_domain_alloc_descs+0x64/0xe4
	33)     2600      56   irq_create_mapping+0x108/0x1fc
	34)     2544      56   irq_create_fwspec_mapping+0x140/0x318
	35)     2488      88   irq_create_of_mapping+0x5c/0x64
	36)     2400     168   of_irq_get+0x68/0x78
	37)     2232      24   stpmu1_regulator_parse_dt+0x68/0x80
	38)     2208      96   regulator_register+0x218/0x970
	39)     2112      32   devm_regulator_register+0x54/0x84
	40)     2080     136   stpmu1_regulator_probe+0x350/0x5f4
	41)     1944      32   platform_drv_probe+0x60/0xbc
	42)     1912      64   driver_probe_device+0x2f4/0x488
	43)     1848      32   __device_attach_driver+0xac/0x14c
	44)     1816      40   bus_for_each_drv+0x54/0xa4
	45)     1776      40   __device_attach+0xc0/0x150
	46)     1736      16   device_initial_probe+0x1c/0x20
	47)     1720      32   bus_probe_device+0x94/0x9c
	48)     1688      64   device_add+0x3c0/0x5d0
	49)     1624      16   of_device_add+0x44/0x4c
	50)     1608      40   of_platform_device_create_pdata+0x84/0xb4
	51)     1568     104   of_platform_bus_create+0x160/0x2f8
	52)     1464      56   of_platform_populate+0x9c/0x134
	53)     1408      32   stpmu1_probe+0x6c/0xac
	54)     1376      40   i2c_device_probe+0x290/0x2dc
	55)     1336      64   driver_probe_device+0x2f4/0x488
	56)     1272      32   __device_attach_driver+0xac/0x14c
	57)     1240      40   bus_for_each_drv+0x54/0xa4
	58)     1200      40   __device_attach+0xc0/0x150
	59)     1160      16   device_initial_probe+0x1c/0x20
	60)     1144      32   bus_probe_device+0x94/0x9c
	61)     1112      64   device_add+0x3c0/0x5d0
	62)     1048      24   device_register+0x24/0x28
	63)     1024      48   i2c_new_device+0x14c/0x2f4
	64)      976      96   of_i2c_register_device+0x134/0x1dc
	65)      880      40   of_i2c_register_devices+0x8c/0x100
	66)      840      48   i2c_register_adapter+0x184/0x404
	67)      792      48   i2c_add_adapter+0xa4/0x138
	68)      744     160   stm32f7_i2c_probe+0x954/0xd08
	69)      584      32   platform_drv_probe+0x60/0xbc
	70)      552      64   driver_probe_device+0x2f4/0x488
	71)      488      32   __driver_attach+0x110/0x12c
	72)      456      40   bus_for_each_dev+0x5c/0xac
	73)      416      16   driver_attach+0x2c/0x30
	74)      400      48   bus_add_driver+0x1d0/0x274
	75)      352      24   driver_register+0x88/0x104
	76)      328      16   __platform_driver_register+0x50/0x58
	77)      312      16   stm32f7_i2c_driver_init+0x24/0x28
	78)      296     112   do_one_initcall+0x54/0x178
	79)      184      72   kernel_init_freeable+0x1dc/0x274
	80)      112      24   kernel_init+0x18/0x124
	81)       88      88   ret_from_fork+0x14/0x24

更多示踪剂

更多跟踪器可用于ftrace。请参阅Linux内核文档中的ftrace [2 ]。
跟踪器名称 描述
blk 块跟踪器。blktrace用户应用程序 使用的跟踪器
hwlat 硬件延迟跟踪器。它用于检测硬件是否产生任何延迟
irqsoff 跟踪禁用中断的区域,并以最长的最大延迟保存跟踪
preemptoff 与irqsoff类似,但跟踪并记录禁用抢占的时间
preemptirqsoff 与irqsoff和preemptoff类似,但是跟踪并记录禁用irqs和/或抢占的最大时间
wakeup 跟踪并记录唤醒后优先级最高的任务安排所需的最大延迟
wakeup_rt 跟踪并记录仅RT任务所需的最大延迟(就像当前的“唤醒”一样)
wakeup_dl 跟踪并记录唤醒SCHED_DEADLINE任务所需的最大延迟(如"wakeup”和"wakeup_rt”一样)
mmiotrace 一种特殊的跟踪器,用于跟踪二进制模块。它跟踪模块对硬件的所有调用
branch 在跟踪内核中可能/不太可能发生的调用时可以配置此跟踪器
nop 这是“空的”追踪器

辅助工具

尽管 debugfs 接口非常简单,但使用起来也很尴尬。建议使用一些工具来简化ftrace的用户体验。
trace-cmd是一种命令行工具,可以与ftrace配合使用并与之交互,而不是将命令回显到特定文件中并从另一个文件读取结果。它提出了一个高级用户命令界面来简化ftrace的使用。
与trace-cmd相关联的kernelshark工具提出了一个跟踪查看器,可用于分析跟踪。
LTTng是部分基于ftrace的Linux开源跟踪框架,该框架还通过命令行提出了高级用户界面。我们将主机PC端的Trace Compass与日志查看器关联。