Heng30的博客
搜索 分类 关于 订阅

如何使用ftrace跟踪调试内核?

2025-02-12

ftraceLinux内核中的一种跟踪工具,用于分析和调试内核行为。它通过在内核函数中插入钩子来捕获函数调用、返回及其他事件,帮助开发者了解内核的执行流程和性能瓶颈。

主要功能

  • 函数跟踪:记录内核函数的调用和返回。

  • 事件跟踪:捕获特定内核事件,如调度、中断等。

  • 动态探针:允许在运行时插入探针,跟踪特定函数或代码路径。

  • 性能分析:测量函数执行时间,识别性能瓶颈。

调试跟踪步骤

  • 进入到debugfs目录:cd /sys/kernel/debug/tracing

  • 查看可用跟踪器:cat available_tracers

    • timerlat osnoise hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
    • 常用的跟踪器:functionfunction_graph
    • function:跟踪函数的执行
    • function_graph:跟踪函数的调用关系
  • 查看支持哪些内核函数cat available_filter_functions

...
get_energy_counter [intel_rapl_common]
get_pl_prim [intel_rapl_common]
rapl_write_pl_data [intel_rapl_common]
...
  • 查看支持哪些内核事件cat available_events
...
mctp:mctp_key_acquire
handshake:tls_alert_recv
handshake:tls_alert_send
...
  • 通过perf top -a查看系统函数的使用情况

  • 追踪所有函数:echo > set_graph_function

  • 追踪特定函数:echo kmem_cache_free > set_graph_function

  • 追踪多个函数:echo "*mount*" > set_graph_function

  • 打印函数调用栈:echo 1 > options/func_stack_trace

  • 停止当前追踪器:echo nop > current_tracer

  • 设置追踪器:

    • echo function_graph > current_tracer
    • echo funcgraph-proc > trace_options
  • 开启追踪:echo 1 > tracing_on

  • 等待1秒,让函数触发

  • 关闭追踪:echo 0 > tracing_on

  • 查看追踪结果:cat trace

 7)    <idle>-0    |               |  kmem_cache_free() {
 7)    <idle>-0    |               |    __memcg_slab_free_hook() {
 7)    <idle>-0    |               |      obj_cgroup_uncharge() {
 7)    <idle>-0    |   0.113 us    |        refill_obj_stock();
 7)    <idle>-0    |   0.317 us    |      }
 7)    <idle>-0    |   0.116 us    |      mod_objcg_state();
 7)    <idle>-0    |   0.109 us    |      __rcu_read_lock();
 7)    <idle>-0    |   0.107 us    |      __rcu_read_unlock();
 7)    <idle>-0    |   1.111 us    |    }
 7)    <idle>-0    |   0.117 us    |    __slab_free();
 7)    <idle>-0    |   1.520 us    |  }

通过上面的输出可以看到有函数的调用链函数的运行时长。这些信息可以帮助我们了解内核热点函数。

最终脚本

#!/bin/sh

# 参数为内核函数。如:kmem_cache_free

# 检查并挂载 debugfs
if ! mount | grep -q debugfs; then
    sudo mount -t debugfs none /sys/kernel/debug
fi

# 清空追踪缓冲区
sudo sh -c 'echo > /sys/kernel/debug/tracing/trace'

# 查找正确的函数名
function_name=$(grep $1 /proc/kallsyms | awk '{print $3}'| tr -d ' ' | grep -E "^$1$")
if [ -z "$function_name" ]; then
    echo "can not find $1 in this kernel"
    exit 1
fi

# 设置想要追踪的函数
sudo sh -c "echo $function_name > /sys/kernel/debug/tracing/set_graph_function"

# 设置追踪器
sudo sh -c 'echo function_graph > /sys/kernel/debug/tracing/current_tracer'
sudo sh -c 'echo funcgraph-proc > /sys/kernel/debug/tracing/trace_options'

# 开启追踪
sudo sh -c 'echo 1 > /sys/kernel/debug/tracing/tracing_on'

# 等待函数触发
sleep 1

# 关闭追踪
sudo sh -c 'echo 0 > /sys/kernel/debug/tracing/tracing_on'

# 查看追踪结果
sudo cat /sys/kernel/debug/tracing/trace

排错

  • 如果没有tracing目录,需要运行下面的命令mount -t debugfs nodev /sys/kernel/debug

  • 如果内核未启用CONFIG_FUNCTION_GRAPH_TRACER选项,function_graph追踪器将不可用。你可以检查内核配置文件: grep CONFIG_FUNCTION_GRAPH_TRACER /boot/config-$(uname -r)CONFIG_FUNCTION_GRAPH_TRACER=y为启用。

  • 检查内核是否包含指定函数:cat /proc/kallsyms | grep function-name

希望上面的内容对你有所帮助。