Project Icon

flamegraph

基于Rust的火焰图生成器 支持多语言性能分析

flamegraph是一个基于Rust的火焰图生成工具,适用于Cargo项目和其他语言应用的性能分析。它使用perf和dtrace进行采样,无需Perl或管道,简化了操作流程。通过可视化程序运行时间分布,flamegraph帮助开发者快速识别性能瓶颈。工具提供多种命令行选项,允许自定义采样频率和调色方案,并生成交互式SVG火焰图。作为系统性能优化的分析工具,flamegraph具有较强的实用性。

[cargo-]flamegraph

彩色火焰图输出

一个由Rust驱动的火焰图生成器,额外支持Cargo项目!它可以用于分析任何东西,不仅仅是Rust项目!无需perl或管道 <3

如何使用火焰图:什么是火焰图,以及如何使用它来指导系统性能工作?

[!提示] 你可能还想尝试samply,它提供了一个更交互式的UI,使用Firefox的Profiler网页UI无缝集成。它也是用Rust编写的,并且对macOS支持更好。

在Linux上依赖perf,其他系统依赖dtrace。基于@jonhoo出色的Inferno全Rust火焰图生成库构建! Windows正在获得dtrace支持,如果你尝试使用,请让我们知道效果如何。:D

注意:如果你在Linux上使用lld或mold,必须使用--no-rosegment标志。否则perf将无法生成准确的堆栈跟踪(解释)。例如,对于lld:

[target.x86_64-unknown-linux-gnu]
linker = "/usr/bin/clang"
rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"]

对于mold:

[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-Clink-arg=-fuse-ld=/usr/local/bin/mold", "-Clink-arg=-Wl,--no-rosegment"]

安装

cargo install flamegraph

这将使flamegraphcargo-flamegraph二进制文件在你的cargo二进制目录中可用。在大多数系统上,这通常类似于~/.cargo/bin

Linux上的要求:

Debian(x86和aarch)

注意:Debian bullseye(截至2022年的当前稳定版本)打包了一个过时的Rust版本,不满足flamegraph的要求。你应该使用rustup安装最新版本的Rust,或升级到Debian bookworm(当前测试版本)或更新版本。

sudo apt install -y linux-perf

Ubuntu(x86)

在aarch上不工作,使用Debian发行版,或提交PR解决Ubuntu上的问题

sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r`

Ubuntu/Ubuntu MATE(树莓派)

sudo apt install linux-tools-raspi

Pop!_OS

sudo apt install linux-tools-common linux-tools-generic

Shell自动完成

目前,只有flamegraph支持自动完成。支持的shell包括bashfishzshpowershellelvishcargo-flamegraph不支持自动完成,因为为自定义cargo子命令实现这一功能并不那么直接。详情请参见#153

启用自动完成的方式取决于你的shell,例如

flamegraph --completions bash > $XDG_CONFIG_HOME/bash_completion # 或 /etc/bash_completion.d/

示例

# 如果你想分析任意可执行文件:
flamegraph [-o my_flamegraph.svg] -- /path/to/my/binary --my-arg 5

# 或者如果可执行文件已经在运行,你可以通过`-p`(或`--pid`)标志提供PID:
flamegraph [-o my_flamegraph.svg] --pid 1337

# 注意:默认情况下,perf尝试为每个样本的每个堆栈帧计算哪些函数是内联的。
# 这可能需要很长时间(参见 https://github.com/flamegraph-rs/flamegraph/issues/74)。
# 如果你不想这样,可以向flamegraph传递--no-inline:
flamegraph --no-inline [-o my_flamegraph.svg] /path/to/my/binary --my-arg 5

# 通过cargo-flamegraph二进制文件提供cargo支持!
# 默认分析cargo run --release
cargo flamegraph

# 默认使用`--release`配置,
# 但你可以覆盖这一点:
cargo flamegraph --dev

# 如果你想分析特定的二进制文件:
cargo flamegraph --bin=stress2

# 如果你想像使用cargo run那样传递参数:
cargo flamegraph -- my-command --my-arg my-value -m -f

# 如果你想使用有趣的perf或dtrace选项,使用`-c`
# 这对于关联诸如分支未命中、缓存未命中等事项很有用,
# 或者通过`perf list`或dtrace可用于你系统的任何其他选项
cargo flamegraph -c "record -e branch-misses -c 100 --call-graph lbr -g"

# 运行criterion基准测试
# 注意,最后的--bench对于`criterion 0.3`在基准模式而不是测试模式下运行是必需的。
cargo flamegraph --bench some_benchmark --features some_features -- --bench

cargo flamegraph --example some_example --features some_features

# 分析单元测试。
# 注意,如果`--unit-test`是最后一个标志,则必须使用分隔符`--`。
cargo flamegraph --unit-test -- test::in::package::with::single::crate
cargo flamegraph --unit-test crate_name -- test::in::package::with::multiple:crate
cargo flamegraph --unit-test --dev test::may::omit::separator::if::unit::test::flag::not::last::flag

# 分析集成测试。
cargo flamegraph --test test_name

用法

flamegraph相当简单。cargo-flamegraph更复杂:

用法: cargo flamegraph [选项] [-- <尾随参数>...]

参数:
  [尾随参数]...  传递给被分析二进制文件的尾随参数

选项:
      --dev                            使用dev配置构建
      --profile <配置>                 使用指定配置构建
  -p, --package <包>                   包含要运行二进制文件的包
  -b, --bin <二进制文件>               要运行的二进制文件
      --example <示例>                 要运行的示例
      --test <测试>                    要运行的测试二进制文件(当前分析测试工具和二进制文件中的所有测试)
      --unit-test [<单元测试>]         要单元测试的crate目标,如果crate只有一个目标,可以省略<unit-test>(当前分析测试工具和二进制文件中的所有测试;测试选择可以作为尾随参数在`--`分隔符之后传递)
      --bench <基准测试>               要运行的基准测试
      --manifest-path <清单路径>       Cargo.toml的路径
  -f, --features <特性>                要启用的构建特性
      --no-default-features            禁用默认特性
  -r, --release                        无操作。为与`cargo run --release`兼容
  -v, --verbose                        打印额外输出以帮助调试问题
  -o, --output <输出>                  输出文件 [默认: flamegraph.svg]
      --open                           用默认程序打开输出的.svg文件
      --root                           使用root权限运行(使用`sudo`)
  -F, --freq <频率>                    采样频率(Hz)[默认: 997]
  -c, --cmd <自定义命令>               用于调用perf/dtrace的自定义命令
      --deterministic                  选择颜色,使函数的颜色在运行之间不变
  -i, --inverted                       生成上下颠倒的火焰图
      --reverse                        生成堆栈反转的火焰图
      --notes <字符串>                 在SVG中设置嵌入的注释
      --min-width <浮点数>             忽略小于<浮点数>像素的函数 [默认: 0.01]
      --image-width <图像宽度>         图像宽度(像素)
      --palette <调色板>               颜色调色板 [可能的值: hot, mem, io, red, green, blue, aqua, yellow, purple, orange, wakeup, java, perl, js, rust]
      --skip-after <函数>              在<函数>之下切断堆栈帧;可以重复
      --flamechart                     生成火焰图表(按时间排序,不合并堆栈)
      --ignore-status                  忽略perf的退出代码
      --no-inline                      因性能问题禁用perf脚本的内联
      --post-process <后处理>          运行命令处理折叠的堆栈,从stdin输入并输出到stdout
  -h, --help                           打印帮助
  -V, --version                        打印版本

然后用浏览器打开生成的flamegraph.svg,因为大多数图像查看器不支持交互式svg文件。

为非特权用户启用perf

要在不以root身份运行的情况下启用perf,你可以降低proc中的perf_event_paranoid值到适合你环境的水平。 最宽松的值是-1,但可能不适合你的安全需求等...

echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid

macOS上的DTrace

在macOS上,要启用DTrace,唯一的方法是以超级用户身份运行。这应该通过调用sudo flamegraph ...cargo flamegraph --root ...来完成。不要使用sudo cargo flamegraph ...; 这可能会因为Cargo的构建系统以root身份运行而导致问题。

请注意,如果被测试的二进制文件是用户感知的,这确实会改变其行为。

改善使用--release运行时的输出

由于优化等原因...有时在分析发布版本时,火焰图中呈现的信息质量会受到影响。

为了在某种程度上抵消这一点,你可以在Cargo.toml文件中设置以下内容:

[profile.release]
debug = true

或设置环境变量CARGO_PROFILE_RELEASE_DEBUG=true

请注意,测试、单元测试和基准测试在发布模式下使用bench配置(参见这里)。

与基准测试一起使用

为了对现有基准测试进行性能分析,你应该设置一些配置。 在你的Cargo.toml文件中设置以下内容以运行基准测试:

[profile.bench]
debug = true

使用perf和dtrace的自定义路径

如果设置了PERFDTRACE环境变量, 它将被用作相应工具的命令。 例如,要使用~/bin中的perf

env PERF=~/bin/perf flamegraph /path/to/my/binary

火焰图指导的系统性能工作

火焰图用于可视化你的程序中时间消耗的位置。 每秒多次中断程序的线程,并记录你代码中的当前位置 (基于线程的指令指针),以及到达那里所调用的函数链。 这称为堆栈采样。然后处理这些样本, 共享公共函数的堆栈被加在一起。然后生成一个SVG, 显示测量的调用堆栈,宽度与包含它们的 所有堆栈样本的比例成正比。

y轴显示堆栈深度编号。在查看火焰图时, 你程序的主函数会更靠近底部,被调用的函数 会堆叠在上面,它们调用的函数会堆叠在它们上面,以此类推...

x轴跨越所有样本。它显示从左到右的时间流逝。 从左到右的顺序没有意义。

每个框的宽度显示该函数在CPU上的总时间 或是调用堆栈的一部分。如果一个函数的框比其他函数宽, 这意味着它每次执行消耗的CPU比其他函数多, 或者它被调用的次数比其他函数多。

每个框的颜色没有特殊意义,是随机选择的。

火焰图适合可视化你程序中运行时最昂贵的部分, 这很棒,因为...

人类在猜测性能方面很糟糕!

特别是从C和C++转到Rust的人经常会过度优化 LLVM自己能够优化掉的代码。在开始 微优化、最小化分配等之前,总是更好 以清晰明显的方式编写Rust...

许多看起来会有糟糕性能的东西在Rust中实际上 是廉价或 火焰图显示了占用时间的事物,但它们是一种用于对被测系统进行高层次和初步观察的采样技术。它们非常适合找出需要更仔细研究的内容,通常根据火焰图就能明显看出如何改进某些东西,但它们更多是用于选择优化目标,而不是优化测量工具本身。它们粒度较粗,难以进行差异比较(尽管这项功能可能很快就会得到支持)。此外,由于火焰图是基于某事物占总时间的比例,如果你不小心使其他内容变得非常慢,它会在火焰图上显示所有其他内容变小,即使整个程序运行时间变慢了很多,你希望优化的项目看起来反而变小了。

使用火焰图来确定你想要优化的内容,然后设置一个测量环境,以便确定实际上是否有改进,这是个好主意。

  • 使用火焰图找出一组优化目标
  • 为这些优化目标创建基准测试,并在适当的情况下使用类似cachegrind和cg_diff这样的工具来测量CPU指令,并将它们与之前的版本进行比较。
  • 在许多情况下,测量CPU指令通常比测量运行工作负载所需的时间更好,因为你的机器上的后台任务可能会导致某些东西在物理时间上变慢,但如果你真的使实现变快了,它很可能与减少的总CPU指令数有更强的相关性。
  • CPU上花费的时间并不是全部情况,因为还有等待IO完成的时间,这在像perf这样只测量CPU上消耗时间的工具中是不会被计算的。查看Brendan Gregg关于Off-CPU Accounting的文章以获取更多相关信息!

性能理论101:定量工程基础

  • 在真实硬件上使用真实工作负载,否则你的数据不一定与生产环境中发生的情况有很大关系
  • 我们所有的猜测在某种程度上都是错误的,所以我们必须测量我们工作的效果。通常,看起来不应该快的简单代码实际上比看起来优化过的代码快得多。我们需要测量我们的优化,以确保我们没有使代码既难以阅读又变慢。
  • 在改变任何东西之前进行测量,并将结果保存在安全的地方!许多分析工具在再次运行时会覆盖旧的输出,所以确保在开始之前保存数据,以便你可以比较前后的结果。
  • 在已经预热且没有做其他事情的机器上进行测量,并给它时间从上一个工作负载中冷却下来。CPU在空闲时会进入睡眠状态和节能模式,如果温度过高,它们也会降频(有时SIMD会导致运行变慢,因为它会使温度升高到核心必须降频的程度)。

性能理论202:USE方法

USE方法是一种快速定位性能问题的方式,同时最大限度地减少发现工作。它更多是关于发现生产问题而不是直接与火焰图相关,但如果你要进行性能分类,这是一个很好的技术工具,火焰图可以帮助识别需要深入分析队列的组件。

计算机中的一切都可以被视为一个资源,前面有一个队列,可以同时处理一个或多个请求。我们计算机和程序中的各种系统在一段时间内可以完成一定量的工作,然后请求开始堆积并等待,直到它们能够被服务。

有些资源可以处理越来越多的工作而不会降低性能,直到它们达到最大利用率。网络设备在很大程度上可以被认为是以这种方式工作的。其他资源在达到最大利用率之前就开始饱和,比如磁盘。

磁盘(特别是旋转磁盘,但即使是SSD)如果允许更多的工作排队,它们会做更多的工作,直到达到工作负载的最大吞吐量,但每个请求的延迟会在达到100%利用率之前增加,因为磁盘开始服务每个请求的时间会变长。调优磁盘性能通常涉及测量各种IO队列深度,以确保它们足够高以获得良好的吞吐量,但又不至于高到使延迟变得不理想。

无论如何,我们系统中几乎所有东西都可以分解为基于3个高层次特征进行分析:

  • 利用率是被测系统实际做有用工作服务请求的时间量,可以测量为可用时间中用于服务请求的百分比
  • 饱和度是请求在被服务之前必须等待的情况。这可以通过一段时间内的队列深度来测量
  • 错误是当事情开始失败时,比如当队列不再能接受任何新请求时 - 就像当TCP连接被拒绝因为系统的TCP积压已经充满了尚未被用户空间程序accept的连接。

这形成了开始应用USE方法来定位复杂系统中与性能相关问题的必要背景!

方法是:

  1. 列举可能表现不佳的各种资源 - 也许通过创建火焰图并查找占总运行时间比预期更多的函数
  2. 选择其中一个
  3. (错误)检查错误,如TCP连接失败、其他IO失败、日志中的不良信息等...
  4. (利用率)测量系统的利用率,看看它的吞吐量是否接近已知的最大值,或者是已知开始出现饱和的点
  5. (饱和度)实际上是否发生了饱和?请求是否在被服务之前在排队等待?延迟是否在增加而吞吐量保持不变?

这些探测性问题作为一个锐利的手电筒,大多数时候能快速识别出潜在的问题。

如果你想了解更多关于这方面的信息,可以查看Brendan Gregg的博客文章。我倾向于建议,任何正在成为SRE的人都应该把Brendan的系统性能这本书作为他们阅读的第一批内容之一,以了解如何在生产系统中快速测量这些东西。

USE方法源于一个称为队列理论的研究领域,这个领域对计算机世界以及人类所从事的许多其他物流工作产生了巨大影响。

性能法则

如果你想更深入地研究理论,了解这些法则!

  • 通用可扩展性法则是关于并发收益、排队和协调成本之间关系的
  • 阿姆达尔定律是关于通过并行化可以为工作负载带来的理论最大收益的
  • 利特尔法则是一个看似简单但有一些微妙含义的队列理论法则,它允许我们推理系统适当的队列长度
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

稿定AI

稿定设计 是一个多功能的在线设计和创意平台,提供广泛的设计工具和资源,以满足不同用户的需求。从专业的图形设计师到普通用户,无论是进行图片处理、智能抠图、H5页面制作还是视频剪辑,稿定设计都能提供简单、高效的解决方案。该平台以其用户友好的界面和强大的功能集合,帮助用户轻松实现创意设计。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号