性能分析

在优化程序时,你也需要一种方法来确定程序的哪些部分是“热点”(被频繁执行以影响运行时)并且值得修改。这最好通过性能分析来完成。

性能分析工具

有许多不同的性能分析工具可用,每种都有其优点和缺点。以下是已成功用于 Rust 程序的性能分析工具的不完全列表。

  • perf 是一种使用硬件性能计数器的通用性能分析工具。HotspotFirefox Profiler 适用于查看 perf 记录的数据。它在 Linux 上运行。
  • Instruments 是一种通用性能分析工具,随 Xcode 一起提供在 macOS 上。
  • Intel VTune Profiler 是一种通用性能分析工具。它在 Windows、Linux 和 macOS 上运行。
  • AMD μProf 是一种通用性能分析工具。它在 Windows 和 Linux 上运行。
  • samply 是一种采样分析器,可生成可以在 Firefox Profiler 中查看的分析文件。它在 Mac 和 Linux 上运行。
  • flamegraph 是一个 Cargo 命令,使用 perf/DTrace 来分析您的代码,然后在火焰图中显示结果。它在 Linux 上运行,以及支持 DTrace 的所有平台(macOS、FreeBSD、NetBSD 和可能的 Windows)。
  • CachegrindCallgrind 提供全局、每个函数和每个源代码行的指令计数以及模拟缓存和分支预测数据。它们在 Linux 和其他一些 Unix 上运行。
  • DHAT 适用于查找代码中哪些部分导致了大量分配,并提供有关峰值内存使用情况的见解。它还可以用于识别对 memcpy 的热点调用。它在 Linux 和其他一些 Unix 上运行。dhat-rs 是一个实验性的替代方案,功能稍弱,需要对您的 Rust 程序进行轻微更改,但在所有平台上都运行。
  • heaptrackbytehound 是堆分析工具。它们在 Linux 上运行。
  • counts 支持即时分析,将 eprintln! 语句与基于频率的后处理结合使用,非常适合获取对代码部分的领域特定见解。它在所有平台上运行。
  • Coz 执行因果分析以测量优化潜力,并通过 coz-rs 支持 Rust。它在 Linux 上运行。

调试信息

为了有效地对发布版本进行性能分析,您可能需要启用源代码行调试信息。要做到这一点,请将以下行添加到您的 Cargo.toml 文件中:

[profile.release]
debug = 1

有关 debug 设置的更多详细信息,请参阅 Cargo 文档

不幸的是,即使执行了上述步骤,您也不会得到有关标准库代码的详细性能分析信息。这是因为 Rust 标准库的发布版本未使用调试信息构建。

绕过这个问题最可靠的方法是构建您自己版本的编译器和标准库,按照 这些说明 进行操作,并将以下行添加到 config.toml 文件中:

[rust]
debuginfo-level = 1

虽然这很麻烦,但在某些情况下可能值得一试。

另外,不稳定的 build-std 功能允许您将标准库作为程序的正常编译的一部分进行编译,并使用相同的构建配置。然而,标准库调试信息中的文件名不会指向源代码文件,因为此功能不会下载标准库源代码。因此,这种方法不会帮助像 Cachegrind 和 Samply 这样需要源代码才能完全运行的性能分析工具。

符号解析

Rust 使用一种名称编码形式来在编译代码中编码函数名称。如果性能分析工具不了解这一点,其输出可能包含以 _ZN_R 开头的符号名称,例如 _ZN3foo3barE_ZN28_$u7b$$u7b$closure$u7d$$u7d$E_RMCsno73SFvQKx_1cINtB0_3StrKRe616263_E

类似这样的名称可以使用 [rustfilt] 手动解析。

如果在性能分析时遇到符号解析的问题,将默认的旧版格式更改为新版 v0 格式可能值得一试。

要从命令行使用 v0 格式,可以使用 -C symbol-mangling-version=v0 标志。例如:

RUSTFLAGS="-C symbol-mangling-version=v0" cargo build --release

或者,要求在 config.toml 文件中(对于一个或多个项目)添加以下指令:

[build]
rustflags = ["-C", "symbol-mangling-version=v0"]