Linux之perf(6)report统计

Author:Onceday Date:2023年9月23日

漫漫长路,才刚刚开始…

注:该文档内容采用了GPT4.0生成的回答,部分文本准确率可能存在问题

参考文档:

文章目录

1. 概述

命令 perf-report 是一种性能分析工具,用于读取 perf record 创建的 perf.data 文件,然后显示性能分析报告。

这个命令的正确使用方法是:

perf report [选项]

其中,选项 可以是以下的一种或多种:

  • -i <文件>--input=<文件>:从指定的文件中读取数据,而不是默认的 perf.data 文件。
  • -F <字段>--fields=<字段>:选择要在报告中显示的字段。
  • -s <排序字段>--sort=<排序字段>:选择按照哪个字段对报告进行排序。

例如,如果你想读取一个名为 mydata.perf 的文件,并按照 CPU 时间排序,你可以使用以下命令:

perf report -i mydata.perf -s cpu
1.1参数概览
2. 功能介绍
2.1 显示不同CPU模式下的样本百分比

--show-cpu-utilization,显示不同CPU模式下的样本百分比。

perf record--show-cpu-utilization选项用于显示不同CPU模式下的样本百分比。它可以帮助你理解CPU在用户模式、内核模式、空闲状态和其他状态中分别花费了多少时间。

例如,运行以下命令:

perf record --show-cpu-utilization [Your Program]

在你的程序运行结束后,perf会生成一个包含CPU利用率信息的记录文件。你可以使用perf report命令来查看这个文件。注意,这个选项可能需要特定版本的Linux内核才能使用,所以请确保你的系统支持这个功能。

2.2 指定进程名列表

-c, --comms=,只考虑这些comms中的符号。理解 file://filename 条目的CSV。此选项将影响overhead列的百分比。更多信息请查看 --percentage选项。

perf record-c--comms=选项允许你指定仅考虑哪些进程的符号(symbols)。你可以提供一个包含进程名的CSV文件,或者直接在命令行中指定进程名。

例如,如果你只想考虑名为myProcess1myProcess2的进程,你可以运行以下命令:

perf record -c myProcess1,myProcess2 [Your Program]

或者,如果你有一个包含进程名的CSV文件(例如,myProcesses.csv),你可以运行以下命令:

perf record --comms=file://myProcesses.csv [Your Program]

注意,--comms=选项会影响overhead列的百分比,因为它改变了perf所考虑的符号的总数。你可以使用--percentage选项来查看或更改overhead的计算方式。

2.3 指定动态库列表

-d, --dsos=,只考虑这些dsos中的符号。理解 file://filename 条目的CSV。此选项将影响overhead列的百分比。更多信息请查看 --percentage选项。

perf record-d--dsos=选项允许你指定仅考虑哪些动态共享对象(Dynamic Shared Objects,简称DSOs)中的符号。你可以提供一个包含DSO名的CSV文件,或者直接在命令行中指定DSO名。

例如,如果你只想考虑名为myDSO1.somyDSO2.so的动态共享对象,你可以运行以下命令:

perf record -d myDSO1.so,myDSO2.so [Your Program]

或者,如果你有一个包含DSO名的CSV文件(例如,myDSOs.csv),你可以运行以下命令:

perf record --dsos=file://myDSOs.csv [Your Program]

注意,--dsos=选项会影响overhead列的百分比,因为它改变了perf所考虑的符号的总数。你可以使用--percentage选项来查看或更改overhead的计算方式。

2.4 指令展示的符号

-S, --symbols=,只考虑这些符号。理解 file://filename 条目的CSV。此选项将影响overhead列的百分比。更多信息请查看 --percentage选项。

perf record-S--symbols=选项允许你指定仅考虑哪些符号。你可以提供一个包含符号名的CSV文件,或者直接在命令行中指定符号名。

例如,如果你只想考虑名为mySymbol1mySymbol2的符号,你可以运行以下命令:

perf record -S mySymbol1,mySymbol2 [Your Program]

或者,如果你有一个包含符号名的CSV文件(例如,mySymbols.csv),你可以运行以下命令:

perf record --symbols=file://mySymbols.csv [Your Program]

注意,--symbols=选项会影响overhead列的百分比,因为它改变了perf所考虑的符号的总数。你可以使用--percentage选项来查看或更改overhead的计算方式。

--symbol-filter=,只显示与此过滤器(部分)匹配的符号。

perf record--symbol-filter=选项允许你指定一个过滤器,只有与此过滤器(全名或部分名称)匹配的符号才会被显示。

例如,如果你想只显示名称中包含mySymbol的符号,你可以运行以下命令:

perf record --symbol-filter=mySymbol [Your Program]

-U, --hide-unresolved, 只显示已解析到符号的条目。

perf record-U--hide-unresolved选项允许你只显示已解析到符号的条目。这意味着,如果一个条目无法解析到具体的符号,那么该条目将不会被显示。

例如,运行以下命令:

perf record -U [Your Program]

在这种情况下,perf将只记录那些可以解析到具体符号的事件,无法解析的将被忽略。

2.5 指定排序的关键字

-s, --sort=,根据给定的键对直方图条目进行排序 - 可以以CSV格式指定多个键。可用的排序键包括:

pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight, cgroup_id, addr...

每个键的含义如下:

在默认情况下,将使用comm,dso和symbol键进行排序(即–sort comm,dso,symbol)

此外,当使用--branch-stack选项时,还有更多的排序键可用,包括:

默认的排序键被改为comm, dso_from, symbol_from, dso_to和symbol_to,具体可以参考’–branch-stack’。

当指定了symbol作为排序键时,"IPC"和"IPC Coverage"这两列会自动启用。"IPC"列报告每个函数的平均每周期指令数(IPC),"IPC Coverage"列报告在该函数中采样到的IPC的指令占比。如果IPC较低,可能表示函数执行时存在性能瓶颈,如内存访问瓶颈。如果一个函数的开销很大且IPC低,那么值得进一步分析以优化其性能

如果使用了--mem-mode选项,以下排序键也可用(与–branch-stack不兼容):symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline, blocked

默认的排序键被改为local_weight, mem, sym, dso, symbol_daddr, dso_daddr, snoop, tlb, locked, blocked, local_ins_lat,具体可以参考’–mem-mode’。

如果数据文件中有跟踪点事件,以下的动态排序键也可用:trace, trace_fields, [<event>.]<field>[/raw]

trace:以单列形式美化打印的跟踪输出

trace_fields:跟踪点中的字段,分别放在不同的列中

<field name>:特定字段的可选事件和字段名称

最后一种形式由事件名称和字段名称组成。如果省略了事件名称,它会搜索所有事件以匹配字段名称。匹配的字段只会显示在具有该字段的事件中。事件名称支持子字符串匹配,因此用户无需每次指定完整的子系统和事件名称。例如,'sched:sched_switch'事件可以简化为'switch',只要不会引起歧义。此外,事件可以通过其索引(从1开始)来指定,前面带有'%'。所以'%1'是第一个事件,'%2'是第二个,依此类推。

字段名称可以带有'/raw'后缀,这将禁用美化打印并显示原始字段值,如十六进制数字。--raw-trace选项对所有动态排序键都有相同的效果。

如果数据文件中的所有事件都是跟踪点,那么默认的排序键会改为’trace’。

2.6 指定输出字段

-F, --fields=,指定输出字段 - 可以以CSV格式指定多个键。以下字段可用:overhead、overhead_sys、overhead_us、overhead_children、sample和period。此外,它还可以包含任何排序键。

默认情况下,未在-F中指定的所有排序键将自动附加。如果键以前缀 ‘+’ 开头,那么它将把指定的字段追加到默认字段顺序中。例如:perf report -F +period,sample

在这个指令中,-F--fields选项允许用户定义希望在报告中显示的字段。这些字段可以包括诸如overhead(总体开销)、overhead_sys(系统开销)、overhead_us(用户开销)、overhead_children(子进程开销)、sample(样本)和period(周期)等。如果你想在默认的字段组合中添加一些新的字段,你可以在字段名之前加上 + 前缀。例如,如果你想在默认字段中添加periodsample,你可以使用命令 perf report -F +period,sample

需要注意的是,如果没有在 -F 选项中指定字段,perf record 将会自动添加所有可用的排序键。

2.7 函数正则表达式匹配

-p, --parent=[regex],一个用于识别父项(即函数的调用者)的正则表达式过滤器。父项是此函数的调用者,并通过调用链进行搜索,因此需要记录调用链信息。模式采用扩展正则表达式格式,默认为" do_page_fault",请参见 --sort parent。

在这个选项中,-p--parent选项允许用户使用正则表达式来过滤和识别函数的调用者。这在研究函数调用链时非常有用。这个正则表达式需要在已经记录了调用链信息的情况下使用。

默认的正则表达式是 "^sys_|^do_page_fault",这个表达式匹配以 “sys_” 或 “do_page_fault” 开头的函数。如果你想过滤和排序父函数,你可以使用 --sort parent 选项。

例如,如果你只对以 “my_function” 开头的父函数感兴趣,你可以这样使用 perf record 命令:perf record -p "^my_function"

请注意,正则表达式使用的是扩展的格式,所以你可以使用如 *+? 等符号来创建更复杂的匹配模式。

2.8 指定字段分割符

-t, --field-separator=,使用特殊的分隔符字符,而不是用空格填充,将符号名(和其他输出)中的所有此类分隔符替换为.字符,因此这是唯一的非法分隔符。

在这个选项中,-t--field-separator选项允许用户定义一个特殊的字段分隔符。这个分隔符将用于代替默认的空格分隔符,同时所有的符号名(以及其他输出)中的这种分隔符都将被替换为.字符。

举个例子,如果你想用逗号 , 来分隔字段,你可以这样使用 perf record 命令:perf record -t ,。这将导致所有的 , 在符号名和其他输出中都被替换为 .。这意味着 , 是唯一不能作为分隔符的字符。请注意,如果你的符号名或者其他输出中包含了 ,,那么这个 , 会被替换为 .

这个功能在你需要导出 perf record 的输出到其他处理数据的工具(如Excel或R)时非常有用,因为这些工具通常可以接受 , 分隔的数据,但不能接受空格分隔的数据。

2.9 指定调用栈参数

使用类型、最小百分比阈值、打印限制、调用顺序、排序键、可选的分支和值显示调用链。注意,排序并非固定的,因此任何参数都可以按任意顺序给出。唯一的例外是打印限制,它应该在阈值之后给出。

print_type 可以是以下其中之一:

  • flat:单列,线性展示调用链。
  • graph:使用图形树,显示绝对开销率(默认)
  • fractal:类似 graph,但显示相对率。树的每个分支被视为一个新的已分析对象。
  • folded:在一行中显示调用链,用分号分隔
  • none:禁用调用链显示

threshold是一个百分比值,指定了包含在输出调用图中的最小百分比。默认值为 0.5%。

print_limit仅在使用 stdio 接口时应用。它的作用是限制单个 hist 条目中的调用图条目数量。注意,它需要在阈值之后给出(但不一定是连续的),默认值为 0(无限制)。

order 可以是以下其中之一(默认值是 ‘caller’,当使用 --children 时,否则是 ‘callee’):

  • callee:基于被调用者的调用图。
  • caller:反转的基于调用者的调用图。

sort_key 可以是:

  • function:基于函数比较(默认)
  • address:基于各个代码地址比较
  • srcline:基于源文件名和行号比较

branch 可以是:

  • branch:在可用时,将最后一次分支信息包含在调用图中,--branch-history进行此操作。

value 可以是:

  • percent:显示开销百分比(默认)
  • period:显示事件周期
  • count:显示事件计数

这个选项提供了很多定制调用图的方式。例如,你可以选择打印类型(print_type),设置百分比阈值(threshold),限制打印数量(print_limit),设置调用顺序(order),选择排序键(sort_key),是否包含分支信息(branch),以及选择显示的值类型(value)。

例如,如果你想查看一个基于函数的、以分号分隔的、不包含小于1%开销的调用链,你可以使用如下命令:perf report --call-graph=folded,1,function

2.10 累积父项输出

--children,将子项的调用链积累到父项条目,这样它们就可以在输出中显示。输出将有一个新的 “Children” 列,并按数据排序。它需要记录调用链。具体详情请参见 ‘overhead calculation’ 部分。默认启用,使用 --no-children 禁用。

这个--children选项允许你在输出中包含一个新的"Children"列,这个列包含了子项的调用链信息。这个选项需要调用链信息已经被记录。

添加这个选项后,输出将会按照"Children"列的数据进行排序。这个功能对于理解一个函数的子函数如何影响其性能非常有用。

请注意,--children选项默认是启用的,如果你不想包含"Children"列,你可以使用--no-children选项来禁用它。

关于如何计算开销(overhead),你可以查阅文档的’overhead calculation’部分来获取更多信息。

2.11 设置调用栈的最大解析深度

--max-stack,在解析调用链时设置堆栈深度限制,超过指定深度的内容将被忽略。这是信息丢失和更快处理之间的权衡,尤其适用于可能有很长调用链堆栈的工作负载。注意,当使用 --itrace 选项时,如果合成的调用链大小更大,将覆盖此值,默认值:127。

这个--max-stack选项允许你设置在解析调用链时的堆栈深度限制。这意味着,超过你设置的限制的堆栈深度将会被忽略。

这个选项是一个权衡。如果你设置了较低的堆栈深度,处理将会更快,但你可能会丢失一些信息。反之,如果你设置了较高的堆栈深度,你将获得更完整的信息,但处理可能会慢一些。

请注意,如果你使用了--itrace选项,并且合成的调用链大小大于你设置的--max-stack值,那么实际的堆栈深度将会是合成的调用链大小。

默认的--max-stack值是127。如果你没有指定--max-stack选项,那么将使用这个默认值。

2.12 基于倒置的调用图

-G, --inverted,基于倒置的调用者的调用图的别名。

这个-G--inverted选项是为倒置的调用者基础的调用图设置的别名。当你使用这个选项时,会生成一个倒置的调用图,这意味着调用关系是反向的,从被调用方向调用者方向展示。

例如,正常的调用关系是 A -> B -> C,其中 A 调用了 B,B 调用了 C。在倒置的调用图中,这个关系会被展示为 C -> B -> A。

这个选项对于理解函数如何被其它函数调用,以及分析调用路径非常有用。它可以帮助你更好地理解程序的运行流程,并找出可能的性能瓶颈。

2.13 通过命令行配置彩色输出

--stdio-color,always, never 或 auto,允许通过命令行配置彩色输出,此外还可以通过 “color.ui” .perfconfig 进行配置。使用 --stdio-color always 即使在重定向到管道或文件时也能生成彩色输出。只使用 --stdio-color 等同于使用 always。

这个--stdio-color选项用于设置是否在输出中包含颜色。可用的值包括alwaysneverauto

  • always:这个选项表示总是在输出中包含颜色,即使输出被重定向到管道或文件。

  • never:这个选项表示从不在输出中包含颜色。

  • auto:这个选项表示只有当输出设备是终端时才在输出中包含颜色。

此外,你还可以在.perfconfig文件的color.ui选项中设置是否包含颜色。如果你在命令行中使用了--stdio-color选项,那么这个选项的设置将覆盖.perfconfig文件中的设置。

如果你只使用了--stdio-color选项,而没有指定alwaysneverauto,那么这等同于使用了always选项。

例如,如果你想在输出中总是包含颜色,即使输出被重定向到文件,你可以使用命令perf report --stdio-color always

2.14 使用采样分支地址

-b, --branch-stack,使用采样的分支地址而不是指令地址来构建直方图。要生成有意义的输出,perf.data 文件必须使用 perf record -b 或 perf record --branch-filter xxx 获取,其中 xxx 是一个分支过滤选项。perf report 能够自动检测 perf.data 文件是否包含分支堆栈,它将自动切换到分支视图模式,除非使用了 --no-branch-stack。

这个 -b--branch-stack 选项用于构建直方图时使用采样的分支地址,而不是指令地址。这个选项在分析程序的分支行为,例如预测错误的分支,或者是寻找分支频繁的代码区域时非常有用。

为了可以生成有意义的输出,你需要在使用 perf record 时使用 -b--branch-filter xxx 选项,其中 xxx 是一个分支过滤选项。这样,生成的 perf.data 文件将包含分支堆栈信息。

perf report 命令可以自动检测 perf.data 文件是否包含分支堆栈信息。如果包含,perf report 会自动切换到分支视图模式。但如果你使用了 --no-branch-stack 选项,perf report 就不会切换到分支视图模式。

例如,你可以使用如下命令来记录分支信息,并在报告中显示:

perf record -b ./my_program
perf report --branch-stack

--branch-history,将采样的分支地址添加到调用堆栈中。这允许检查程序到达每个样本的路径。数据收集必须使用 -b(或 -j)和 -g。

这个--branch-history选项用于将采样的分支地址添加到调用堆栈中。这样,你就可以检查程序到达每个样本的路径,这对于理解程序的执行流程和优化性能非常有帮助。

为了可以使用此选项,你需要在数据收集时使用-b(或-j)和-g选项。-b(或-j)选项用于记录分支信息,-g选项用于记录调用图。

例如,你可以使用如下命令来记录分支信息和调用图:

perf record -b -g ./my_program

然后,你可以使用--branch-history选项来查看报告:

perf report --branch-history

这将显示出程序到达每个样本的路径,包括分支信息。

2.15 使用样本的数据地址

--mem-mode,在构建直方图时,除了使用指令地址外,还使用样本的数据地址。要生成有意义的输出,必须使用 perf record -d -W 和特殊事件 -e cpu/mem-loads/p 或 -e cpu/mem-stores/p 获取 perf.data 文件。查看 perf mem 以获得更简单的访问方式。

--mem-mode选项用于在构建直方图时使用样本的数据地址,而不只是指令地址。这有助于分析程序的内存访问模式,例如查找导致缓存未命中或页面错误的数据访问。

为了使用这个选项,你需要在数据收集时使用perf record -d -W以及一个特殊的事件,例如-e cpu/mem-loads/p(用于记录内存加载事件)或-e cpu/mem-stores/p(用于记录内存存储事件)。这样,生成的perf.data文件将包含内存访问信息。

例如,你可以使用如下命令来记录内存加载事件:

perf record -d -W -e cpu/mem-loads/p ./my_program

然后,你可以使用--mem-mode选项来查看报告:

perf report --mem-mode

这将显示出程序的内存访问模式,包括每个样本的数据地址。

另外,perf mem提供了一种更简单的方式来记录和分析内存访问事件。你可以查看perf mem的文档以获取更多信息。

2.16 限制显示条目的百分比

--percent-limit,不显示开销低于该百分比的条目。(默认值:0)。请注意,此选项还设置了调用链的百分比限制(阈值)。然而,调用链阈值的默认值与直方图条目的默认值不同。请查看 --call-graph 选项以获取详细信息。

--percent-limit选项用于设置一个阈值,只显示开销超过该阈值的条目。例如,如果你设置--percent-limit为1.0,那么在报告中就只会显示开销超过1%的条目。

这个选项的默认值是0,意味着默认情况下会显示所有的条目,无论其开销如何。

请注意,这个选项也会设置调用链的百分比限制。也就是说,只有开销超过这个阈值的调用链才会被显示。

然而,调用链阈值的默认值与直方图条目的默认值不同。为了查看或设置调用链的阈值,你需要使用--call-graph选项。你可以查看--call-graph选项的文档以获取更多信息。

例如,你可以使用如下命令来生成一个报告,其中只显示开销超过1%的条目:

perf report --percent-limit 1.0
2.17 如何显示过滤条目的开销百分比

--percentage,确定如何显示过滤条目的开销百分比。可以通过 --comms,–dsos 和/或 --symbols 选项以及 TUI(线程,dso等)上的缩放操作应用过滤器。

“relative” 意味着它只相对于过滤条目,因此显示的条目总和将始终为100%。 “absolute” 意味着在应用过滤器之前和之后,它都保留原始值。

--percentage选项用于确定如何显示过滤条目的开销百分比。你可以通过--comms--dsos--symbols选项以及文本用户界面(TUI)上的放大/缩小操作来过滤条目。

此选项有两个可能的值:“relative"和"absolute”。

  • “relative”:这意味着显示的开销百分比是相对于过滤条目的。也就是说,过滤后显示的所有条目的开销百分比之和将始终为100%。

  • “absolute”:这意味着显示的开销百分比是绝对值,即在应用过滤器之前和之后,开销百分比保持不变。

例如,你可以使用以下命令来显示相对于过滤条目的开销百分比:

perf report --percentage relative

或者,你可以使用以下命令来显示绝对开销百分比:

perf report --percentage absolute
2.18 分析给定时间窗口内的样本

仅分析给定时间窗口内的样本:[start],[stop]。时间格式为秒.纳秒。如果没有给出开始时间(即,时间字符串为 ,x.y),则分析从文件开始处开始。如果没有给出停止时间(即,时间字符串为 x.y,),则分析直到文件结束。可以用空格分隔多个范围,这需要引用参数,例如 --time “1234.567,1234.789 1235,”

同样支持带有多个时间范围的时间百分比。时间字符串为 ‘a%/n,b%/m,…’ 或 ‘a%-b%,c%-%d,…’。

例如,选择第二个10%的时间片段:

perf report --time 10%/2

选择从0%到10%的时间片段:

perf report --time 0%-10%

选择第一和第二个10%的时间片段:

perf report --time 10%/1,10%/2

选择从0%到10%和30%到40%的片段:

perf report --time 0%-10%,30%-40%

--time选项用于只分析给定时间窗口内的样本。时间窗口的格式为 <start>,<stop>,其中时间是以秒.纳秒的格式表示的。

如果没有给出开始时间(即,时间字符串为 ,x.y),则分析将从文件开始处开始。如果没有给出结束时间(即,时间字符串为 x.y,),则分析将直达文件的结束。

此选项还支持指定多个时间范围,这些范围可以用空格分隔。在这种情况下,你需要给参数加上引号,例如 --time "1234.567,1234.789 1235,"

此外,这个选项还支持基于时间百分比的选择。你可以使用 a%/n,b%/m,...a%-b%,c%-d%,... 的格式来指定时间范围。在这种格式中,a%b% 分别表示时间的起始和结束百分比,nm 表示第 nm 个时间片段。

例如,你可以使用以下命令来选择第二个10%的时间片段:

perf report --time 10%/2

或者,你可以使用以下命令来选择从0%到10%和30%到40%的时间片段:

perf report --time 0%-10%,30%-40%
2.19 解码指令跟踪数据的选项

--itrace 是一个用于解码指令跟踪数据的选项。以下是各个选项的解释:

  • i:合成指令事件
  • y:合成周期事件
  • b:合成分支事件(Arm SPE的分支未命中)
  • c:合成分支事件(仅调用)
  • r:合成分支事件(仅返回)
  • x:合成事务事件
  • w:合成ptwrite事件
  • p:合成电源事件(包括Intel PT的PSB事件)
  • o:合成因使用aux-output而记录的其他事件(参考perf record)
  • I:合成中断或类似的(异步)事件(例如Intel PT事件跟踪)
  • e:合成错误事件
  • d:创建调试日志
  • f:合成一级缓存事件
  • m:合成最后一级缓存事件
  • M:合成内存事件
  • t:合成TLB事件
  • a:合成远程访问事件
  • g:合成调用链(与i或x一起使用)
  • G:在现有事件记录上合成调用链
  • l:合成最后一次分支条目(与i或x一起使用)
  • L:在现有事件记录上合成最后一次分支条目
  • s:跳过最初的一些事件
  • q:更快(较少详细)的解码
  • A:近似IPC
  • Z:更倾向于忽略时间戳(所谓的“无时间”解码)

默认的选项是所有事件,即相当于--itrace=iybxwpe,除了perf script默认为--itrace=ce

此外,对于指令事件,可以指定周期(默认100000,perf script默认为1),单位可以是:

  • i:指令
  • t:刻度
  • ms:毫秒
  • us:微秒
  • ns:纳秒(默认)

对于指令或事务事件,还可以指定调用链大小(默认16,最大1024)和最后一次分支条目数量(默认64,最大1024)。

类似于选项g和l,G和L的大小也可以被指定。在x86上,如果数据被大PEBS记录,G和L的效果会很差。详情请参阅linkperf:perf-intel-pt[1]手册页。

也可以跳过生成的一些最初的事件(指令,分支,事务,ptwrite,电源)。这对于忽略初始化代码很有用。例如,--itrace=i0nss1000000会跳过前一百万个指令。

‘e’选项可以跟随标志,这会影响哪些错误将会或不会被报告。每个标志前必须预加’+‘或’-'。这些标志包括:

  • o:溢出
  • l:丢失跟踪数据

如果支持,‘d’选项可以跟随标志,这会影响哪些调试消息将会或不会被记录。每个标志前必须预加’+‘或’-'。这些标志包括:

  • a:所有perf事件
  • e:仅在错误时输出(大小可配置 - 见linkperf:perf-config[1])
  • o:输出到stdout

如果支持,'q’选项可以重复以增加效果。

要完全禁用解码,使用--no-itrace

2.20 显示由参考事件收集的参考调用图。

--show-ref-call-graph 是一个选项,它在多个事件被采样时可能会有用。可能并不需要为所有这些事件收集调用图。通常,采样点位于附近,只需要在参考事件上收集调用图就足够了。因此,用户可以使用 “call-graph=no” 事件修饰符来禁用其他事件的调用图以减少开销。然而,perf report 无法为禁用调用图的事件显示调用图。这个选项扩展了 perf report,使其能够在没有调用图的事件中显示由参考事件收集的参考调用图。

2.21 显示使用拼接的LBRs调用图

--stitch-lbr 是一个选项,它可以显示使用拼接的LBRs(Last Branch Records,最后分支记录)的调用图,可能会得到更完整的调用图。perf.data文件必须使用 perf record --call-graph lbr 获取。默认情况下,此选项是禁用的。在调用堆栈溢出的常见情况下,它可以比默认的lbr调用堆栈输出重建更好的调用堆栈。但是,这种方法并非万无一失。可能存在由于错误的匹配创建错误调用堆栈的情况。已知的限制包括异常处理,如 setjmp/longjmp 将会有不匹配的调用/返回。

2.22 打印内联堆栈

--inline 是一个选项,如果一个调用图地址属于一个内联函数,那么将会打印内联堆栈。每个条目都是函数名或者文件/行。该选项默认启用,可以使用 --no-inline 来禁用它。

内联函数是编译器优化的一种形式,其中函数的代码直接插入到调用它的代码中,而不是通过常规的函数调用机制进行调用。这可以减少函数调用的开销,并可能允许进一步的优化。然而,对于性能分析,内联函数可能会使事情变得更复杂,因为内联函数的代码可能会分散在多个地方。因此,--inline 选项可以帮助分析师更准确地理解代码的性能特性。

2.23 显示mmap信息

--mmaps 是一个选项,它将显示 --tasks 输出加上类似于 /proc/<PID>/maps 格式的mmap信息。

请注意,并非所有的mmaps都被存储,影响存储哪些mmap的选项包括 perf record --data 等。这些选项可以影响perf工具记录的mmap事件的数量和类型。

/proc/<PID>/maps 文件为一个进程的内存映射提供了一种可读的表示。每一行都包含一个映射的详细信息,包括其地址范围,权限,偏移量,设备和文件名(如果适用)。

类似地,--mmaps 选项允许用户在perf报告中查看类似的信息,这有助于理解代码如何与系统的内存子系统交互,这对于性能分析可能是非常重要的。

2.24 显示被监视的任务

--tasks 是一个选项,它能显示存储在 perf 数据中的被监视的任务。它显示 pid/tid/ppid 以及命令字符串,并对齐它们以区分父任务和子任务。

  • pid: 进程标识符(Process ID),是操作系统分配给每个进程的唯一标识号。
  • tid: 线程标识符(Thread ID),是操作系统分配给每个线程的唯一标识号。在单线程进程中,pid和tid是相同的。
  • ppid: 父进程标识符(Parent Process ID),指的是创建当前进程的进程的ID。

这个选项在理解进程和线程如何在数据收集期间创建和销毁时非常有用,这对于分析多线程应用程序的性能特性可能是十分重要的。

2.25 设置注释的百分比类型

--percent-type 是一个选项,它允许你从以下选择中设置注释的百分比类型:global-periodlocal-periodglobal-hitslocal-hits

  • global-periodlocal-period:这些选项基于“周期”来计算百分比。在这里,“周期”是一个度量,它表示在特定时间间隔内事件发生的频率。global-period 是在整个数据范围内计算的百分比,而 local-period 是在函数范围内计算的百分比。

  • global-hitslocal-hits:这些选项基于样本的“命中”次数来计算百分比。global-hits 是在整个数据范围内计算的百分比,而 local-hits 是在函数范围内计算的百分比。

这个选项有助于更好地理解和解释性能数据,因为它改变了perf工具计算和显示百分比的方式。这对于确定代码的哪些部分对整体性能有最大影响可能是非常有用的。

2.26 配置时间排序键的时间单位

--time-quantum 是一个选项,它用于配置时间排序键的时间量子。默认值为100毫秒。它接受秒(s)、微秒(us)、毫秒(ms)和纳秒(ns)这几个单位。

在这个上下文中,“时间量子”(time quantum)是一个时间段,它是用于确定在排序或性能分析中应该考虑哪个时间段的度量。

例如,如果你设置 --time-quantum=200ms,那么perf工具会将性能数据分割成200毫秒的时间段,并分析每个时间段的性能特征。这个选项可以帮助你更细粒度地理解和分析性能数据,特别是在你需要理解性能随时间变化的情况时。

2.27 支持按 Sampled Cycles% 为所有块排序

--total-cycles 是一个选项,当指定了 --total-cycles 时,它支持按 Sampled Cycles% 为所有块排序。这对于关注全局最热的块很有用。在输出中,有一些新的列:

  • ‘Sampled Cycles%’:块采样周期的聚合 / 总采样周期
  • ‘Sampled Cycles’:块采样周期的聚合
  • ‘Avg Cycles%’:块平均采样周期 / 总块平均采样周期之和
  • ‘Avg Cycles’:块平均采样周期

这个选项可以帮助你更好地理解和分析性能数据,特别是当你需要理解代码的哪些部分对总体性能有最大影响时。在这种情况下,你可以使用 --total-cycles 选项来发现全局最热的块,也就是消耗周期最多的代码块。通过专注于这些热点,你可以更有效地优化代码以提高性能。

3. 开销计算

参考文档: perf-top(1) - Linux manual page (man7.org)

当perf收集调用链时,开销可以显示为Children和Self两列。self开销简单地通过添加条目的所有周期值来计算——通常是一个函数(符号)。这是perf传统上显示的值,所有自我开销值的总和应该是100%。

子开销(children overhead)是通过将子函数的所有周期值相加来计算的,这样就可以显示高一层次函数的总开销,即使它们没有直接执行很多。这里的子函数是指从另一个(父)函数调用的函数。

所有子开销值(children overhead)的总和超过100%可能会令人困惑,因为它们每一个都累积了其子函数的自我开销,这会导致重复累加。但启用了这个功能后,即使样本分布在子函数上,用户也可以找到开销最大的函数。考虑下面的例子,有如下三个函数:

void foo(void) { /* do something */ }

void bar(void) {
   /* do something */
   foo();
}

int main(void) {
   bar()
   return 0;
}

在这种情况下,foo是bar的子元素,bar是main的直接子元素,所以foo也是main的子元素。换句话说,main是foo和bar的父元素,bar是foo的父元素。假设所有的样本只记录在foo和bar中。当它用调用链记录时,输出将显示如下通常的(仅自开销)perf report输出:

Overhead  Symbol
........  .....................
  60.00%  foo
          |
          --- foo
              bar
              main
              __libc_start_main

  40.00%  bar
          |
          --- bar
              main
              __libc_start_main

当启用——children选项时,子函数(即foo和bar)的自开销值被添加到父函数以计算子函数开销。在这种情况下,报告可以显示为:

Children      Self  Symbol
........  ........  ....................
100.00%     0.00%  __libc_start_main
            |
            --- __libc_start_main

100.00%     0.00%  main
            |
            --- main
                __libc_start_main

100.00%    40.00%  bar
            |
            --- bar
                main
                __libc_start_main

60.00%    60.00%  foo
        |
        --- foo
            bar
            main
            __libc_start_main

在上面的输出中,foo的自身开销(60%)被添加到bar、main和_libc_start_main的子开销中。同样,bar的self开销(40%)被添加到main和libc_start_main的子开销中。因此,首先显示的是libc_start_main和main,因为它们具有相同的(100%)子开销(即使它们的self开销为零),并且它们是foo和bar的父对象。

自v3.16以来,默认情况下显示子开销,并按其值对输出进行排序。通过在命令行上指定--no-children选项或在perf配置文件中添加report.children = false or top.children = false来禁用子开销。

09-26 10:20