You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用perf分析Rust二进制程序时如何规避意外栈帧?

用perf分析Rust程序时如何消除意外栈帧?

我使用perf record对Rust二进制程序进行性能分析,在perf script的输出中发现了意外栈帧,导致火焰图难以解读。

分析命令:

$ perf record -F 997 --call-graph dwarf,65528 -g -e cpu-clock /path/to/bin
$ perf script

程序中fn main调用fn tip_mine,以下是符合预期的栈帧记录:

...
56275bcc4bee stacks_inspect::tip_mine+0xd23e (inlined)
56275bcc4bee stacks_inspect::main+0xd23e (/home/igor/stacks-blockchain/target/release/stacks-inspect)
ffffffffffffffff [unknown] ([unknown])

但同一次运行中,perf script还输出了包含额外栈帧的记录,这些栈帧出现在fn main和fn tip_mine之间:

...
56275bcbe20d stacks_inspect::tip_mine+0x685d (inlined)
56275bcbe20d stacks_inspect::main+0x685d (/home/igor/stacks-blockchain/target/release/stacks-inspect)
56275bc9bc42 core::ops::function::FnOnce::call_once+0x2 (inlined)
56275bc9bc42 std::sys_common::backtrace::__rust_begin_short_backtrace+0x2 (/home/igor/stacks-blockchain/target/release/stacks-inspect)
56275bca5e68 std::rt::lang_start::{{closure}}+0x8 (inlined)
56275c35dc8d core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once+0x42d (inlined)
56275c35dc8d std::panicking::try::do_call+0x42d (inlined)
56275c35dc8d std::panicking::try+0x42d (inlined)
56275c35dc8d std::panic::catch_unwind+0x42d (inlined)
56275c35dc8d std::rt::lang_start_internal::{{closure}}+0x42d (inlined)
56275c35dc8d std::panicking::try::do_call+0x42d (inlined)
56275c35dc8d std::panicking::try+0x42d (inlined)
56275c35dc8d std::panic::catch_unwind+0x42d (inlined)
56275c35dc8d std::rt::lang_start_internal+0x42d (/home/igor/stacks-blockchain/target/release/stacks-inspect)
56275bcc64e7 main+0x27 (/home/igor/stacks-blockchain/target/release/stacks-inspect)
7fa0aa8b4d8f [unknown] (/usr/lib/x86_64-linux-gnu/libc.so.6)
7fa0aa8b4e3f __libc_start_main+0x7f (/usr/lib/x86_64-linux-gnu/libc.so.6)
56275bc5a1d4 _start+0x24 (/home/igor/stacks-blockchain/target/release/stacks-inspect)

解决方法

1. 编译时关闭panic unwind机制

Rust默认用unwind处理panic,会生成大量标准库相关的栈帧。改用abort策略可以消除这些额外栈帧:
在项目的Cargo.toml中添加:

[profile.release]
panic = "abort"

修改后重新编译程序,再执行perf分析。

2. 后处理perf输出过滤栈帧

直接在perf script输出中过滤掉Rust标准库的辅助函数,只保留业务代码栈帧:

  • 仅保留自己项目的代码和main函数:
perf script | grep -E 'stacks_inspect::|main'
  • 过滤掉core::、std::开头的标准库栈帧:
perf script | awk '!/core::|std::/'

3. 改用帧指针采集调用图

默认情况下Rust编译会省略帧指针,开启后可以用fp模式采集更简洁的栈:
首先在Cargo.toml中开启帧指针:

[profile.release]
rustflags = ["-C", "force-frame-pointers=yes"]

重新编译后,用以下命令执行perf:

perf record -F 997 --call-graph fp -g -e cpu-clock /path/to/bin

4. 火焰图工具层面过滤

如果使用flamegraph.pl生成火焰图,可以通过--exclude参数直接过滤不需要的函数前缀:

perf script | flamegraph.pl --exclude 'core::|std::' > flame.svg

内容的提问来源于stack exchange,提问作者user19777296

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:24:21