基于msm-5.4 Android-12
一、翻译
=============
事件追踪
=============
: 作者: Theodore Ts'o
:更新:李泽凡和汤姆·扎努西
1. 简介
===============
无需创建自定义内核模块即可使用跟踪点(请参阅 Documentation/trace/tracepoints.rst)来使用事件跟踪基础设施注册探测函数。
并非所有跟踪点都可以使用事件跟踪系统进行跟踪; 内核开发人员必须提供代码片段,定义如何将跟踪信息保存到跟踪缓冲区中,以及如何打印跟踪信息。
2. 使用事件跟踪
=====================
2.1 通过'set_event'接口
---------------------------------
可用于跟踪的事件可以在文件 /sys/kernel/debug/tracing/available_events 中找到。
要启用特定事件,例如“sched_wakeup”,只需将其echo到 /sys/kernel/debug/tracing/set_event。 例如::
# echo sched_wakeup >> /sys/kernel/debug/tracing/set_event
.. 注意:: '>>' 是必要的,否则将禁用所有其它事件。
要禁用事件,请将带有感叹号前缀的事件名称echo到 set_event 文件::
# echo '!sched_wakeup' >> /sys/kernel/debug/tracing/set_event
要禁用所有事件,请在 set_event 文件中echo空行
# echo > /sys/kernel/debug/tracing/set_event
要启用所有事件,请将 ``*:*`` 或 ``*:`` echo到 set_event 文件::
# echo *:* > /sys/kernel/debug/tracing/set_event
事件被组织成子系统,例如 ext4、irq、sched 等,完整的事件名称如下所示:<subsystem>:<event>。 子系统名称是可选的,但它显示在 available_events 文件中。子系统中的所有事件都可以通过语法“<subsystem>:*”指定; 例如,要启用所有 irq 事件,可以使用命令::
# echo 'irq:*' > /sys/kernel/debug/tracing/set_event
2.2 通过“enable”开关
----------------------------
可用的事件也列在 /sys/kernel/debug/tracing/events/ 目录层次结构中。
启用事件“sched_wakeup”::
# echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
要禁用它::
# echo 0 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
启用 sched 子系统中的所有事件:
# echo 1 > /sys/kernel/debug/tracing/events/sched/enable
要启用所有事件::
# echo 1 > /sys/kernel/debug/tracing/events/enable
读取这些启用文件之一时,会出现四种结果:
- 0 - 该文件影响的所有事件均被禁用 - 1 - 该文件影响的所有事件均已启用 - X - 混合启用和禁用事件 - ? - 该文件不影响任何事件
2.3 启动选项
----------------
为了方便早期启动调试,使用boot option::
trace_event=[event-list]
event-list 是逗号分隔的事件列表。 事件格式请参见第 2.1 节。
3. 定义启用事件的跟踪点
=========================================
请参阅 samples/trace_events 中提供的示例
4. Event格式
===============
每个跟踪事件都有一个与其关联的“format”文件,其中包含已记录事件中每个字段的描述。 此信息可用于解析二进制跟踪流,也是查找可在事件过滤器中使用的字段名称的位置(请参阅第 5 节)。
它还以文本模式打印事件的格式字符串,以及用于分析的事件名称和 ID。
每个事件都有一组与其关联的“common”字段; 这些是以``common_`` 为前缀的字段(cat format看到)。 其他字段因事件而异,并对应于该事件的 TRACE_EVENT 定义中定义的字段。
format中的每个字段的形式如下:
field:field-type field-name; offset:N; size:N;
其中 offset 是跟踪记录中字段的偏移量,size 是数据项的大小(以字节为单位)。
例如,以下是“sched_wakeup”事件显示的信息:
# cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/format name: sched_wakeup ID: 60 format: field:unsigned short common_type; offset:0; size:2; field:unsigned char common_flags; offset:2; size:1; field:unsigned char common_preempt_count; offset:3; size:1; field:int common_pid; offset:4; size:4; field:int common_tgid; offset:8; size:4; field:char comm[TASK_COMM_LEN]; offset:12; size:16; field:pid_t pid; offset:28; size:4; field:int prio; offset:32; size:4; field:int success; offset:36; size:4; field:int cpu; offset:40; size:4; print fmt: "task %s:%d [%d] success=%d [%03d]", REC->comm, REC->pid, REC->prio, REC->success, REC->cpu
该事件包含 10 个字段,前 5 个是公共字段,其余 5 个是事件特定字段。 该事件的所有字段都是数值,除了“comm”,它是一个字符串,这对于事件过滤很重要。
5. 事件过滤
=================
可以通过将布尔“过滤表达式”与其关联来在内核中过滤跟踪事件。 一旦事件被记录到跟踪缓冲区中,就会根据与该事件类型关联的过滤器表达式检查其字段。 字段值与过滤器“匹配”的事件将出现在跟踪输出中,而值不匹配的事件将被丢弃。######## 没有关联过滤器的事件匹配所有内容,并且在没有为事件设置过滤器时是默认值。
5.1 表达式语法
--------------------
过滤表达式由一个或多个“谓词”组成,可以使用逻辑运算符“&&”和“||”组合这些谓词。 谓词只是一个子句,它将记录的事件中包含的字段值与常量值进行比较,并根据字段值是否匹配 (1) 或不匹配 (0) 返回 0 或 1::
field-name relational-operator value
括号可用于提供任意逻辑分组,双引号可用于防止 shell 将运算符解释为 shell 元字符。
可在过滤器中使用的字段名称可以在跟踪事件的“format”文件中找到(请参阅第 4 节)。
关系运算符取决于正在测试的字段的类型:
可用于数字字段的运算符有:==、!=、<、<=、>、>=、&
对于字符串字段,它们是:==、!=、~
glob (~) 接受通配符 (\*,?) 和字符类 ([)。 例如::
prev_comm ~ "*sh" prev_comm ~ "sh*" prev_comm ~ "*sh*" prev_comm ~ "ba*sh"
5.2 设置过滤器
-------------------
通过将过滤器表达式写入给定事件的“filter”文件来设置单个事件的过滤器。
例如::
# cd /sys/kernel/debug/tracing/events/sched/sched_wakeup # echo "common_preempt_count > 4" > filter
一个稍微复杂一点的例子:
# cd /sys/kernel/debug/tracing/events/signal/signal_generate # echo "((sig >= 10 && sig < 15) || sig == 17) && comm != bash" > filter
如果表达式中有错误,您在设置它时会收到“Invalid argument”错误,并且可以通过查看过滤器看到错误的字符串和错误消息,例如:
# cd /sys/kernel/debug/tracing/events/signal/signal_generate # echo "((sig >= 10 && sig < 15) || dsig == 17) && comm != bash" > filter -bash: echo: write error: Invalid argument # cat filter ((sig >= 10 && sig < 15) || dsig == 17) && comm != bash ^ parse_error: Field not found
目前,表示错误的插入符号 ('^') 始终出现在过滤字符串的开头; 即使没有更准确的位置信息,错误消息仍然应该有用。
5.3 清除过滤器
--------------------
要清除事件的过滤器,请在事件的 filter 文件中写入“0”。
要清除子系统中所有事件的过滤器,请向子系统的 filter 文件写入“0”。
5.3 子系统过滤器
--------------------
为了方便起见,可以通过将过滤器表达式写入子系统根目录下的过滤器文件中来作为一组设置或清除子系统中每个事件的过滤器。 但请注意,如果子系统内任何事件的过滤器缺少子系统过滤器中指定的字段,或者由于任何其他原因无法应用该过滤器,则该事件的过滤器将保留其先前的设置。 这可能会导致意外的过滤器混合,从而导致跟踪输出混乱(对于可能认为不同过滤器有效的用户来说)。 只有引用公共字段的过滤器才能保证成功传播到所有事件。
以下是一些子系统过滤器示例,也说明了上述几点:
清除sched子系统中所有事件的过滤器::
# cd /sys/kernel/debug/tracing/events/sched # echo 0 > filter # cat sched_switch/filter none # cat sched_wakeup/filter none
仅使用调度子系统中所有事件的公共字段设置过滤器(所有事件最终都使用相同的过滤器)::
# cd /sys/kernel/debug/tracing/events/sched # echo common_pid == 0 > filter # cat sched_switch/filter common_pid == 0 # cat sched_wakeup/filter common_pid == 0
尝试为 sched 子系统中的所有事件使用非公共字段设置过滤器(除了那些具有 prev_pid 字段的事件外,所有事件都保留其旧过滤器):
# cd /sys/kernel/debug/tracing/events/sched # echo prev_pid == 0 > filter # cat sched_switch/filter prev_pid == 0 # cat sched_wakeup/filter common_pid == 0
5.4 PID过滤
-----------------
与顶级事件目录位于同一目录中的 set_event_pid 文件将过滤所有事件,以防止跟踪任何未在 set_event_pid 文件中列出 PID 的任务。
# cd /sys/kernel/debug/tracing # echo $$ > set_event_pid # echo 1 > events/enable
仅跟踪当前任务的事件。
实验:
/sys/kernel/tracing # echo 2979 > set_event_pid /sys/kernel/tracing # echo sched_wakeup > set_event /sys/kernel/tracing # cat events/sched/sched_wakeup/filter none /sys/kernel/tracing # > trace; echo 1 > tracing_on; cat trace_pipe Binder:2979_4-7097 [003] d..6 4683.187122: sched_wakeup: comm=sh.smartcontrol pid=2979 prio=120 target_cpu=002 <...>-2979 [002] d..6 4683.187189: sched_wakeup: comm=StackTraceColle pid=3966 prio=120 target_cpu=003 sh.smartcontrol-2979 [006] dNh7 4683.449279: sched_wakeup: comm=cat pid=7361 prio=120 target_cpu=000 app-671 [003] d..6 4683.462235: sched_wakeup: comm=sh.smartcontrol pid=2979 prio=110 target_cpu=004 <idle>-0 [004] dNh4 4684.316512: sched_wakeup: comm=sh.smartcontrol pid=2979 prio=110 target_cpu=004
可以看到,一条trace中任意位置出现pid为2979的,都会过滤出来。
要添加更多 PID 而不会丢失已包含的 PID,请使用“>>”。
# echo 123 244 1 >> set_event_pid
6. 事件触发器
=================
跟踪事件可以有条件地调用触发器“命令”,这些命令可以采用各种形式,下面将详细描述; 例如,启用或禁用其他跟踪事件,或者每当命中跟踪事件时调用堆栈跟踪。 每当调用带有附加触发器的跟踪事件时,都会调用与该事件关联的触发器命令集。 任何给定的触发器还可以具有与其关联的第 5 节(事件过滤)中描述的相同形式的事件过滤器 - 仅当被调用的事件通过关联的过滤器时才会调用该命令。 如果没有过滤器与触发器关联,则它始终会通过。
通过将触发器表达式写入给定事件的“trigger”文件,可以将触发器添加到特定事件或从特定事件中删除触发器。
给定事件可以有任意数量的与其关联的触发器,但要遵守各个命令在这方面可能具有的任何限制。
事件触发器是在“软”模式之上实现的,这意味着每当跟踪事件有一个或多个与之关联的触发器时,即使该事件实际上并未启用,也会被激活,但在“软”模式下会被禁用。也就是说,跟踪点将被调用,但不会被跟踪,除非它实际上已启用。 该方案允许即使对于未启用的事件也可以调用触发器,并且还允许将当前事件过滤器实现用于有条件地调用触发器。
事件触发器的语法大致基于 set_ftrace_filter“ftrace 过滤器命令”的语法(请参阅 Documentation/trace/ftrace.rst 的“过滤器命令”部分),但存在重大差异,并且实现目前未绑定到它,所以要小心在两者之间进行概括。
注意:写入 trace_marker(请参阅 Documentation/trace/ftrace.rst)还可以启用写入 /sys/kernel/tracing/events/ftrace/print/trigger 的触发器。
6.1 表达式语法
--------------------
通过将命令echo到“trigger”文件来添加触发器:
# echo 'command[:count] [if filter]' > trigger
通过echo相同的命令但以“!”开头到“trigger”文件来删除触发器::
# echo '!command[:count] [if filter]' > trigger
删除时,[if filter] 部分不会用于匹配命令,因此将其保留在“!”中 命令将完成与输入它相同的事情。
过滤器语法与上面“事件过滤”部分中描述的相同。
为了便于使用,使用“>”写入trigger文件当前仅添加或删除单个触发器,并且没有显式的“>>”支持(“>”实际上表现得像“>>”)或截断支持来删除所有触发器 (每添加一项都必须使用“!”。)
实测,只有下面这些可选:
/sys/kernel/tracing # cat events/sched/sched_wakeup/trigger # Available triggers: # traceon traceoff stacktrace enable_event disable_event
6.2 支持的触发命令
------------------------------------------
支持以下命令:
- enable_event/disable_event
每当触发事件发生时,这些命令都可以启用或禁用另一个跟踪事件。 当这些命令被注册时,另一个跟踪事件被激活,但在“soft”模式下被禁用。 也就是说,跟踪点将被调用,但不会被跟踪。 只要存在可以触发事件跟踪点的有效触发器,事件跟踪点就会保持在此模式。
例如,以下触发器会导致在输入 read 系统调用时跟踪 kmalloc 事件,并且末尾的 :1 指定此启用仅发生一次:
# echo 'enable_event:kmem:kmalloc:1' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger
当读取系统调用退出时,以下触发器会导致 kmalloc 事件停止被跟踪。 此禁用发生在每次读取系统调用退出时::
# echo 'disable_event:kmem:kmalloc' > /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger
格式为::
enable_event:<system>:<event>[:count] disable_event:<system>:<event>[:count]
要删除上述命令::
# echo '!enable_event:kmem:kmalloc:1' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger # echo '!disable_event:kmem:kmalloc' > /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger
请注意,每个触发事件可以有任意数量的 enable/disable_event 触发器,但每个触发事件只能有一个触发器。 例如 sys_enter_read 可以具有启用 kmem:kmalloc 和 sched:sched_switch 的触发器,但不能有两个 kmem:kmalloc 版本,例如 kmem:kmalloc 和 kmem:kmalloc:1 或 'kmem:kmalloc if bytes_req == 256' 和 'kmem: kmalloc if bytes_alloc == 256' (不过,它们可以组合成 kmem:kmalloc 上的单个过滤器)。
- stacktrace
每当触发事件发生时,此命令都会在跟踪缓冲区中转储堆栈跟踪。
例如,每次命中 kmalloc 跟踪点时,以下触发器都会转储堆栈跟踪:
# echo 'stacktrace' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger //这会打印完整的内核栈
以下触发器在发生 kmalloc 请求大小 >= 64K 的前 5 次时转储堆栈跟踪::
# echo 'stacktrace:5 if bytes_req >= 65536' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger //不成功
格式为:: stacktrace[:count]
要删除上述命令::
# echo '!stacktrace' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger # echo '!stacktrace:5 if bytes_req >= 65536' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
者也可以通过以下更简单地删除(不使用过滤器)::
# echo '!stacktrace:5' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
请注意,每个触发事件只能有一个堆栈跟踪触发器。
- snapshot
每当触发事件发生时,此命令都会触发快照。
每次拔出 depth > 1 的块请求队列时,以下命令都会创建一个快照。如果您当时正在跟踪一组事件或函数,则快照跟踪缓冲区将在触发事件发生时捕获这些事件:
# echo 'snapshot if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
仅快照一次::
# echo 'snapshot:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
要删除上述命令::
# echo '!snapshot if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger # echo '!snapshot:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
请注意,每个触发事件只能有一个快照触发器。
- traceon/traceoff
当指定事件发生时,这些命令会打开和关闭跟踪。 该参数决定跟踪系统打开和关闭的次数。 如果未指定,则没有限制。
以下命令将在第一次拔出 depth > 1 的块请求队列时关闭跟踪。如果您当时正在跟踪一组事件或函数,则可以检查跟踪缓冲区以查看导致事件发生的顺序,直到触发事件::
# echo 'traceoff:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
当 nr_rq > 1 时始终禁用跟踪::
# echo 'traceoff if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
要删除上述命令::
# echo '!traceoff:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger # echo '!traceoff if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
请注意,每个触发事件只能有一个 traceon 或 traceoff 触发器。
- hist
此命令将事件命中聚合到哈希表中,该哈希表以一个或多个跟踪事件格式字段(或堆栈跟踪)以及从一个或多个跟踪事件格式字段和/或事件计数(命中计数)派生的一组运行总计为关键字。
有关详细信息和示例,请参阅 Documentation/trace/histogram.rst。
标签:kernel,ftrace,sched,tracing,echo,sys,事件,rst,events From: https://www.cnblogs.com/hellokitty2/p/18212448