Rust性能基准测试库criterion2的使用,criterion2提供精确的微基准测试和统计分析功能
Rust性能基准测试库criterion2的使用
特性
- 统计分析:能够检测性能变化,并量化变化的程度
- 图表生成:使用gnuplot生成详细的基准测试结果图表
- 稳定版兼容:无需安装nightly Rust即可进行基准测试
快速开始
首先需要安装gnuplot以生成图表。
在项目的Cargo.toml
中添加以下内容:
[dev-dependencies]
criterion = { version = "0.4", features = ["html_reports"] }
[[bench]]
name = "my_benchmark"
harness = false
然后,在benches/my_benchmark.rs
中创建基准测试文件:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
// 定义一个斐波那契函数用于测试
fn fibonacci(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci(n-1) + fibonacci(n-2),
}
}
// 基准测试函数
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
// 定义基准测试组
criterion_group!(benches, criterion_benchmark);
// 定义基准测试主函数
criterion_main!(benches);
运行cargo bench
命令后,你将看到类似以下的输出:
Running target/release/deps/example-423eedc43b2b3a93
fib 20 time: [26.029 us 26.251 us 26.505 us]
Found 11 outliers among 99 measurements (11.11%)
6 (6.06%) high mild
5 (5.05%) high severe
完整示例
下面是一个更完整的基准测试示例,展示了如何比较不同实现的性能:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
// 递归实现的斐波那契
fn fibonacci_recursive(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci_recursive(n-1) + fibonacci_recursive(n-2),
}
}
// 迭代实现的斐波那契
fn fibonacci_iterative(n: u64) -> u64 {
if n == 0 || n == 1 {
return 1;
}
let mut a = 1;
let mut b = 1;
for _ in 2..=n {
let c = a + b;
a = b;
b = c;
}
b
}
// 基准测试函数
fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("Fibonacci");
// 测试递归实现
group.bench_function("recursive 20", |b| {
b.iter(|| fibonacci_recursive(black_box(20)))
});
// 测试迭代实现
group.bench_function("iterative 20", |b| {
b.iter(|| fibonacci_iterative(black_box(20)))
});
group.finish();
}
// 定义基准测试组
criterion_group!(benches, criterion_benchmark);
// 定义基准测试主函数
criterion_main!(benches);
这个示例会:
- 比较递归和迭代两种斐波那契实现
- 使用
benchmark_group
来组织相关测试 - 对每种实现运行多次测试以获得准确结果
运行后你会看到两者的性能对比,帮助你选择更优的实现方案。
Criterion.rs是优化Rust代码性能的强大工具,它通过统计学方法确保测试结果的可靠性,让你能够精确测量代码优化带来的性能提升。
Rust性能基准测试库criterion2使用指南
简介
criterion2是Rust生态中一个强大的性能基准测试库,它提供了精确的微基准测试功能和统计分析能力。相比标准库中的基准测试功能,criterion2提供了更详细的统计数据和可视化报告,能够帮助开发者更准确地测量和优化代码性能。
主要特性
- 精确的微秒级基准测试
- 高级统计分析功能
- 自动检测性能回归
- 生成HTML报告
- 支持对比基准测试
- 无需nightly Rust即可使用
使用方法
1. 添加依赖
首先在Cargo.toml
中添加criterion2依赖:
[dev-dependencies]
criterion = "0.4"
2. 创建基准测试
在项目的benches
目录下创建基准测试文件(如benches/my_benchmark.rs
):
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci(n-1) + fibonacci(n-2),
}
}
fn bench_fib(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
criterion_group!(benches, bench_fib);
criterion_main!(benches);
3. 运行基准测试
执行以下命令运行基准测试:
cargo bench
高级用法
对比基准测试
可以比较不同实现的性能:
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
fn fibonacci_recursive(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci_recursive(n-1) + fibonacci_recursive(n-2),
}
}
fn fibonacci_iterative(n: u64) -> u64 {
let mut a = 1;
let mut b = 1;
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
a
}
fn bench_fibs(c: &mut Criterion) {
let mut group = c.benchmark_group("Fibonacci");
for i in [20, 21, 22].iter() {
group.bench_with_input(BenchmarkId::new("Recursive", i), i,
|b, i| b.iter(|| fibonacci_recursive(black_box(*i))));
group.bench_with_input(BenchmarkId::new("Iterative", i), i,
|b, i| b.iter(|| fibonacci_iterative(black_box(*i))));
}
group.finish();
}
criterion_group!(benches, bench_fibs);
criterion_main!(benches);
参数化基准测试
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
fn process_data(data: &[u32]) -> u32 {
data.iter().sum()
}
fn bench_processing(c: &mut Criterion) {
let sizes = [100, 1000, 10000];
let mut group = c.benchmark_group("Processing");
for size in sizes.iter() {
let data: Vec乌32> = (0..*size).collect();
group.bench_with_input(BenchmarkId::from_parameter(size), &data,
|b, data| b.iter(|| process_data(black_box(data))));
}
group.finish();
}
criterion_group!(benches, bench_processing);
criterion_main!(benches);
自定义配置
可以自定义基准测试的配置:
use criterion::{criterion_group, criterion_main, Criterion, SamplingMode};
fn bench_config(c: &mut Criterion) {
let mut group = c.benchmark_group("sample-size-example");
group.sample_size(50) // 减少样本数量以加快测试
.sampling_mode(SamplingMode::Flat); // 线性采样
group.bench_function("fast-function", |b| b.iter(|| 1 + 1));
group.finish();
}
criterion_group!{
name = benches;
config = Criterion::default().sample_size(10);
targets = bench_config
}
criterion_main!(benches);
查看报告
运行cargo bench
后,criterion2会生成详细的HTML报告,位于target/criterion/reports
目录下。报告包含:
- 执行时间分布
- 变化趋势
- 统计摘要
- 性能对比图表
最佳实践
- 使用
black_box
防止编译器过度优化 - 为基准测试函数选择有意义的名称
- 测试不同规模的输入以了解算法复杂度
- 关注统计显著性而不仅仅是平均时间
- 在稳定的环境中运行基准测试(避免后台任务干扰)
criterion2是优化Rust代码性能的强大工具,通过其详细的统计数据和可视化报告,开发者可以更科学地评估和改进代码性能。
完整示例demo
下面是一个完整的criterion2基准测试示例,包含参数化测试和对比测试:
// benches/complete_demo.rs
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
// 三种不同的字符串拼接实现
fn concat_plus(mut s: String, parts: &[&str]) -> String {
for part in parts {
s += part;
}
s
}
fn concat_push_str(mut s: String, parts: &[&str]) -> String {
for part in parts {
s.push_str(part);
}
s
}
fn concat_join(s: String, parts: &[&str]) -> String {
s + &parts.join("")
}
// 参数化基准测试函数
fn bench_string_concat(c: &mut Criterion) {
let parts_sizes = [10, 100, 1000];
let test_string = "test".repeat(10);
let mut group = c.benchmark_group("String Concatenation");
for size in parts_sizes.iter() {
let parts: Vec<&str> = (0..*size).map(|_| &test_string[..]).collect();
group.bench_with_input(
BenchmarkId::new("Using +=", size),
&parts,
|b, parts| b.iter(|| {
concat_plus(black_box(String::new()), black_box(parts))
})
);
group.bench_with_input(
BenchmarkId::new("Using push_str", size),
&parts,
|b, parts| b.iter(|| {
concat_push_str(black_box(String::new()), black_box(parts))
})
);
group.bench_with_input(
BenchmarkId::new("Using join", size),
&parts,
|b, parts| b.iter(|| {
concat_join(black_box(String::new()), black_box(parts))
})
);
}
group.finish();
}
criterion_group!{
name = benches;
config = Criterion::default().sample_size(20);
targets = bench_string_concat
}
criterion_main!(benches);
这个完整示例演示了:
- 三种不同的字符串拼接实现
- 对不同大小的输入进行参数化测试
- 使用black_box防止编译器优化
- 自定义样本数量为20
- 清晰的benchmark分组和命名
运行这个基准测试后,criterion2会生成详细的对比报告,帮助开发者分析不同实现和不同输入规模下的性能差异。