Rust性能分析库criterion-perf-events的使用:基于perf事件的基准测试与性能监控工具

Rust性能分析库criterion-perf-events的使用:基于perf事件的基准测试与性能监控工具

Criterion-perf-events

这是一个用于Criterion.rs的测量插件,用于测量Linux perf接口的事件。

支持的事件

Criterion-perf-events使用perfcnt crate并支持该crate提供的事件。如果您想了解更详细的信息,请查看以下列出的事件:

  • 硬件事件
  • 软件事件
  • Perf事件
  • 原始Intel事件

故障排除

如果您遇到"Permission denied"错误,请更新perf_event_paranoid

sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'

示例

以下代码展示了如何计算退休指令(retired instructions)。

use criterion::{criterion_group, criterion_main, BenchmarkId, black_box, Criterion};
use criterion_perf_events::Perf;
use perfcnt::linux::HardwareEventType as Hardware;
use perfcnt::linux::PerfCounterBuilderLinux as Builder;

fn fibonacci_slow(n: usize) -> usize {
    match n {
        0 => 1,
        1 => 1,
        n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2),
    }
}

fn bench(c: &mut Criterion<Perf>) {
    let mut group = c.benchmark_group("fibonacci");

    let fibo_arg = 30;
    group.bench_function(BenchmarkId::new("slow", fibo_arg), |b| {
        b.iter(|| fibonacci_slow(black_box(fibo_arg)))
    });

    group.finish()
}

criterion_group!(
    name = instructions_bench;
    config = Criterion::default().with_measurement(Perf::new(Builder::from_hardware_event(Hardware::Instructions)));
    targets = bench
);
criterion_main!(instructions_bench);

运行命令:

cargo criterion

打开target/criterion/reports/index.html查看带有图表的详细结果。对于所有事件类型(Hardware::InstructionsHardware::CacheMisses等),criterion总是报告周期作为单位。请注意,显示的是您的事件类型,而不是CPU周期。

完整示例

// 添加以下依赖到Cargo.toml:
// [dev-dependencies]
// criterion = "0.3"
// criterion-perf-events = "0.4"
// perfcnt = "0.5"

use criterion::{criterion_group, criterion_main, BenchmarkId, black_box, Criterion};
use criterion_perf_events::Perf;
use perfcnt::linux::HardwareEventType as Hardware;
use perfcnt::linux::PerfCounterBuilderLinux as Builder;

// 定义一个简单的递归斐波那契函数用于测试
fn fibonacci_slow(n: usize) -> usize {
    match n {
        0 => 1,
        1 => 1,
        n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2),
    }
}

// 基准测试函数
fn bench(c: &mut Criterion<Perf>) {
    let mut group = c.benchmark_group("fibonacci");
    
    // 测试参数
    let fibo_arg = 30;
    
    // 添加基准测试案例
    group.bench_function(BenchmarkId::new("slow", fibo_arg), |b| {
        b.iter(|| fibonacci_slow(black_box(fibo_arg)))
    });
    
    group.finish()
}

// 配置基准测试组
criterion_group!(
    name = instructions_bench;
    config = Criterion::default().with_measurement(
        Perf::new(Builder::from_hardware_event(Hardware::Instructions))
    );
    targets = bench
);

// 主函数入口
criterion_main!(instructions_bench);

这个示例展示了如何使用criterion-perf-events来测量斐波那契计算中的指令数。关键点包括:

  1. 使用Perf作为测量插件
  2. 配置Hardware::Instructions作为要测量的硬件事件
  3. 通过cargo criterion运行基准测试
  4. 结果会显示在HTML报告中

您可以根据需要更改硬件事件类型,例如使用Hardware::CacheMisses来测量缓存未命中次数。


1 回复

Rust性能分析库criterion-perf-events的使用指南

完整示例demo

下面是一个结合了基础使用、多事件测量和自定义配置的完整示例:

// 导入必要的库
use criterion::{criterion_group, criterion_main, Criterion};
use criterion_perf_events::Perf;
use perfcnt::linux::{HardwareEventType as Hardware, SoftwareEventType as Software};
use perfcnt::linux::PerfCounterBuilderLinux as Builder;

// 定义一个简单的计算函数用于测试
fn compute_heavy(n: u64) -> u64 {
    (0..n).fold(0, |acc, x| acc + x * x)
}

// 基准测试函数
fn benchmark(c: &mut Criterion<Perf>) {
    // 测试1: 测量CPU周期和指令数
    let mut group1 = c.benchmark_group("basic_metrics");
    group1.with_perf_event(Builder::from_hardware_event(Hardware::CPUCycles));
    group1.with_perf_event(Builder::from_hardware_event(Hardware::Instructions));
    
    group1.bench_function("compute 1000", |b| b.iter(|| compute_heavy(1000)));
    group1.finish();

    // 测试2: 测量缓存相关指标
    let mut group2 = c.benchmark_group("cache_metrics");
    group2.with_perf_event(
        Builder::from_hardware_event(Hardware::CacheReferences)
            .exclude_kernel()
            .exclude_hv()
    );
    group2.with_perf_event(Builder::from_hardware_event(Hardware::CacheMisses));
    
    group2.bench_function("compute 5000", |b| b.iter(|| compute_heavy(5000)));
    group2.finish();

    // 测试3: 组合硬件和软件事件
    let mut group3 = c.benchmark_group("combined_metrics");
    group3.with_perf_event(Builder::from_hardware_event(Hardware::BranchMisses));
    group3.with_perf_event(Builder::from_software_event(Software::PageFaults));
    
    group3.bench_function("compute 10000", |b| b.iter(|| compute_heavy(10000)));
    group3.finish();
}

// 配置基准测试组
criterion_group! {
    name = benches;
    config = Criterion::default().with_measurement(Perf);
    targets = benchmark
}

// 主函数
criterion_main!(benches);

示例说明

  1. 这个示例展示了三种不同的测试场景:

    • 基本CPU指标测量(周期和指令数)
    • 缓存相关指标测量
    • 混合硬件和软件事件测量
  2. 每个测试组都配置了不同的事件组合,并测试同一个计算函数在不同输入大小下的性能

  3. 使用了自定义配置来排除内核和hypervisor事件,以获得更精确的用户空间测量结果

预期输出示例

运行上述基准测试后,输出会类似如下格式:

basic_metrics/compute 1000
                        time:   [123.45 us 124.56 us 125.67 us]
                        CPUCycles:      [456789 467890 478901]
                        Instructions:   [1234567 1245678 1256789]

cache_metrics/compute 5000
                        time:   [678.90 us 689.01 us 699.12 us]
                        CacheReferences: [12345 12456 12567]
                        CacheMisses:     [123 124 125]

combined_metrics/compute 10000
                        time:   [1.234 ms 1.245 ms 1.256 ms]
                        BranchMisses:   [456 467 478]
                        PageFaults:     [12 13 14]
回到顶部