agentleFS
hellyguohellyguo/self-ai-spec/skills/rust-flamegraph/SKILL.md

rust-flamegraph

Skill8 starsChanged 17 days agoApache-2.0View on GitHub

使用 cargo flamegraph 生成火焰图并定位 Rust 程序 CPU 热点。触发场景:Rust 性能瓶颈定位、CPU 热点分析、函数耗时占比量化、优化前后对比、基准或测试性能不达预期。

  • Installs packages

The file

Files
SKILL.md

Rust Flamegraph 性能分析

前置条件

cargo install cargo-flamegraph
sudo sysctl kernel.perf_event_paranoid=0  # 允许非 root 采样

工作流

Step 1: 确定分析目标

明确要分析的操作和测试入口:

  • 哪个函数/模块需要分析?
  • 对应的测试在哪里?(lib unit test / 集成测试 / bench)
  • 预期的性能瓶颈在哪?(IO / CPU / 内存分配 / 锁争用)

Step 2: 准备测试入口

优先使用集成测试(tests/ 目录),cargo flamegraph --unit-test 对 lib 内测试支持不稳定。

# 集成测试(推荐)
cargo flamegraph --dev [OPTIONS] --test <test_file> -- <test_name> [test_args]

# bench
cargo flamegraph --dev [OPTIONS] --bench <bench_name> -- <bench_args>

关键原则:

  • 测试函数内用 std::time::Instant 计时并 eprintln! 输出,配合 --nocapture
  • 测试数据量要足够大(建议 10w+ 操作),否则采样点不足
  • 随机数据范围要足够大,避免重复(如 0..5000 而非 0..500)
  • 将耗时操作集中在单个测试函数中,避免 build 阶段混入火焰图

典型测试结构:

#[test]
fn perf_xxx() {
    // 1. 准备数据(不计入测量)
    let data = prepare_data();
    
    // 2. 计时执行(这是火焰图分析的目标)
    let start = Instant::now();
    for item in &data {
        target_function(item);
    }
    let elapsed = start.elapsed();
    
    // 3. 输出结果
    eprintln!("ops: {:.0}/s, per_op: {:.2?}", 
        count as f64 / elapsed.as_secs_f64(), elapsed / count as u32);
}

Step 3: 临时移除 #[inline] 并生成火焰图

关键:--no-inline 仅控制编译器内联策略,源码中 #[inline] 标注的函数仍会被内联导致火焰图无法捕获。需先注释掉所有 #[inline]。

# 1. 注释掉所有 #[inline](分析前)
fd -t f -e rs -X sed -i 's/#\[inline/\/\/ #\[inline/g' {}

# 2. 生成火焰图
cargo flamegraph \
  --dev \                          # debug 编译(保留函数名)
  --no-inline \                    # 不内联,保留函数调用栈
  --image-width 1500 \             # 宽图,看清函数名
  --freq 8000 \                    # 采样频率 8000Hz
  --palette rust \                 # Rust 友好配色
  --test <test_file> -- <test_name> --nocapture

参数说明:

参数说明建议值
--devdebug 编译,保留符号必选
--no-inline禁止编译器内联,展开调用栈推荐(需配合源码注释 #[inline])
--image-widthSVG 宽度(px)1500-2000
--freqperf 采样频率(Hz)8000-99999
--palette配色方案rust / io / hot
--test集成测试文件名对应 tests/ 下的文件
--benchbench 文件名benches/ 下的文件

输出: 项目根目录生成 flamegraph.svg

# 3. 恢复 #[inline](分析后)
fd -t f -e rs -X sed -i 's/\/\/ #\[inline/#\[inline/g' {}

注意:务必在分析后恢复 #[inline],否则生产构建性能会严重退化。

Step 4: 提取热点数据

从 SVG 中提取函数占比(自动化脚本):

# 提取热点函数及占比,按占比降序
rg '<title>' flamegraph.svg | \
  sed 's/.*<title>\(.*\)<\/title>.*/\1/' | \
  rg -v 'kernel|syscall|page_fault|_dl_|glibc|__GI_|_start|clone|thread_start|_int_free|_int_malloc|cfree|libc_start' | \
  sort -t'(' -k2 -rn | head -30

输出格式: function_name (N samples, X.XX%)

重点关注:

  • 项目自身函数(含 crate 名或模块路径)
  • 标准库中的热点(alloc::, core::, DashMap 等)
  • 内存分配相关(malloc, _int_malloc, sysmalloc)

Step 5: 分析热点

常见热点模式及优化方向:

热点模式典型占比优化方向
str::split + fold10-15%预计算/缓存编码结果
DashMap::insert10-20%减少写入/批量写入/Arc<str> 替代 String key
DashMap::get5-15%缓存查找结果/减少查表次数
alloc::fmt::format2-5%预分配 String/避免热路径 format!
String::hash3-10%Arc<str> 替代 String/换用更快的 hasher
malloc/_int_malloc5-15%对象池/预分配/减少 clone
malloc_consolidate1-3%减少内存碎片/用 jemalloc
Drop (析构)5-10%延迟析构/对象池复用
Arc::clone1-5%减少引用计数操作/传引用

Step 6: 量化对比

优化前后用相同参数生成火焰图,对比:

  1. 同一函数占比变化
  2. 总采样时间变化
  3. eprintln! 输出的 ops/s 变化

火焰图管理:

# 重命名保留(SVG 被 .gitignore 排除,不提交)
mv flamegraph.svg flamegraph_<scenario>_<timestamp>.svg

常见问题

perf_event_paranoid 报错

Error: Access to performance monitoring and observability operations is limited

解决: sudo sysctl kernel.perf_event_paranoid=0

no automatically selectable target

Error: crate has no automatically selectable target

解决: 用 --test <file> 或 --bench <file> 指定目标,而非 --unit-test

samples too few

火焰图信息稀疏 → 提高测试数据量或提高 --freq

火焰图中 inline 函数缺失

源码 #[inline] 标注的函数在火焰图中不可见 → 临时注释掉 #[inline] 后重新生成:

fd -t f -e rs -X sed -i 's/#\[inline/\/\/ #\[inline/g' {}
# 生成火焰图后恢复:
fd -t f -e rs -X sed -i 's/\/\/ #\[inline/#\[inline/g' {}

build_trie 阶段占比过高

测试中 build 阶段被采样 → 在测试函数中仅对目标操作计时,build 放在计时外

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.