调试分析Rust程序的简单方法

性能优秀是使用 Rust 的重要原因之一。Rust 并不是提高性能的魔法棒,它只是提供了控制能力,让你可以获得所需的性能。那么,如果你的程序仍然很慢,该如何解决呢?

调试分析你的程序是最好的选择之一,它能让你找出程序变慢的原因以及需要重点改进的地方。如果不进行调试分析,你就只能盲目猜测问题所在。有了调试分析,你就能知道大部分时间都花在哪里,从而集中精力解决问题。

有几种方法可以对 Rust 程序进行分析调试,但我最喜欢的是 flamegraph(也叫 cargo-flamegraph)。它是一款出色的工具,可与标准性能分析器 perf(Linux 上)和 dtrace(MacOS 上)结合使用。

基本用法

flamegraph 的基本用法非常简单,文档中也有详细介绍,但选项之多可能令人望而生畏。最基本的用法是,安装flamegraph 和依赖项后,将其作为cargo 命令运行。以下是我使用的几种调用方式。

# Run your default target with no arguments
cargo flamegraph

# Run your default target with the arguments after --
cargo flamegraph -- arg1 arg2 arg3

# Run the specified bin target with arguments
cargo flamegraph -b mybin -- arg1 arg2 arg3

# Run your default target with arguments and save
# the results to a different filename
cargo flamegraph -o myoutput.svg -- arg1 arg2 arg3

您可以混合使用这些选项。运行这些命令之一会生成一个文件,文件名为 flamegraph.svg,除非你重写了输出文件名。

生成文件后,您需要确保结果合理,以获得所需的结果。输出结果会告诉你记录了多少数据以及采样了多少次,类似于这样:

[ perf record: Woken up 59 times to write data ]
[ perf record: Captured and wrote 14.706 MB perf.data (925 samples) ]

在这个例子中,我们有 925 个样本,这对于在重大问题上取得进展来说可能是合理的。您需要多少样本取决于您的程序,但我发现低于 1,000 个样本效果并不好,而高于 1,000 个样本似乎会让速度变慢。如果你的程序存在大而全的低效问题,较少的样本仍能捕捉到它们。如果是相对微妙的小改进,则可能需要更多的样本。如何调整样本大小是一门艺术。

要控制采样的数量,有两个选择:一是改变程序,二是改变检测。采样是以特定频率进行的,因此你可以控制程序的持续时间,也可以控制采样频率。如果采样次数很少,但可以延长程序运行时间(加大输入、多次重复等),这样就可以增加采样次数。反之,采样过多也是同样的道理。另一种方法是改变检测本身:可以使用 -F 参数来改变采样频率。

# Sample at a rate of 1997 samples per second
cargo flamegraph -F 1997 -- arg1 arg2 arg3

有了好的样本,接下来的工作就交给你–程序员兼分析师了。我喜欢在 Firefox 中打开 SVG 文件,它有一个方便的查看器,可以放大并检查单个事件堆栈。不过你也可以使用任何合适的 SVG 查看器。您应该能够浏览flamegraph ,直观地了解 CPU 的使用时间,并以此来集中精力。有关如何阅读和使用火焰图的更详细介绍,请参阅flamegraph docs,其中有专门的一节。

几个问题

在对我的 Rust 程序进行各种分析调试时,我遇到了一些麻烦。以下是我记得的几个。当然还有更多,如果有需要补充的地方,请告诉我!

  • 缺少系统调用。当被测系统花大量时间进行系统调用时,如果不捕获这些调用,就会产生误导性的flamegraph图。由于系统调用会将控制权转移到内核,标准用户通常无法测量它们,而 perf 默认是以用户身份运行的!要解决这个问题,可以让perfroot身份采样。在 flamegraph 中,你可以添加 --root 标志,这样就能使用 sudo 获得权限,对包括系统调用在内的一切进行采样。这一点在进行大量磁盘或网络活动时尤为重要,否则调用这些系统调用的代码可能会丢失,而你也将陷入困境!
  • 优化隐藏信息。正如 flamegraph 文档中所述,”由于优化等原因……有时在剖析发行版构建时,flamegraph 中显示的信息质量会受到影响”。要解决这个问题,要么为发布目标设置 debug = true,要么使用环境变量 CARGO_PROFILE_RELEASE_DEBUG=true
  • 锁步采样。正如布伦丹-格雷格(Brendan Gregg)所指出的,采样频率与程序使用的典型频率不同。如果使用 100Hz 这样的频率,最终可能会与程序中重复事件的频率相同,导致重复从同一点采样,而不是从整个程序中采样。您可以尝试使用不同的频率,看看是否有任何频率的结果明显更好或更差;如果结果都差不多,那么您可能没有与程序保持一致。

现在开始吧分析您的程序!

P.S.

在 Fedora 上,我不得不用 sudo dnf install perf 来安装 perf,而且我还不得不降级 perf(sudo dnf downgrade perf),因为最新版本出现了回归,导致生成的结果中出现了混淆的名称。如果你的结果中没有你所期望的函数名称,请检查一下。

本文文字及图片出自 Profiling Rust programs the easy way

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号