Divan是一个快速舒适的Rust代码基准测试框架,让我们通过例子来学习它。
新建一个Rust项目:
cargo new divan-example
Cargo.toml文件的内容如下:
[dev-dependencies]
divan = "0.1.2"
[[bench]]
name = "example"
harness = false
在项目根目录下创建benches目录,在目录下创建一个example.rs文件,文件代码如下:
fn main() {
// 运行已注册的基准测试
divan::main();
}
// 定义一个' fibonacci '函数并将其注册为基准测试
#[divan::bench]
fn fibonacci() -> u64 {
fn compute(n: u64) -> u64 {
if n <= 1 {
1
} else {
compute(n - 2) + compute(n - 1)
}
}
compute(divan::black_box(10))
}
使用#[Divan::bench]属性可以在任何地方注册Divan基准测试,类似于#[test]。
运行cargo bench命令进行测试,结果如下:
Timer precision: 15 ns
example fastest │ slowest │ median │ mean │ samples │ iters
╰─ fibonacci 191.5 ns │ 204.8 ns │ 192.4 ns │ 193.2 ns │ 100 │ 800
属性选项
每个基准测试还可以通过属性选项来控制,比如max_time和sample_size:
#[divan::bench(
max_time = 0.001, // 秒
sample_size = 64, // 64 × 80 = 5120
)]
fn fibonacci() -> u64 {
......
}
测试结果如下:
Timer precision: 15 ns
example fastest │ slowest │ median │ mean │ samples │ iters
╰─ fibonacci 189.9 ns │ 196.7 ns │ 190 ns │ 190.1 ns │ 80 │ 5120
模块树结构
如果我们想比较fibonacci的递归实现和迭代实现,可以把它们放在一个模块中:
mod fibonacci {
const N: u64 = 10;
// 迭代实现
#[divan::bench]
fn iterative() -> u64 {
let mut previous = 1;
let mut current = 1;
for _ in 2..=divan::black_box(N) {
let next = previous + current;
previous = current;
current = next;
}
current
}
// 递归实现
#[divan::bench]
fn recursive() -> u64 {
fn compute(n: u64) -> u64 {
if n <= 1 {
1
} else {
compute(n - 2) + compute(n - 1)
}
}
compute(divan::black_box(N))
}
}
测试结果如下:
Timer precision: 14 ns
example fastest │ slowest │ median │ mean │ samples │ iters
╰─ fibonacci │ │ │ │ │
├─ iterative 9.152 ns │ 15.12 ns │ 9.187 ns │ 9.535 ns │ 100 │ 25600
╰─ recursive 191.5 ns │ 285.8 ns │ 192.3 ns │ 202.3 ns │ 100 │ 800
fibonacci迭代实现明显比递归实现的效率高很多。
泛型测试
Divan可以对泛型函数进行基准测试,下面的基准测试示例用于测试From<&str>转换为&str和String的性能:
#[divan::bench(types = [
&str,
String,
])]
fn from_str<'a, T>() -> T
where
T: From<&'a str>,
{
divan::black_box("hello world").into()
}
测试结果如下:
Timer precision: 19 ns
example fastest │ slowest │ median │ mean │ samples │ iters
╰─ from_str │ │ │ │ │
├─ &str 1.809 ns │ 3.289 ns │ 1.819 ns │ 1.902 ns │ 100 │ 102400
╰─ String 80.12 ns │ 127.5 ns │ 81.02 ns │ 82.75 ns │ 100 │ 3200
从测试结果可以看出,From<&str>转换为String的性能更低,因为涉及到堆分配操作。