Skip to content

性能剖析(Profiling)

编译带调试信息的 Release 版 oxlint

Profiling 时需使用带调试符号的 Release 二进制。向 cargo build 传入 --profile release-with-debug

bash
cargo build --profile release-with-debug --bin oxlint

产物位于 ./target/release-with-debug/oxlint,性能分析时请始终使用该二进制。

CPU — Samply

Samply 是命令行 CPU 采样器,UI 复用 Firefox Profiler;可在 macOS 与 Linux 使用。

示例:对 oxlint 的执行过程采样:

bash
samply record ./target/release-with-debug/oxlint .

可酌情调整选项以改善图谱可读性:

  • oxlint --silent:抑制诊断文本,图谱更聚焦于核心逻辑。
  • oxlint --threads 1:单线程运行更慢但便于剖析单线程热点。
  • samply record --rate <n>:提高采样频率(默认 1000Hz),细节更多但 .profile 文件更大。

例如在 0.1ms 粒度下单线程剖析:

bash
samply record --rate 10000 ./target/release-with-debug/oxlint --silent --threads 1 .

CPU — macOS Xcode Instruments

cargo instruments 常用于连接 Xcode Instruments。

首先安装 Xcode 命令行组件:

bash
xcode-select --install

并确保已通过上文方式编译生成带符号的 oxlint

cargo instruments 底层等价于调用:

bash
xcrun xctrace record --template 'Time Profile' --output . --launch -- /path/to/oxc/target/release-with-debug/oxlint

输出类似:

Starting recording with the Time Profile template...
...
Output file saved as: Launch_oxlint_2023-09-03_4.41.45 PM_EB179B85.trace

双击 trace 或用 open 打开 .trace。"Top-down"视图可如此操作:

  1. 顶部切换到 CPUs
  2. 左侧清空搜索框旁的 x 后再选 Time Profiler
  3. 底部勾选 Call Tree:Invert Call Tree 开启,Separate by Thread 关闭

若想观察内存/磁盘,--template 可改用 AllocationsFile Activity
更深入(L1/L2 Miss、cycles、instruction、分支预测)可自建 CPU Counters 模版(在 Instruments GUI 勾选 High Frequency Sampling 并追加事件);保存模版后即可通过 xcrun xctrace record --template 'My Custom CPU Counters' 使用。

堆内存 — dhat

dhat 是堆剖析器,可定位泄漏与分配热点。

配置

Cargo.toml 中加入 dhat 依赖,并在二进制入口注册全局 allocator:

toml
[dependencies]
dhat = "0.3"
rust
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;

采集

在被监控的作用域起始处创建 profiler;自创建起到析构期间的堆分配都会被记录:

rust
fn main() {
    let _profiler = dhat::Profiler::new_heap();
    // 此处及后续业务代码中的所有堆分配都会被统计
}

也可在具体函数的开头加入 _profiler,只追踪该函数内的分配:

rust
fn my_function() {
    let _profiler = dhat::Profiler::new_heap();
    // 仅限本函数作用域内的分配
}

profiler 销毁时会自动在当前工作目录生成 dhat-heap.json

载入与解读

程序运行完毕后,在当前工作目录会生成 dhat-heap.json

使用步骤:

  1. 打开 https://nnethercote.github.io/dh_view/dh_view.html
  2. 载入 dhat-heap.json
  3. 在 「Sort metrics」 中选择感兴趣的指标:
  • At t-gmax (bytes):峰值内存瞬时分配视图。
  • At t-end (bytes):Profile 结束前仍未释放的内存,利于发现泄漏。
  • Total (bytes):全程累计字节数,可看哪些路径分配最频繁即便随后已释放。

高级:手动控制 Profiler 生命周期

若需要先在核心逻辑结束前结束剖析、再执行收尾清理,可把 profiler 存放在结构体字段中手动释放:

rust
struct MyApp {
    profiler: Option<dhat::Profiler>,
    // 其余字段……
}

impl MyApp {
    fn close(&mut self) {
        // 在 cleanup 前先 drop profiler,以快照清理前的堆状态
        self.profiler = None;
        // cleanup code
    }
}

这样能观察程序在某一阶段仍持有哪些数据结构。