-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The commit implements a variant of LRU cache with lazy eviction: * Each entry maintains an associated ordinal value representing when the entry was last accessed. * The cache is allowed to grow up to 2 times specified capacity with no evictions, at which point, the excess entries are evicted based on LRU policy resulting in an _amortized_ `O(1)` performance. In many use cases which can allow the cache to store 2 times capacity and can tolerate amortized nature of performance, this results in better average performance as shown by the added benchmarks. Additionally, with the existing implementation, `.get` requires a mutable reference `&mut self`. In a multi-threaded setting, this requires an exclusive write-lock on the cache even on the read path, which can exacerbate lock contentions. With lazy eviction, the ordinal values can be updated using atomic operations, allowing shared lock for lookups.
- Loading branch information
1 parent
cf063f6
commit cb82a39
Showing
4 changed files
with
574 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#![feature(test)] | ||
|
||
extern crate core; | ||
extern crate lru; | ||
extern crate rand; | ||
extern crate test; | ||
|
||
use core::num::NonZeroUsize; | ||
use rand::Rng; | ||
use test::Bencher; | ||
|
||
const REPS: usize = 1 << 10; | ||
const NUM_KEYS: usize = 1 << 20; | ||
const CAPACITY: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1 << 17) }; | ||
|
||
macro_rules! impl_put_bench { | ||
($name: ident, $cache: ty) => { | ||
fn $name(bencher: &mut Bencher, capacity: NonZeroUsize, num_keys: usize, reps: usize) { | ||
let mut rng = rand::thread_rng(); | ||
let mut cache = <$cache>::new(capacity); | ||
for _ in 0..5 * capacity.get() { | ||
let key = rng.gen_range(0..num_keys); | ||
let _ = cache.put(key, ()); | ||
} | ||
bencher.iter(|| { | ||
for _ in 0..reps { | ||
let key = rng.gen_range(0..num_keys); | ||
let _ = cache.put(key, ()); | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! impl_get_bench { | ||
($name: ident, $cache: ty) => { | ||
fn $name(bencher: &mut Bencher, capacity: NonZeroUsize, num_keys: usize, reps: usize) { | ||
let mut rng = rand::thread_rng(); | ||
let mut cache = <$cache>::new(capacity); | ||
for _ in 0..5 * capacity.get() { | ||
let key = rng.gen_range(0..num_keys); | ||
let _ = cache.put(key, ()); | ||
} | ||
bencher.iter(|| { | ||
for _ in 0..reps { | ||
let key = rng.gen_range(0..num_keys); | ||
let _ = cache.get(&key); | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
|
||
impl_put_bench!(run_put_bench, lru::LruCache<usize, ()>); | ||
impl_put_bench!(run_put_bench_lazy, lru::lazy::LruCache<usize, ()>); | ||
|
||
impl_get_bench!(run_get_bench, lru::LruCache<usize, ()>); | ||
impl_get_bench!(run_get_bench_lazy, lru::lazy::LruCache<usize, ()>); | ||
|
||
#[bench] | ||
fn bench_put(bencher: &mut Bencher) { | ||
run_put_bench(bencher, CAPACITY, NUM_KEYS, REPS); | ||
} | ||
|
||
#[bench] | ||
fn bench_put_lazy(bencher: &mut Bencher) { | ||
run_put_bench_lazy(bencher, CAPACITY, NUM_KEYS, REPS); | ||
} | ||
|
||
#[bench] | ||
fn bench_get(bencher: &mut Bencher) { | ||
run_get_bench(bencher, CAPACITY, NUM_KEYS, REPS); | ||
} | ||
|
||
#[bench] | ||
fn bench_get_lazy(bencher: &mut Bencher) { | ||
run_get_bench_lazy(bencher, CAPACITY, NUM_KEYS, REPS); | ||
} |
Oops, something went wrong.