From c602ac49ca339fad827a485663a40388033c3c7e Mon Sep 17 00:00:00 2001 From: tickbh Date: Fri, 14 Jun 2024 15:58:45 +0800 Subject: [PATCH] lru --- benches/lru.rs | 56 +++++++++++++++++++++++++++++++++++++++++++ examples/bench_lru.rs | 49 +++++++++++++++++++++++++++++++++++++ src/cache/arc.rs | 3 ++- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 benches/lru.rs create mode 100644 examples/bench_lru.rs diff --git a/benches/lru.rs b/benches/lru.rs new file mode 100644 index 0000000..bb567b6 --- /dev/null +++ b/benches/lru.rs @@ -0,0 +1,56 @@ +// bench.rs +#![feature(test)] + +extern crate test; + +use std::mem::replace; +use test::Bencher; + +// bench: find the `BENCH_SIZE` first terms of the fibonacci sequence +static BENCH_SIZE: usize = 30; + +// recursive fibonacci +fn fibonacci(n: usize) -> u32 { + if n < 2 { + 1 + } else { + fibonacci(n - 1) + fibonacci(n - 2) + } +} + +// iterative fibonacci +struct Fibonacci { + curr: u32, + next: u32, +} + +impl Iterator for Fibonacci { + type Item = u32; + fn next(&mut self) -> Option { + let new_next = self.curr + self.next; + let new_curr = replace(&mut self.next, new_next); + + Some(replace(&mut self.curr, new_curr)) + } +} + +fn fibonacci_sequence() -> Fibonacci { + Fibonacci { curr: 1, next: 1 } +} + +// function to benchmark must be annotated with `#[bench]` +#[bench] +fn recursive_fibonacci(b: &mut Bencher) { + // exact code to benchmark must be passed as a closure to the iter + // method of Bencher + b.iter(|| { + (0..BENCH_SIZE).map(fibonacci).collect::>() + }) +} + +#[bench] +fn iterative_fibonacci(b: &mut Bencher) { + b.iter(|| { + fibonacci_sequence().take(BENCH_SIZE).collect::>() + }) +} \ No newline at end of file diff --git a/examples/bench_lru.rs b/examples/bench_lru.rs new file mode 100644 index 0000000..9900f35 --- /dev/null +++ b/examples/bench_lru.rs @@ -0,0 +1,49 @@ +use std::collections::hash_map::RandomState; +use std::time::Instant; +use algorithm::{ArcCache, LfuCache, LruCache, LruKCache}; + +macro_rules! do_test_bench { + ($name: expr, $cache: expr, $num: expr, $evict: expr, $data1: expr, $data2: expr) => { + let mut cost = vec![]; + let now = Instant::now(); + for i in 0..$num { + $cache.insert($data1[i], $data1[i]); + } + cost.push(now.elapsed().as_micros()); + + let now = Instant::now(); + for i in 0..$num { + $cache.get(&$data1[i]); + } + cost.push(now.elapsed().as_micros()); + + let now = Instant::now(); + for i in 0..$num { + $cache.get(&$data2[i]); + } + cost.push(now.elapsed().as_micros()); + println!("{} 耗时:{}", $name, cost.iter().map(|v| v.to_string()).collect::>().join("\t")); + }; +} + +fn do_bench(num: usize, times: usize) { + let evict = num * 2; + let mut data1 = (0..num).collect::>(); + let mut data2 = vec![]; + for _ in 0..evict { + data2.push(rand::random::() % evict); + } + let mut lru = LruCache::::new(num); + let mut lruk = LruKCache::::new(num); + let mut lfu = LfuCache::::new(num); + let mut arc = ArcCache::::new(num); + do_test_bench!("LruCache", lru, num, evict, &data1, &data2); + do_test_bench!("LruKCache", lruk, num, evict, &data1, &data2); + do_test_bench!("LfuCache", lfu, num, evict, &data1, &data2); + do_test_bench!("ArcCache", arc, num, evict, &data1, &data2); + // println!("耗时:{}", set_timer); +} + +fn main() { + do_bench(1e5 as usize, 5); +} \ No newline at end of file diff --git a/src/cache/arc.rs b/src/cache/arc.rs index 0730c98..ded0bc4 100644 --- a/src/cache/arc.rs +++ b/src/cache/arc.rs @@ -12,7 +12,7 @@ use std::{ borrow::Borrow, - collections::{hash_map::RandomState}, + collections::hash_map::RandomState, fmt::{self, Debug}, hash::{BuildHasher, Hash}, ops::{Index, IndexMut}, @@ -54,6 +54,7 @@ pub struct ArcCache { } impl ArcCache { + /// 因为存在四个数组, 所以实际的容量为这个的4倍 pub fn new(cap: usize) -> Self { ArcCache::with_hasher(cap, RandomState::new()) }