Linux 追踪技术 ftrace的使用二


前言

一、Single thread tracing

通过写入 set_ftrace_pid,您可以跟踪单个线程,比如:

echo 0 > tracing_on
echo nop > current_tracer
echo > trace

追踪 pid = 411870 的任务:

 echo 411870 > set_ftrace_pid
 echo function > current_tracer
 echo 1 > tracing_on
 cat trace | more

在这里插入图片描述

二、Ftrace function_graph

2.1 Graph Tracing

此跟踪器类似于函数跟踪器,只是它在函数的入口和出口处探测函数。 这是通过在每个 task_struct 中使用动态分配的返回地址堆栈来完成的。 在函数进入时,跟踪器会覆盖每个跟踪函数的返回地址以设置自定义探针。 因此原始返回地址存储在task_struct中的返回地址堆栈中。

在函数的两端进行探测会导致特殊功能,例如:
(1)衡量函数执行时间。
(2)有一个可靠的调用栈来绘制函数调用图。

这个跟踪器在以下几种情况下是有用的:
(1)想找到内核异常行为的原因,需要详细了解在任何区域(或特定区域)发生了什么。
(2)正在经历不寻常的延迟,但很难找到它的起源。
(3)快速找到特定功能所采用的路径
(4)查看运行中的内核,看看那里发生了什么。

有几列可以动态启用/禁用。 您可以根据需要使用所需的每种选项组合:

function_graph 跟踪器打印函数的调用图,展示其代码流。

在这里插入图片描述


只跟踪一个函数及其所有子函数,将其名称echo 到 set_graph_function 中:

echo do_nanosleep > set_graph_function

下面使用 do_nanosleep() 函数上的 function_graph 跟踪器来显示其子函数调用:

echo do_nanosleep > set_graph_function
echo function_graph > current_tracer

在这里插入图片描述

 echo nop > current_tracer
 echo > set_graph_function

输出显示子调用和代码流:do_nanosleep() 调用 hrtimer_start_range_ns().左侧的列显示了 CPU(在此输出中,主要是 CPU 3)和函数的持续时间,以便可以识别延迟.高延迟包括一个字符符号以帮助您注意它们,在此输出中,延迟为 1000337 微秒(1.0 秒)旁边的“$”。

在这里插入图片描述

$: Greater than 1 second
@: Greater than 100 ms
*: Greater than 10 ms
#: Greater than 1 ms
!: Greater than 100 μs
+: Greater than 10 μs

这个例子特意没有设置函数过滤器(set_ftrace_filter),这样所有子调用都可以看到。 但是,这确实会产生一些开销,从而夸大了报告的持续时间。 它通常对于定位高延迟的来源仍然很有用,这会使增加的开销相形见绌。 当您希望给定函数的时间更准确时,可以使用函数过滤器来减少跟踪的函数。 例如,仅跟踪 do_nanosleep():

echo do_nanosleep > set_ftrace_filter

以 do_sys_open 函数为例子来测试function_graph:

echo do_sys_open > set_graph_function
echo function_graph > current_tracer
echo funcgraph-proc > trace_options

在这里插入图片描述


CPU 字段给出了执行函数的 CPU 号,本例中为2 号 CPU
TASK/PID 地段给出进程名称和进程PID号
DURATION 字段给出了函数执行的时间长度,以 us 为单位。
FUNCTION CALLS 则给出了调用的函数,并显示了调用流程。
需要注意:

对于不调用其它函数的函数,其对应行以“;”结尾,而且对应的 DURATION 字段给出其运行时长;

对于调用其它函数的函数,则在其“}”对应行给出了运行时长,该时间是一个累加值,包括了其内部调用的函数的执行时长。DURATION 字段给出的时长并不是精确的,它还包含了执行 ftrace 自身的代码所耗费的时间,所以示例中将内部函数时长累加得到的结果会与对应的外围调用函数的执行时长并不一致;不过通过该字段还是可以大致了解函数在时间上的运行开销的。

备注:function graph trace 实际是在要跟踪函数的入口处和返回处分别放置了钩子函数,在要跟踪函数的入口处插入钩子函数ftrace_caller,在要跟踪函数的返回处插入钩子函数return_to_handler。因此function_graph tracer即可以跟踪到函数的入口还可以跟踪到函数的返回

2.2 Options

选项可用于更改输出,可以在选项options目录中列出:

ls options/funcgraph-*

在这里插入图片描述


这些调整输出并且可以包括或排除详细信息,例如 CPU ID (funcgraph-cpu)、进程名称 (funcgraph-proc)、函数持续时间 (funcgraph-duration) 和延迟标记 (funcgraph-overhead)。

(1)
执行函数的 CPU 编号默认启用。 有时最好只跟踪一个 cpu,或者您有时可能会在 cpu 跟踪切换时看到无序的函数调用。

hide: echo nofuncgraph-cpu > trace_options
show: echo funcgraph-cpu > trace_options

(2)
持续时间(函数的执行时间)显示在函数的右括号行上,或者在叶子函数的情况下显示在与当前函数相同的行上。 它是默认启用的。

hide: echo nofuncgraph-duration > trace_options
show: echo funcgraph-duration > trace_options

在这里插入图片描述


叶子函数:没有调用其他的函数。

(3)
task/pid 字段显示执行该函数的线程 cmdline 和 pid。 默认禁用。

hide: echo nofuncgraph-proc > trace_options
show: echo funcgraph-proc > trace_options

比如:

# tracer: function_graph
#
# CPU  TASK/PID        DURATION                  FUNCTION CALLS
# |    |    |           |   |                     |   |   |   |
0)    sh-4802     |               |                  d_free() {
0)    sh-4802     |               |                    call_rcu() {
0)    sh-4802     |               |                      __call_rcu() {
0)    sh-4802     |   0.616 us    |                        rcu_process_gp_end();
0)    sh-4802     |   0.586 us    |                        check_for_new_grace_period();
0)    sh-4802     |   2.899 us    |                      }
0)    sh-4802     |   4.040 us    |                    }
0)    sh-4802     |   5.151 us    |                  }
0)    sh-4802     | + 49.370 us   |                }

(4)
在达到持续时间阈值的情况下,开销字段在持续时间字段之前。

hide: echo nofuncgraph-overhead > trace_options
show: echo funcgraph-overhead > trace_options
depends on: funcgraph-duration

比如:

3) # 1837.709 us |          } /* __switch_to */
3)               |          finish_task_switch() {
3)   0.313 us    |            _raw_spin_unlock_irq();
3)   3.177 us    |          }
3) # 1889.063 us |        } /* __schedule */
3) ! 140.417 us  |      } /* __schedule */
3) # 2034.948 us |    } /* schedule */
3) * 33998.59 us |  } /* schedule_preempt_disabled */

[...]

1)   0.260 us    |              msecs_to_jiffies();
1)   0.313 us    |              __rcu_read_unlock();
1) + 61.770 us   |            }
1) + 64.479 us   |          }
1)   0.313 us    |          rcu_bh_qs();
1)   0.313 us    |          __local_bh_enable();
1) ! 217.240 us  |        }
1)   0.365 us    |        idle_cpu();
1)               |        rcu_irq_exit() {
1)   0.417 us    |          rcu_eqs_enter_common.isra.47();
1)   3.125 us    |        }
1) ! 227.812 us  |      }
1) ! 457.395 us  |    }
1) @ 119760.2 us |  }

[...]

2)               |    handle_IPI() {
1)   6.979 us    |                  }
2)   0.417 us    |      scheduler_ipi();
1)   9.791 us    |                }
1) + 12.917 us   |              }
2)   3.490 us    |    }
1) + 15.729 us   |            }
1) + 18.542 us   |          }
2) $ 3594274 us  |  }
+ means that the function exceeded 10 usecs.
! means that the function exceeded 100 usecs.
# means that the function exceeded 1000 usecs.
* means that the function exceeded 10 msecs.
@ means that the function exceeded 100 msecs.
$ means that the function exceeded 1 sec.

(5)

对于开始在跟踪缓冲区中的函数,可以在右括号(the closing bracket)后显示函数名称,从而可以更轻松地使用 grep 搜索函数持续时间。 默认禁用。

hide: echo nofuncgraph-tail > trace_options
show: echo funcgraph-tail > trace_options

nofuncgraph-tail 示例(默认):

0)               |      putname() {
0)               |        kmem_cache_free() {
0)   0.518 us    |          __phys_addr();
0)   1.757 us    |        }
0)   2.861 us    |      }

funcgraph-tail 示例:

0)               |      putname() {
0)               |        kmem_cache_free() {
0)   0.518 us    |          __phys_addr();
0)   1.757 us    |        } /* kmem_cache_free() */	 右括号(代表函数结束)显示函数名称
0)   2.861 us    |      } /* putname() */	 --右括号(代表函数结束)显示函数名称

(6)

可以使用 trace_printk() 对特定函数 function() 添加一些注释 例如,如果您想在 function() 函数中添加注释,您只需包含 <linux/ftrace.h> 并在 function() 中调用 trace_printk() :

trace_printk("I'm a comment!\n")

将产生:

1)               |              function()  {
1)               |                /* I'm a comment! */
1)   1.449 us    |             }

三、tracepoint

3.1 tracepoint简介

参考:Event Tracing
tracepoint是内核静态检测,跟踪点在技术上只是放置在内核源代码中的跟踪函数; 它们从定义和格式化它们的参数的跟踪事件接口中使用。 跟踪事件在 tracefs 中可见,并与 Ftrace 共享输出和控制文件

无需创建自定义内核模块即可使用tracepoint来使用 event tracing infrastructure 注册探测功能。

并非所有tracepoint都可以使用 event tracing system 进行跟踪; 内核开发人员必须提供代码片段,这些代码片段定义了如何将跟踪信息保存到跟踪缓冲区中,以及应该如何打印跟踪信息。

基于 ftrace 跟踪内核静态跟踪点,包括全部可用于跟踪的静态跟踪点,可跟踪的完整列表可通过 available_events 查看:

在这里插入图片描述


events 目录下查看到各分类的子目录:

ls -F events

在这里插入图片描述


例如,以下启用 block:block_rq_issue 跟踪点并实时监视事件。 此示例通过禁用跟踪点完成:

echo 1 > events/block/block_rq_issue/enable
cat trace_pipe | more

前五列是:进程名称“-”PID、CPU ID、标志、时间戳(秒)和事件名称。其余的是跟踪点的格式字符串。

在这里插入图片描述


在这里插入图片描述

echo 0 > events/block/block_rq_issue/enable

从这个例子中可以看出,跟踪点在事件下的目录结构中有控制文件。 每个跟踪系统都有一个目录(例如,“block”)和每个事件的子目录(例如,“block_rq_issue”):

在这里插入图片描述


这些控制文件记录在 Linux 源代码的 Documentation/trace/events.rst 下,在此示例中,启用文件用于打开和关闭跟踪点。 其他文件提供过滤和触发功能。

3.2 Filter

可以包含过滤器以仅在满足布尔表达式时记录事件。 它有一个受限制的语法:

field operator value

(1)数字运算符是以下之一:==、!=、<、<=、>、>=、&;

(2)对于字符串:==、!=、~。

(3)“~”运算符执行 shell glob 样式的匹配,带有通配符:*、?、[]。

这些布尔表达式可以用括号分组并使用:&&、|| 组合。

备注:
通配符*:表示字符在匹配模式的文本中出现0次或多次
通配符?:表示字符在匹配模式的文本中出现0次或1次
通配符[]: []表示字符组,可以定义用来匹配文本模式中某个位置的一组字符。如果字符组中某个字符出现在了数据流中,就匹配该模式。

例如,以下对已启用的 block:block_rq_insert 跟踪点设置过滤器以仅跟踪字节字段大于 64 KB 的事件:

echo 'bytes > 65536' > events/block/block_rq_insert/filter

输出现在只包含较大的 I/O。

echo 0 > events/block/block_rq_insert/filter //echo 0 重置过滤器

3.3 Trigger

触发事件时,触发器会运行额外的跟踪命令。 该命令可能是启用或禁用其他跟踪、打印堆栈跟踪或获取跟踪缓冲区的快照。 当前未设置触发器时,可以从触发器文件中列出可用的触发器命令。 例如:

cat events/block/block_rq_issue/trigger

在这里插入图片描述


触发器的一个用例是当您希望查看导致错误条件的事件时:可以将触发器放置在错误条件上,该条件可以禁用跟踪 (traceoff),以便跟踪缓冲区仅包含先前的事件,或者获取 一个快照(snapshot)来保存它。

触发器可以通过使用 if 关键字与上一节中显示的过滤器结合使用。 这可能是匹配错误条件或有趣事件所必需的。 例如,要在大于 64 KB 的块 I/O 排队时停止记录事件:

 echo 'traceoff if bytes > 65536' > events/block/block_rq_insert/trigger

四 、kprobes

参考:Kprobe-based Event Tracing

这些事件类似于基于跟踪点的事件。 它不是基于 Tracepoint,而是基于 kprobes(kprobe 和 kretprobe)。 所以它可以探测 kprobes 可以探测的任何地方(这意味着,除了那些带有 __kprobes/nokprobe_inline 注释和那些标记为 NOKPROBE_SYMBOL 的函数之外的所有函数)。 与基于 Tracepoint 的事件不同,它可以动态添加和删除.

要启用此功能,请使用 CONFIG_KPROBE_EVENTS=y 构建内核。

与events tracer(tracepoint)类似,这不需要通过 current_tracer 激活。 取而代之的是,通过 /sys/kernel/debug/tracing/kprobe_events 添加探测点,并通过 /sys/kernel/debug/tracing/events/kprobes//enable 启用它。

您也可以使用 /sys/kernel/debug/tracing/dynamic_events 而不是 kprobe_events。 该接口也将提供对其他动态事件的统一访问。

kprobes 是内核动态检测机制,允许我们跟踪函数任意位置,还可用于获取函数参数与结果返回值。kprobe 机制跟踪函数须是 available_filter_functions 列表中的子集。

kprobes 创建 kprobe 事件供跟踪器使用,它与 Ftrace 共享 tracefs 输出和控制文件。kprobes 类似于 Ftrace 函数跟踪器,因为它们跟踪核函数。然而,kprobes 可以进一步定制,可以放置在函数偏移量(单独的指令)上,并且可以报告函数参数和返回值。

4.1 Event Tracing

每个探针事件过滤功能允许您在每个探针上设置不同的过滤器,并为您提供将在跟踪缓冲区中显示的参数。 如果在 kprobe_events 中的 ‘p:’ 或 ‘r:’ 之后指定了事件名称,它会在 tracking/events/kprobes/ 下添加一个事件,在该目录中您可以看到 id、enable、format 、filter 和 trigger。

例如,以下使用 kprobes 检测 do_nanosleep() 内核函数:

echo 'p:brendan do_nanosleep' >> kprobe_events
echo 1 > events/kprobes/brendan/enable
cat trace | more

在这里插入图片描述

enable:
You can enable/disable the probe by writing 1 or 0 on it.

format:
This shows the format of this probe event.

filter:
You can write filtering rules of this event.

id:
This shows the id of this probe event.

trigger:
This allows to install trigger commands which are executed when the event is hit 

在这里插入图片描述

echo 0 > events/kprobes/brendan/enable
echo '-:brendan' >> kprobe_events

通过将特殊语法附加到 kprobe_events 来创建和删除 kprobe。 创建后,它会与跟踪点一起出现在 events 目录中,并且可以以类似的方式使用。kprobe 语法在 Documentation/trace/kprobetrace.rst 下的内核源代码中有完整说明。kprobes 能够跟踪内核函数的进入和返回以及函数偏移量。

kprobe_events 概要:

 p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]  : Set a probe
 r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]  : Set a return probe
 p:[GRP/]EVENT] [MOD:]SYM[+0]%return [FETCHARGS]       : Set a return probe
 -:[GRP/]EVENT                                         : Clear a probe

GRP            : Group name. If omitted, use "kprobes" for it.
EVENT          : Event name. If omitted, the event name is generated
                 based on SYM+offs or MEMADDR.
MOD            : Module name which has given SYM.
SYM[+offs]     : Symbol+offset where the probe is inserted.
SYM%return     : Return address of the symbol
MEMADDR        : Address where the probe is inserted.
MAXACTIVE      : Maximum number of instances of the specified function that
                 can be probed simultaneously, or 0 for the default value
                 as defined in Documentation/trace/kprobes.rst section 1.3.1.

FETCHARGS      : Arguments. Each probe can have up to 128 args.
 %REG          : Fetch register REG
 @ADDR         : Fetch memory at ADDR (ADDR should be in kernel)
 @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol)
 $stackN       : Fetch Nth entry of stack (N >= 0)
 $stack        : Fetch stack address.
 $argN         : Fetch the Nth function argument. (N >= 1) (\*1)
 $retval       : Fetch return value.(\*2)
 $comm         : Fetch current task comm.
 +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4)
 \IMM          : Store an immediate value to the argument.
 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
                 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
                 (x8/x16/x32/x64), "string", "ustring" and bitfield
                 are supported.

 (\*1) only for the probe on function entry (offs == 0).
 (\*2) only for return probe.
 (\*3) this is useful for fetching a field of data structures.
 (\*4) "u" means user-space dereference. See :ref:`user_mem_access`.

在上面的示例中,字符串“p:brendan do_nanosleep”为内核符号 do_nanosleep() 创建了一个名为“brendan”的探针 (p:)。 字符串“-:brendan”删除名称为“brendan”的探测。

4.2 Arguments

与函数跟踪不同,kprobes 可以检查函数参数和返回值。 例如,这里是前面跟踪的 do_nanosleep() 函数的声明,来自 kernel/time/hrtimer.c,其中突出显示了参数变量类型:

static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
{
	hrtimer_init_sleeper(t, current);

	do {
		set_current_state(TASK_INTERRUPTIBLE);
		hrtimer_start_expires(&t->timer, mode);

		if (likely(t->task))
			freezable_schedule();

		hrtimer_cancel(&t->timer);
		mode = HRTIMER_MODE_ABS;

	} while (t->task && !signal_pending(current));

	__set_current_state(TASK_RUNNING);

	return t->task == NULL;
}

跟踪 Intel x86_64 系统上的前两个参数并将它们打印为十六进制(默认值):

echo 'p:brendan do_nanosleep hrtimer_sleeper=$arg1 hrtimer_mode=$arg2' >> kprobe_events

在这里插入图片描述

echo 0 > events/kprobes/brendan/enable
echo '-:brendan' >> kprobe_events

在第一行的事件描述中添加了额外的语法:例如,字符串“hrtimer_sleeper=$arg1”跟踪函数的第一个参数并使用自定义名称“hrtimer_sleeper”。 这已在输出中突出显示。
在 Linux 4.20 中添加了访问 a r g 1 、 arg1、 arg1arg2 等函数的参数。 以前的 Linux 版本需要使用寄存器名称。 这是使用寄存器名称的等效 kprobe 定义:

 echo 'p:brendan do_nanosleep hrtimer_sleeper=%di hrtimer_mode=%si' >> kprobe_events

要使用寄存器名称,您需要知道处理器类型和使用的函数调用约定。 x86_64 uses the AMD64 ABI,所以前两个参数在寄存器 rdi 和 rsi 中可用。

4.3 Return Values

返回值的特殊别名 $retval 可用于 kretprobes。 以下示例使用它来显示 do_nanosleep() 的返回值:

echo 'r:brendan do_nanosleep ret=$retval' >> kprobe_events
echo 1 > events/kprobes/brendan/enable
cat trace_pipe

在这里插入图片描述

echo 0 > events/kprobes/brendan/enable
echo '-:brendan' >> kprobe_events

此输出表明,在跟踪时,do_nanosleep() 的返回值始终为“0”(成功)。

4.4 Filters and Triggers

Filters and triggers可以在 events/kprobes/… 目录中使用,就像 tracepoints一样。
这是带有参数的 do_nanosleep() 上早期 kprobe 的格式文件(来自小节 4.2 Arguments):

在这里插入图片描述


请注意,我的自定义 hrtimer_sleeper 和 hrtimer_mode 变量名称作为可与过滤器一起使用的字段可见。 例如:

echo 'hrtimer_mode != 1' > events/kprobes/brendan/filter

这只会跟踪 hrtimer_mode 不等于 1 的 do_nanosleep() 调用。

4.5 kprobe Profiling

启用 kprobe 时,Ftrace 会计算它们的事件。 这些计数可以打印在 kprobe_profile 文件中。 例如:

echo 'p:brendan do_nanosleep' >> kprobe_events
echo 1 > events/kprobes/brendan/enable
cat trace_pipe
cat /sys/kernel/debug/tracing/kprobe_profile

在这里插入图片描述

通过 /sys/kernel/debug/tracing/kprobe_profile 检查探测命中和探测未命中的总数。 第一列是事件名称,第二列是探测命中数,第三列是探测未命中数。

event name             probe hits               probe miss-hits

虽然您已经可以使用 function profiler 获取函数计数,但我发现 kprobe 探查器可用于检查监控软件使用的始终启用的 kprobe,以防某些触发过于频繁而应禁用( 如果可能的话)。

五、ftrace_enabled

请注意,proc sysctl ftrace_enable 是函数跟踪器的大开/关开关。 默认情况下它是启用的(当内核中启用函数跟踪时)。 如果禁用,则禁用所有功能跟踪。 这不仅包括 ftrace 的函数跟踪器,还包括任何其他用途(perf、kprobes、堆栈跟踪、分析等)。
It cannot be disabled if there is a callback with FTRACE_OPS_FL_PERMANENT set registered.

请小心禁用此功能。

这可以通过以下方式禁用(和启用):

 sysctl kernel.ftrace_enabled=0
 sysctl kernel.ftrace_enabled=1

or

 echo 0 > /proc/sys/kernel/ftrace_enabled
 echo 1 > /proc/sys/kernel/ftrace_enabled

六、trace/trace_pipe/Snapshot

(1) trace file:

该文件以可读的格式保存跟踪的输出。 使用 O_TRUNC 标志打开此文件进行写入会清除环形缓冲区内容。 请注意,此文件不是消费者。 如果跟踪关闭(没有跟踪器运行,或 tracking_on 为零),每次读取时都会产生相同的输出。 当跟踪打开时,它可能会产生不一致的结果,因为它会尝试读取整个缓冲区而不消耗它。

cat trace

(2) trace_pipe file

输出与“trace”文件相同,但该文件旨在通过实时跟踪进行流式传输。 从此文件读取将阻塞,直到检索到新数据。 与“trace”文件不同,这个文件是一个消费者。 这意味着从此文件读取会导致顺序读取以显示更多当前数据。 一旦从这个文件中读取数据,它就会被消耗掉,并且不会通过顺序读取再次读取。 “trace”文件是静态的,如果tracer没有添加更多数据,每次读取都会显示相同的信息。

cat trace_pipe

trace_pipe 输出的内容与trace文件相同,但对跟踪的影响不同。 每次从 trace_pipe 读取都会被消耗。 这意味着后续的读取会有所不同。The trace is live.

请注意,在添加更多输入之前,读取 trace_pipe 文件将被阻塞。 这与trace文件相反。 如果任何进程打开trace文件进行读取,它实际上将禁用跟踪并阻止添加新条目。 trace_pipe 文件没有这个限制。

(3)Snapshot

cat snapshot

CONFIG_TRACER_SNAPSHOT 使所有非延迟跟踪器都可以使用通用快照功能。 (记录最大延迟的延迟跟踪器,例如“irqsoff”或“wakeup”,不能使用此功能,因为它们已经在内部使用快照机制。)

快照在特定时间点保留当前跟踪缓冲区,而不会停止跟踪。 Ftrace 将当前缓冲区与备用缓冲区交换,并在新的当前(=先前备用)缓冲区中继续跟踪。

“tracing”中的以下tracefs文件与此功能相关:
snapshot:
这用于拍摄快照并读取快照的输出,echo 1 到该文件中以分配一个备用缓冲区并拍摄快照(交换),然后以与“跟踪”相同的格式从该文件中读取快照,读取快照和跟踪都可以并行执行。 分配备用缓冲区时,echo 0 会释放它,echo else(除0和1以为的其它正整数,比如2、3等等) 值会清除快照内容。

在这里插入图片描述

echo 1 > events/sched/enable
echo 1 > snapshot
cat snapshot

在这里插入图片描述

在这里插入图片描述

echo 0 > events/sched/enable
echo 0 > snapshot
cat snapshot
echo > trace

在这里插入图片描述

echo 3 > snapshot
cat snapshot

在这里插入图片描述

如果您在当前跟踪器是延迟跟踪器之一时尝试使用此快照功能,您将获得以下结果:

在这里插入图片描述

七、trace entries

在诊断内核中的问题时,数据过多或不足都会很麻烦。 文件 buffer_size_kb 用于修改内部跟踪缓冲区的大小。 列出的数字是每个 CPU 可以记录的条目数。 要知道完整大小,请将可能的 CPU 数乘以条目数。
(1)

# cat buffer_size_kb
1408 (units kilobytes)

(2)
或者简单地读取buffer_total_size_kb:

# cat buffer_total_size_kb
5632

(3)
要修改缓冲区,只需简单地echo一个数字(在 1024 字节段中):

# echo 10000 > buffer_size_kb
# cat buffer_size_kb
10000 (units kilobytes)

(4)
它将尝试尽可能多地分配。 如果分配过多,可能会导致 Out-Of-Memory 触发。

# echo 1000000000000 > buffer_size_kb
-bash: echo: write error: Cannot allocate memory
# cat buffer_size_kb
85

(5)
per_cpu缓冲区也可以单独修改:

# echo 10000 > per_cpu/cpu0/buffer_size_kb
# echo 100 > per_cpu/cpu1/buffer_size_kb

在这里插入图片描述

(6)
当 per_cpu 缓冲区不相同时,顶层的 buffer_size_kb 只会显示一个 X

# cat buffer_size_kb
X

写入顶层 buffer_size_kb 会将所有缓冲区重置为相同。

八、Filter commands

set_ftrace_filter 接口支持的命令很少。 跟踪命令具有以下格式:

<function>:<command>:<parameter>

支持以下命令:

8.1 mod

此命令启用每个模块的功能过滤。 参数定义模块。 例如,如果只需要 ext3 模块中的 write* 函数,

echo ‘write*:mod:ext3’ > set_ftrace_filter

此命令与过滤器的交互方式与基于函数名称的过滤相同。 因此,在不同的模块中添加更多功能是通过将 (>>) 附加到过滤器文件来完成的。 通过添加“!”来删除特定的模块功能:

echo '!writeback*:mod:ext3' >> set_ftrace_filter

Mod 命令支持模块通配。 禁用对除特定模块以外的所有功能的跟踪:

echo '!*:mod:!ext3' >> set_ftrace_filter

禁用所有模块的跟踪,但仍跟踪内核:

echo '!*:mod:*' >> set_ftrace_filter

仅为内核启用过滤器:

echo '*write*:mod:!*' >> set_ftrace_filter

为模块通配启用过滤器:

echo '*write*:mod:*snd*' >> set_ftrace_filter

8.2 traceon/traceoff

这些命令在指定功能被命中时打开和关闭跟踪。 该参数确定跟踪系统打开和关闭的次数。 如果未指定,则没有限制。 例如,要在前 5 次遇到计划错误时禁用跟踪,请运行:

echo '__schedule_bug:traceoff:5' > set_ftrace_filter

当__schedule_bug被命中时,总是禁用跟踪:

echo '__schedule_bug:traceoff' > set_ftrace_filter

这些命令是累积的,无论它们是否附加到 set_ftrace_filter。 要删除命令,请在其前面加上“!”并删除参数:

echo '!__schedule_bug:traceoff:0' > set_ftrace_filter

上面删除了具有计数器的 __schedule_bug 的 traceoff 命令。 要删除没有计数器的命令:

echo '!__schedule_bug:traceoff' > set_ftrace_filter

8.3 snapshot

触发该函数时会触发快照:

echo 'native_flush_tlb_others:snapshot' > set_ftrace_filter

仅快照一次:

echo 'native_flush_tlb_others:snapshot:1' > set_ftrace_filter

要删除上述命令:

echo '!native_flush_tlb_others:snapshot' > set_ftrace_filter
echo '!native_flush_tlb_others:snapshot:0' > set_ftrace_filter

8.4 enable_event/disable_event

这些命令可以启用或禁用跟踪事件。 注意,因为函数跟踪回调非常敏感,当这些命令被注册时,跟踪点被激活,但在“软”模式下被禁用。 也就是说,将调用跟踪点,但不会被跟踪。 只要有触发它的命令,事件跟踪点就会保持这种模式。

echo 'try_to_wake_up:enable_event:sched:sched_switch:2' > \
      set_ftrace_filter

格式:

<function>:enable_event:<system>:<event>[:count]
<function>:disable_event:<system>:<event>[:count]

要删除事件命令:

echo '!try_to_wake_up:enable_event:sched:sched_switch:0' > \
      set_ftrace_filter
echo '!schedule:disable_event:sched:sched_switch' > \
      set_ftrace_filter

8.5 dump

当该函数被命中时,它会将 ftrace 环形缓冲区的内容转储到控制台。 如果您需要调试某些东西,并且想要在某个功能被命中时转储跟踪,这很有用。 也许它是在三重故障发生之前调用的函数,并且不允许您获得常规转储。

8.6 cpudump

当该函数被命中时,它会将当前 CPU 的 ftrace 环形缓冲区的内容转储到控制台。 与“dump”命令不同,它只为执行触发转储的函数的 CPU 打印环形缓冲区的内容。

8.7 stacktrace

当函数被命中时,会记录堆栈跟踪。

总结

以上就是ftrace的一些常规使用,主要参考了Systems.Performance.Enterprise.and.the.Cloud.2nd.Edition和kernel的doc。

参考资料

Systems.Performance.Enterprise.and.the.Cloud.2nd.Edition
https://www.kernel.org/doc/html/latest/trace/ftrace.html#

相关文章

linux常用进程通信方式包括管道(pipe)、有名管道(FIFO)、...
Linux性能观测工具按类别可分为系统级别和进程级别,系统级别...
本文详细介绍了curl命令基础和高级用法,包括跳过https的证书...
本文包含作者工作中常用到的一些命令,用于诊断网络、磁盘占满...
linux的平均负载表示运行态和就绪态及不可中断状态(正在io)的...
CPU上下文频繁切换会导致系统性能下降,切换分为进程切换、线...