rust-bench:基于 Rust 生态的性能基准测试与分析框架

Rust软件性能评测项目

分支7Tags1
当前项目代码仓暂无内容

Rust Bench — Rust 性能基准测试与分析框架

English

一个用于 Rust 程序运行时性能基准测试、数据采集、终端展示和性能分析的完整工具链。基于 rustc-perf 构建,扩展了增强的运行时基准测试能力、自定义指标支持和 TUI 比较界面。

核心特性

  • 运行时基准测试(Runtime Benchmark) — 完整的 Rust 标准库基准测试套件和自定义基准测试,基于硬件性能计数器(perf_event
  • 终端数据展示 — 基准测试过程中实时输出 min/mean/stddev 统计数据,以及交互式 TUI(bench_cmp)用于比较两个版本之间的结果
  • 性能分析(Profile) — 支持 Cachegrind(指令级)和 perf-record(采样式)的运行时性能分析

目录

  1. 项目概览
  2. 快速开始
  3. 功能介绍
  4. Benchmark 编写指南
  5. 项目结构
  6. 许可证

快速开始

前置条件

  • Rust stable 工具链
  • Linux 系统(需要 perf_event 硬件计数器支持)
  • 设置 perf event 权限:
    sudo bash -c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'
    

构建

cargo build --release

运行运行时基准测试

# 运行所有运行时基准测试
./target/release/collector bench_runtime_local <RUSTC>

# 只运行指定的 benchmark 组
./target/release/collector bench_runtime_local <RUSTC> --group std

# 按名称前缀过滤 benchmark
./target/release/collector bench_runtime_local <RUSTC> --include find_existing
./target/release/collector bench_runtime_local <RUSTC> --exclude hashmap

# 复用已编译的产物,加速重复运行
./target/release/collector bench_runtime_local <RUSTC> --no-isolate

# 指定数据库和迭代次数
./target/release/collector bench_runtime_local <RUSTC> --db my_results.db --iterations 10

其中 <RUSTC> 是 rustc 可执行文件的路径(例如 path/to/stage1/bin/rustc),或者以 + 开头的工具链名(例如 +nightly)。

常用选项(bench_runtime_local

选项 说明
--id <ID> 基准测试结果的标识符
--db <DATABASE> 数据库文件路径(默认:results.db
--iterations <N> 每个 benchmark 的迭代次数(默认:5)
--include <PREFIX> 只包含匹配此前缀的 benchmark
--exclude <PREFIX> 排除匹配此前缀的 benchmark
--group <GROUP> 只编译和运行指定的 benchmark 组
--no-isolate 复用之前编译的 benchmark 产物
--purge 在测试前清除该 artifact 的旧数据

比较结果

# 交互式 TUI 比较(交互选择 artifact)
./target/release/collector bench_cmp --db results.db

运行性能分析

# Cachegrind 分析(分析组内所有 benchmark)
./target/release/collector profile_runtime <RUSTC> cachegrind

# 分析指定的组
./target/release/collector profile_runtime <RUSTC> cachegrind --group std

# perf-record 分析
./target/release/collector profile_runtime <RUSTC> perf-record

# 比较两个 rustc 版本(cachegrind diff)
./target/release/collector profile_runtime <RUSTC> cachegrind --rustc2 <RUSTC2>

# 精确 Cachegrind 模式(需要 Valgrind ≥ 3.22)
DEP_VALGRIND=<valgrind-install>/include cargo run --release --bin collector \
  --features precise-cachegrind profile_runtime <RUSTC> cachegrind

功能介绍

3.1 运行时基准测试

运行时基准测试套件测量用特定版本的 rustc 编译后的 Rust 程序执行速度。基准测试以 组(group) 为单位组织——每个组是 collector/runtime-benchmarks/ 下的一个独立 crate。

标准库基准测试组

组名 测试内容
std HashMap、HashSet、IO(BufRead/Copy/Cursor/Impls)、Path、Time
core 核心库基准测试
alloc 内存分配器基准测试

自定义基准测试组

组名 测试内容
fmt 格式化基准测试
hashmap 哈希表性能
compression 压缩算法
css CSS 解析
nbody N 体模拟
nes NES 模拟器
parsing 文本解析
raytracer 光线追踪
svg SVG 处理
text-search 文本搜索
bufreader 缓冲读取
daft-vllm 自定义基准测试示例(包含自定义指标、JSON 报告、额外命令行参数)

采集指标

基准测试框架使用 Linux perf_event_open 系统调用采集硬件性能计数器:

指标 说明
instructions:u CPU 指令数
cycles:u CPU 周期数
wall-time 墙钟时间
branch-misses 分支预测失败
cache-misses 缓存未命中
cache-references 缓存引用
max-rss 最大常驻内存
自定义指标 任意用户定义的指标

每个 benchmark 分两轮执行:一轮采集硬件性能计数器,一轮采集墙钟时间,确保结果准确且互不干扰。

3.2 终端数据展示

实时 Benchmark 输出

每个 benchmark 完成后,统计信息会打印到终端:

Finished std/find_existing (1/42)
    [Instructions]: min:       1,234,567    mean:        1,234,890    stddev:          234
         [Cycles]: min:         456,789    mean:          457,012    stddev:          156
  [Wall time [ns]]: min:         234,000    mean:          235,000    stddev:        2,000
  [Branch misses]: min:           1,234    mean:            1,245    stddev:           12
   [Cache misses]: min:              56    mean:               58    stddev:            3
    [Memory [kb]]: min:           2,048    mean:            2,048    stddev:            0
  • 自定义数值指标(如 throughput_tok/slatency_p99_ms)也会自动显示
  • JSON 报告以 <JSON data> (view in bench_cmp) 标记显示
  • 进度追踪:Finished <group>/<benchmark> (<current>/<total>)

bench_cmp — 交互式 TUI 比较界面

bench_cmp 命令提供基于终端的交互式 UI(基于 ratatui),用于比较两个 artifact 版本之间的基准测试结果:

./target/release/collector bench_cmp --db results.db

功能特性:

  • 模式切换 — 按 M 在编译(Compile)和运行时(Runtime)比较模式间切换
  • 摘要面板 — 顶部显示回归/改进摘要统计
  • 详细表格 — Benchmark 名称、前值(Before)、后值(After)、变化幅度(含 95% 置信区间)
  • 指标切换 — 按 A/S 在可用指标间循环(instructions、cycles、wall-time 等)
  • 显著性过滤 — 按 F 切换显示所有结果或仅显示显著变化
  • 目标平台切换 — 按 1/2 切换基准/修改版本的目标平台
  • JSON 详情视图 — 在 JSON 行(如 perf-record 数据)上按 Enter 打开可滚动的详情视图
  • 导航/ 导航,q/Esc 退出

3.3 性能分析(Profile)

profile_runtime 子命令使用以下两种 profiler 之一对运行时基准测试进行性能分析:

Cachegrind

  • 用途:指令级分析,结果近乎确定性
  • 输出:原始数据(cgout 前缀)+ 人类可读的注解输出(cgann 前缀)
  • Diff 支持:使用 --rustc2 时,生成两个版本的差异对比文件
  • 精确模式:使用 --features precise-cachegrind 时,仅对实际 benchmark 代码进行计数(需要 Valgrind ≥ 3.22)

perf-record

  • 用途:采样式分析,适合发现热点函数
  • 输出:原始数据(perf 前缀)+ 注解报告(perfreport 前缀)
  • 开销:可忽略不计

Profile 选项

选项 说明
<PROFILER> cachegrindperf-record
<RUSTC> rustc 可执行文件路径或 +toolchain
--group <GROUP> 仅分析指定的 benchmark 组
--iterations <N> 分析迭代次数(默认:5)
--include <PREFIX> 按前缀包含 benchmark
--exclude <PREFIX> 按前缀排除 benchmark
--rustc2 <RUSTC> 第二个 rustc,用于对比分析(cachegrind 支持 diff)

Benchmark 编写指南

4.1 使用 #[bench]

推荐的 Rust 函数性能测试方式。#[bench] 宏会自动将您的函数注册到全局 benchmark 组。

第一步:创建或选择 benchmark 组

每个 benchmark 组是 collector/runtime-benchmarks/ 下的一个二进制 crate。按照约定,如果组目录名为 foo,则 crate 名应为 foo-bench

第二步:添加 benchlib 依赖

[dependencies]
benchlib = { path = "../../benchlib" }

第三步:使用 #[bench] 编写 benchmark

use std::collections::HashMap;
use benchlib::benchmark::{bench, Bencher};

#[bench]
fn find_existing(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 1..1001 {
        m.insert(i, i);
    }
    b.iter(
        || {},          // constructor:准备每次迭代的数据(不被测量)
        |_| {           // bench:实际被测量的代码
            for i in 1..1001 {
                m.contains_key(&i);
            }
        },
    );
}

#[bench]
fn grow_by_insertion(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 1..1001 {
        m.insert(i, i);
    }
    let mut k = 1001;
    b.iter(
        || {},
        |_| {
            m.insert(k, k);
            k += 1;
        },
    );
}

第四步:设置 main.rs

fn main() {
    benchlib::benchmark::run_global_benchmark_group();
}

Bencher::iter(constructor, bench) 工作原理

  • constructor:每次测量前调用,用于准备输入数据。其返回值会传递给 bench。此代码 不被 测量。
  • bench:接收 constructor 的输出。此代码 会被 硬件性能计数器和墙钟时间所测量。
  • 系统自动执行 3 次热身迭代,随后进行 N 次正式测量(可通过 --iterations 配置)。

4.2 自定义 Benchmark(daft-vllm 示例)

当需要完全控制测量逻辑、自定义指标、JSON 报告或自定义命令行参数时,使用 benchlib::custom API。

核心 API

API 用途
benchlib::custom::init(&[names]) 初始化 CLI,解析参数,返回 BenchAction
benchlib::custom::parse_extra_args(&extra) 解析 -- 后传入的自定义参数
BenchmarkSample::new(duration) 创建包含墙钟时间的样本
sample.set("metric", value) 设置自定义数值指标
BenchmarkResult::with_samples(name, samples) 从样本创建结果
result.add_report("name", &data) 添加 JSON 报告(任意 Serialize 类型)
result.add_report(METRIC_PERF_RECORD, &entries) 添加 perf-record 分析数据
output_message(&mut stdout, msg) 以 JSON 格式将结果输出到 stdout

完整示例(来自 daft-vllm/src/main.rs

use benchlib::clap;
use benchlib::comm::messages::{
    BenchmarkMessage, BenchmarkResult, BenchmarkSample,
    PerfRecordEntry, METRIC_PERF_RECORD,
};
use benchlib::comm::output_message;
use benchlib::custom::{init, parse_extra_args, BenchAction};
use std::time::Duration;

/// 自定义参数,从命令行 `-- ...` 后解析。
#[derive(clap::Parser, Debug)]
struct VllmArgs {
    #[arg(long, default_value = "default-model")]
    model: String,

    #[arg(long, default_value_t = 16)]
    batch_size: u32,
}

fn main() -> benchlib::anyhow::Result<()> {
    let action = init(&["daft-vllm-example"])?;

    match action {
        BenchAction::Run { iterations, benchmarks, extra } => {
            let vllm_args: VllmArgs = parse_extra_args(&extra)?;
            let mut stdout = std::io::stdout().lock();

            for name in &benchmarks {
                let mut samples = Vec::with_capacity(iterations as usize);

                for _ in 0..iterations {
                    // 在这里编写你的 benchmark 逻辑
                    let mut sample = BenchmarkSample::new(Duration::from_millis(0));

                    // 添加自定义数值指标
                    sample.set("throughput_tok/s", 1234.5);
                    sample.set("latency_p99_ms", 42.0);
                    samples.push(sample);
                }

                let mut result = BenchmarkResult::with_samples(name.clone(), samples);

                // 添加结构化 JSON 报告
                #[derive(serde::Serialize)]
                struct LatencyDist { p50: f64, p90: f64, p99: f64 }
                result.add_report("latency_distribution", &LatencyDist {
                    p50: 12.5, p90: 35.2, p99: 42.0,
                });

                // 添加 perf-record 分析数据
                let perf_entries = vec![
                    PerfRecordEntry {
                        function: "engine::execute_plan".to_string(),
                        delay: 15.3,
                        time_rate: 0.35,
                        sample_count: 350,
                        is_rust: true,
                        category: "compute".to_string(),
                        shared_object: "libdaft.so".to_string(),
                    },
                ];
                result.add_report(METRIC_PERF_RECORD, &perf_entries);

                output_message(&mut stdout, BenchmarkMessage::Result(result))?;
            }
        }
        BenchAction::Profile(profile_args) => {
            let vllm_args: VllmArgs = parse_extra_args(&profile_args.extra)?;
            for _ in 0..profile_args.iterations {
                // 在这里编写你的 profiling 逻辑
            }
        }
    }
    Ok(())
}

运行自定义 Benchmark

# 使用默认参数运行
./target/release/collector bench_runtime_local <RUSTC> --group daft-vllm

# 通过 -- 传递自定义参数
./target/release/collector bench_runtime_local <RUSTC> --group daft-vllm \
  -- --model gpt2 --batch-size 32

项目结构

rust-bench/
├── collector/                        # 数据收集器
│   ├── benchlib/                     # 核心基准测试库
│   │   ├── src/benchmark.rs          # #[bench] 宏 + BenchmarkGroup + Bencher
│   │   ├── src/custom.rs             # 自定义 benchmark 框架(init/BenchAction)
│   │   ├── src/comm/messages.rs      # 消息协议 + 指标定义
│   │   └── src/measure/              # 性能计数器测量(perf_event)
│   ├── benchlib-macros/              # #[bench] 过程宏实现
│   ├── runtime-benchmarks/           # 运行时基准测试套件
│   │   ├── std/                      # 标准库测试(HashMap、IO、Path、Time)
│   │   ├── core/                     # 核心库测试
│   │   ├── alloc/                    # 分配器测试
│   │   ├── fmt/                      # 格式化测试
│   │   ├── hashmap/                  # 哈希表测试
│   │   ├── daft-vllm/                # 自定义 benchmark 示例
│   │   └── ...                       # 更多 benchmark 组
│   ├── compile-benchmarks/           # 编译时基准测试套件
│   └── src/
│       ├── bin/collector.rs          # CLI 入口
│       ├── runtime/mod.rs            # 运行时 benchmark 执行引擎
│       ├── runtime/profile.rs        # 运行时 profiling(cachegrind、perf-record)
│       └── compare/screen.rs         # TUI 比较界面(bench_cmp)
├── database/                         # 数据库层(SQLite/Postgres)
├── site/                             # Web 前端(可选)
├── Cargo.toml                        # Workspace 配置
└── README.md

许可证

原始 rustc-perf 代码基于 MIT 许可证,由 Reuse Specification 管理。 编译时基准测试有各自独立的许可证,详见 collector/compile-benchmarks/REUSE.toml 文件。

旋武团队(Xuanwu Team) 所做的修改和扩展同样采用 MIT 许可证

Copyright (c) Xuanwu Team. All rights reserved.