From 612dca9afdd503512e468ace6d992834fd81a347 Mon Sep 17 00:00:00 2001 From: jackymao Date: Wed, 28 Sep 2022 12:03:20 +0800 Subject: [PATCH] add benchmark_test --- .../benchmark_tests.json" | 7 + .../benchmark_tests.md" | 186 ++++++++++++++++++ .../config.json" | 4 +- 3 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 "data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.json" create mode 100644 "data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.md" diff --git "a/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.json" "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.json" new file mode 100644 index 0000000..0632052 --- /dev/null +++ "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.json" @@ -0,0 +1,7 @@ +{ + "type": "code_options", + "author": "jackymao_com", + "source": "benchmark_tests.md", + "notebook_enable": false, + "exercise_id": "" +} \ No newline at end of file diff --git "a/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.md" "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.md" new file mode 100644 index 0000000..e6fc042 --- /dev/null +++ "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/benchmark_tests.md" @@ -0,0 +1,186 @@ +# 基准测试 + +基准测试通常是在开发的最后阶段进行的(虽然也有例外),用途是知道代码运行所花的时间,或提供代码中存在的性能缺陷的测试信息。 + +对所开发的程序执行基准测试有多种方法。 + +第一种简单的方法是使用 std::time::Instant 来测量程序的执行时间,虽然这并不能提供精确和完善的数据。 + +```rust +fn main() { + use std::time::Instant; + let now = Instant::now(); + + // Code block to measure. + { + println!("test"); + } + + let elapsed = now.elapsed(); + println!("Elapsed: {:.2?}", elapsed); +} +``` + +第二种是使用 Rust 库,比较常见的库有 criterion 和 flamegraph + + +要做好一个基准测试及代码优化并不容易,需要考虑的因素很多: +- 不要过早的对代码进行优化和测试 +- 在代码优化和安全性之间要平衡取舍 +- 如果需要,对编译速度和编译文件大小之间要平衡取舍 +- 使用优化编译命令对代码做基准测试,即编译的时候使用 rustc -O3 选项或 cargo build --release. 在使用 cargo bench 命令时它会自动打开优化 +- 多次测试并进行统计。单次测试往往不够准确,测试用机的负载(操作系统,CPU,硬盘,缓存等)不同测试结果都会不同。 +- 确保你的测试代码不会被后端优化掉,如 LLVM 会在后端进行各种级别的各种优化,或按照测试框架的库的说明来操作。 +- 更多其他注意事项 + + + +对于 Fibonacci 序列算法,在以下的 Benchmark 中调用了四种算法 + +```rust + +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use rust_fibonacci::*; +use std::collections::HashMap; + +fn bench_fibs(c: &mut Criterion) { + let mut group = c.benchmark_group("Fibonacci"); + + for i in [20, 21].iter() { + group.bench_with_input(BenchmarkId::new("Standard", i), i, |b, i| { + b.iter(|| fib_standard(*i)) + }); + + group.bench_with_input(BenchmarkId::new("Recursion", i), i, |b, i| { + b.iter(|| fib_recursive(*i)) + }); + + group.bench_with_input(BenchmarkId::new("Memoization", i), i, |b, i| { + b.iter(|| { + let mut memo = HashMap::new(); + fib_memoization(*i, &mut memo); + }) + }); + + group.bench_with_input(BenchmarkId::new("Iterator", i), i, |b, i| { + b.iter(|| { + FibIterator::default().nth(*i).unwrap(); + }) + }); + } + group.finish(); +} + +criterion_group!(benches, bench_fibs); +criterion_main!(benches); + +``` + + + +问答: + 在如下的四种算法代码中,预期最慢的是: + + +## 答案 + +A + +```rust + +pub fn fib_recursive(n: usize) -> usize { + match n { + 0 | 1 => 1, + _ => fib_recursive(n-2) + fib_recursive(n-1), + } +} + +``` + + +## 选项 + +### + +B + + +```rust + +pub fn fib_standard(n: usize) -> usize { + let mut a = 1; + let mut b = 1; + + for _ in 1..n { + let old = a; + a = b; + b += old; + } + + b +} + +``` + +### + +C + +```rust + +use std::collections::HashMap; + +pub fn fib_memoization(n: usize, memo: &mut HashMap) -> usize { + if let Some(v) = memo.get(&n) { + return *v; + } + + let v = match n { + 0 | 1 => 1, + _ => fib_memoization(n-2, memo) + fib_memoization(n-1, memo), + }; + + memo.insert(n, v); + v +} + +``` + +### + +D + +```rust + +pub struct FibIterator { + a: usize, + b: usize +} + +impl Default for FibIterator { + fn default() -> Self { + FibIterator { a: 1, b: 1 } + } +} + +impl Iterator for FibIterator { + type Item = usize; + + fn next(&mut self) -> Option { + let curr = self.a; + self.a = self.b; + self.b = curr + self.a; + + Some(curr) + } +} + +``` + + + \ No newline at end of file diff --git "a/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/config.json" "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/config.json" index c401e23..cd20de7 100644 --- "a/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/config.json" +++ "b/data/1.rust\345\210\235\351\230\266/4.\346\265\213\350\257\225/4.\346\200\247\350\203\275\346\265\213\350\257\225/config.json" @@ -2,7 +2,9 @@ "node_id": "rust-f86c3d949b624756923c6931daf8ced0", "keywords": [], "children": [], - "export": [], + "export": [ + "benchmark_tests.json" + ], "keywords_must": [], "keywords_forbid": [] } \ No newline at end of file -- GitLab