#perf #graph #matcher #data #tool #post-processing

app perf-focus

分析perf数据的后处理工具

4个版本 (2个稳定版本)

使用旧的Rust 2015

1.1.0 2018年6月5日
1.0.0 2018年2月16日
0.2.0 2018年2月16日
0.1.0 2018年2月16日

#184 in 性能分析

Apache-2.0/MIT

61KB
1.5K SLoC

perf focus 是一个正在开发中的工具,你可以使用它与 Linux perf 一起使用,以回答有关运行时的问题。请注意,这个工具正在积极开发中,目前不应期望稳定的用法。此外,此文档是不完整的,运行 perf-focus --help 以获取完整的选项列表(或者,当然,你可以阅读源代码)。

安装和收集数据

第一步是安装此工具

> cargo install perf-focus

接下来,您需要通过运行 perf 收集一些数据。使用以下设置以获取良好的回溯

> perf record -F 99 -g <some-command-here>

注意:如果您正在分析Rust程序,请启用调试信息,以确保我们可以获取回溯。

关键思想:匹配器

当您使用此工具时,您必须指定一个匹配器。匹配器允许您筛选样本以找到特定函数中的样本;这使得您能够轻松分析从许多地方调用的代码的横切部分。以下是一个简单的示例

> perf focus '{^middle::traits}..{^je_}'

此调用将分析由 perf record 生成的 perf.data 文件,并报告当名为 middle::traits 的函数在堆栈上时调用的函数的名称以 je_ 开头,以及样本被获取的百分比。在查询语法中,{<regex>} 匹配由嵌入的正则表达式指定的单个函数。操作符 , 首先匹配 ..M 前缀跳过任何数量的帧,然后匹配 M。它也可以用作二元运算符,因此 M..N 等价于 M,..N

> perf focus '{^a$},{^b$}'

报告函数 a 直接调用函数 b 的频率。

> perf focus '{^a$},!..{^b$}'

报告名为 a 的函数在栈上出现的频率,但没有(间接地)调用名为 b 的函数。

rustc 查询分析

如果你传递了 --rustc-query,该工具将应用过滤器,仅保留 rustc 查询。这对于确定 rustc 编译时间很有用。我建议与 --tree-callees 一起使用。

示例

> perf focus '{main}' --rustc-query --tree-callees | head
Matcher    : {main}
Matches    : 2690
Not Matches: 0
Percentage : 100%

Tree
| matched `{main}` (100% total, 25% self)
: | mir_borrowck<'tcx>> (35% total, 35% self)
: : | normalize_projection_ty<'tcx>> (0% total, 0% self)
: | typeck_item_bodies<'tcx>> (11% total, 0% self)

你可以通过传递以下选项之一来生成调用者和被调用者树。

--tree-callee
--tree-caller

这将输出显示每个被调用的函数,以及在该子树中花费的时间百分比("total")以及在该实际函数中花费的时间百分比("self")。(像往常一样,这些都是总程序执行时间的百分比。)你可以使用 --tree-max-depth--tree-min-percent 来自定义这些内容,这对于删除不感兴趣的内容很有用。

示例输出

> perf focus '{add_drop_live_constraint}' --tree-callees --tree-max-depth 3 --tree-min-percent 3
Matcher    : {add_drop_live_constraint}
Matches    : 708
Not Matches: 1982
Percentage : 26%

Tree
| matched `{add_drop_live_constraint}` (26% total, 0% self)
: | rustc_mir::borrow_check::nll::type_check::TypeChecker::fully_perform_op (25% total, 0% self)
: : | rustc::infer::InferCtxt::commit_if_ok (23% total, 0% self)
: : : | <std::collections::hash::set::HashSet<T, S>>::insert (8% total, 0% self) [...]
...

你也可以通过传递以下选项之一来生成调用图

--graph
--graph-callers
--graph-callees

第一个选项将生成包括每个匹配样本中所有帧的调用图。--graph-callers 选项生成一个调用图,只包括调用匹配代码的帧。--graph-callees 仅包括被匹配代码调用的帧。

在图中,每个节点和边都标注了一个百分比,表示在运行的所有样本中出现该节点或边的百分比。这个百分比始终是所有样本的绝对百分比(它不是匹配样本的百分比,特别是)。

默认情况下,图包括前 22 个最显著的功能(以及它们之间的边)。你可以通过传递 --threshold N(包括前 N 个功能)来包含更多或更少的功能。

你可以使用 --rename <regex> <match> 来修改图中出现的函数名称。这可以用来删除 fn 名称的部分,或者合并函数。

// convert things like `middle::traits::select::foo::bar` to
// `middle::traits::select`:
--rename '(^middle::traits::[a-zA-Z0-9_]+)::.*' '$1'

// strip the last `...::XXX` suffix:
--rename '::[a-zA-Z0-9_]+$' ''

直方图

除了图之外,你还可以使用直方图选项仅输出最常见的函数以及它们在样本中出现的百分比(如上所述,所有百分比都是绝对值)

--hist
--hist-callers
--hist-callees

依赖项

~5.5MB
~101K SLoC