引导阶段跟踪

作者:

Masami Hiramatsu <mhiramat@kernel.org>

概述

引导阶段跟踪(Boot-time tracing)允许用户跟踪引导阶段的过程,包括设备初始化,并可使用 ftrace 的全部功能,包括每个事件的过滤器和动作、直方图、kprobe-events、合成事件(synthetic-events)以及跟踪实例。由于内核命令行不足以控制这些复杂功能,因此它使用 bootconfig 文件来描述跟踪功能的配置。

Boot Config 中的选项

以下是 boot config 文件中可用于引导阶段跟踪的选项列表 [1]。所有选项均带有 “ftrace.” 或 “kernel.” 前缀。有关以 “kernel.” 前缀开头的选项,请参阅内核参数 [2]

Ftrace 全局选项

Ftrace 全局选项在 boot config 中具有 “kernel.” 前缀,这意味着这些选项作为内核传统命令的一部分传递。

kernel.tp_printk

同时在 printk 缓冲区上输出跟踪事件(trace-event)数据。

kernel.dump_on_oops [= MODE]

在发生 Oops 时转储 ftrace。如果 MODE = 1 或省略,则转储所有 CPU 上的跟踪缓冲区。如果 MODE = 2,则转储触发 Oops 的那个 CPU 上的缓冲区。

kernel.traceoff_on_warning

如果发生 WARN_ON(),则停止跟踪。

kernel.fgraph_max_depth = MAX_DEPTH

将 MAX_DEPTH 设置为 fgraph 跟踪器的最大深度。

kernel.fgraph_filters = FILTER[, FILTER2...]

添加 fgraph 跟踪函数过滤器。

kernel.fgraph_notraces = FILTER[, FILTER2...]

添加 fgraph 非跟踪函数过滤器(排除过滤器)。

Ftrace 实例级选项

这些选项可用于每个实例,包括全局 ftrace 节点。

ftrace.[instance.INSTANCE.]options = OPT1[, OPT2[...]]

启用指定的 ftrace 选项。

ftrace.[instance.INSTANCE.]tracing_on = 0|1

在启动引导阶段跟踪时启用/禁用此实例上的跟踪。(你可以通过 “traceon” 事件触发器动作来启用它)

ftrace.[instance.INSTANCE.]trace_clock = CLOCK

将指定的 CLOCK 设置为 ftrace 的 trace_clock。

ftrace.[instance.INSTANCE.]buffer_size = SIZE

将 ftrace 缓冲区大小配置为 SIZE。该 SIZE 可以使用 “KB” 或 “MB”。

ftrace.[instance.INSTANCE.]alloc_snapshot

分配快照缓冲区。

ftrace.[instance.INSTANCE.]cpumask = CPUMASK

将 CPUMASK 设置为跟踪的 CPU 掩码。

ftrace.[instance.INSTANCE.]events = EVENT[, EVENT2[...]]

在引导时启用指定的事件。你可以在 EVENT 中使用通配符。

ftrace.[instance.INSTANCE.]tracer = TRACER

在引导时将 TRACER 设置为当前的跟踪器。(例如 function)

ftrace.[instance.INSTANCE.]ftrace.filters

这接受一个跟踪函数过滤规则的数组。

ftrace.[instance.INSTANCE.]ftrace.notraces

这接受一个非跟踪(排除)函数过滤规则的数组。

Ftrace 事件级选项

这些选项用于设置每个事件的选项。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.enable

启用 GROUP:EVENT 跟踪。

ftrace.[instance.INSTANCE.]event.GROUP.enable

启用 GROUP 内的所有事件跟踪。

ftrace.[instance.INSTANCE.]event.enable

启用所有事件跟踪。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.filter = FILTER

为 GROUP:EVENT 设置 FILTER 规则。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.actions = ACTION[, ACTION2[...]]

为 GROUP:EVENT 设置动作(ACTION)。

ftrace.[instance.INSTANCE.]event.kprobes.EVENT.probes = PROBE[, PROBE2[...]]

根据 PROBE 定义新的 kprobe 事件。它可以在一个事件上定义多个探测点,但这些探测点必须具有相同类型的参数。此选项仅适用于组名为 “kprobes” 的事件。

ftrace.[instance.INSTANCE.]event.synthetic.EVENT.fields = FIELD[, FIELD2[...]]

用 FIELD 定义新的合成事件(synthetic event)。每个字段应为 “type varname” 格式。

注意,kprobe 和合成事件的定义可以写在实例节点下,但它们对其他实例也是可见的。因此请注意避免事件名称冲突。

Ftrace 直方图选项

由于将直方图动作作为字符串写入事件级动作选项会太长,因此在事件级的 ‘hist’ 子键下提供了树形选项来配置直方图动作。有关每个参数的详细信息,请阅读事件直方图文档 (Event Histograms)

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]keys = KEY1[, KEY2[...]]

设置直方图键(key)参数。(必填)‘N’ 是用于多个直方图的数字字符串。如果事件上只有一个直方图,可以省略它。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]values = VAL1[, VAL2[...]]

设置直方图值(value)参数。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]sort = SORT1[, SORT2[...]]

设置直方图排序参数选项。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]size = NR_ENTRIES

设置直方图大小(条目数)。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]name = NAME

设置直方图名称。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]var.VARIABLE = EXPR

通过 EXPR 表达式定义一个新的 VARIABLE。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]<pause|continue|clear>

设置直方图控制参数。你可以设置其中一个。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]onmatch.[M.]event = GROUP.EVENT

设置直方图 ‘onmatch’ 处理程序的匹配事件参数。‘M’ 是用于多个 ‘onmatch’ 处理程序的数字字符串。如果该直方图上只有一个 ‘onmatch’ 处理程序,可以省略它。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]onmatch.[M.]trace = EVENT[, ARG1[...]]

为 ‘onmatch’ 设置直方图的 ‘trace’ 动作。EVENT 必须是合成事件的名称,ARG1... 是该事件的参数。如果设置了 ‘onmatch.event’ 选项,则此项必填。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]onmax.[M.]var = VAR

设置直方图 ‘onmax’ 处理程序的变量参数。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]onchange.[M.]var = VAR

设置直方图 ‘onchange’ 处理程序的变量参数。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]<onmax|onchange>.[M.]save = ARG1[, ARG2[...]]

为 ‘onmax’ 或 ‘onchange’ 处理程序设置直方图的 ‘save’ 动作参数。如果设置了 ‘onmax.var’ 或 ‘onchange.var’ 选项,则此选项或下方的 ‘snapshot’ 选项为必填项。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.[N.]<onmax|onchange>.[M.]snapshot

为 ‘onmax’ 或 ‘onchange’ 处理程序设置直方图的 ‘snapshot’ 动作。如果设置了 ‘onmax.var’ 或 ‘onchange.var’ 选项,则此选项或上方的 ‘save’ 选项为必填项。

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist.filter = FILTER_EXPR

设置直方图过滤表达式。在 FILTER_EXPR 中不需要使用 ‘if’。

请注意,如果事件级 ‘actions’ 选项包含直方图动作,则此 ‘hist’ 选项可能会与事件级的 ‘actions’ 选项冲突。

何时启动

所有以 ftrace 开头的引导阶段跟踪选项都将在 core_initcall 结束时启用。这意味着你可以从 postcore_initcall 开始跟踪事件。大多数子系统和架构相关的驱动程序都会在此之后初始化(arch_initcall 或 subsys_initcall)。因此,你可以通过引导阶段跟踪来跟踪它们。如果你想在 core_initcall 之前跟踪事件,可以使用以 kernel 开头的选项。其中一些选项会在 initcall 处理之前启用(例如,kernel.ftrace=functionkernel.trace_event 将在 initcall 之前启动)。

示例

例如,要为每个事件添加过滤器和动作、定义 kprobe 事件以及带直方图的合成事件,可以编写如下的 boot config

ftrace.event {
      task.task_newtask {
              filter = "pid < 128"
              enable
      }
      kprobes.vfs_read {
              probes = "vfs_read $arg1 $arg2"
              filter = "common_pid < 200"
              enable
      }
      synthetic.initcall_latency {
              fields = "unsigned long func", "u64 lat"
              hist {
                      keys = func.sym, lat
                      values = lat
                      sort = lat
              }
      }
      initcall.initcall_start.hist {
              keys = func
              var.ts0 = common_timestamp.usecs
      }
      initcall.initcall_finish.hist {
              keys = func
              var.lat = common_timestamp.usecs - $ts0
              onmatch {
                      event = initcall.initcall_start
                      trace = initcall_latency, func, $lat
              }
      }
}

此外,引导阶段跟踪支持 “instance” 节点,这允许我们同时运行多个用于不同目的的跟踪器。例如,一个跟踪器用于跟踪以 “user_” 开头的函数,另一个跟踪 “kernel_” 函数,你可以编写如下的 boot config

ftrace.instance {
      foo {
              tracer = "function"
              ftrace.filters = "user_*"
      }
      bar {
              tracer = "function"
              ftrace.filters = "kernel_*"
      }
}

实例节点也接受事件节点,以便每个实例都可以自定义其事件跟踪。

借助触发器动作和 kprobes,你可以在调用某个函数时跟踪函数图(function-graph)。例如,这将跟踪 pci_proc_init() 中的所有函数调用

ftrace {
      tracing_on = 0
      tracer = function_graph
      event.kprobes {
              start_event {
                      probes = "pci_proc_init"
                      actions = "traceon"
              }
              end_event {
                      probes = "pci_proc_init%return"
                      actions = "traceoff"
              }
      }
}

此引导阶段跟踪还通过 boot config 支持 ftrace 内核参数。例如,以下内核参数

trace_options=sym-addr trace_event=initcall:* tp_printk trace_buf_size=1M ftrace=function ftrace_filter="vfs*"

可以像下面这样写在 boot config 中

kernel {
      trace_options = sym-addr
      trace_event = "initcall:*"
      tp_printk
      trace_buf_size = 1M
      ftrace = function
      ftrace_filter = "vfs*"
}

注意,参数以 “kernel” 前缀开头,而不是 “ftrace”。