6.7 KiB, 7 runs
created by r1870400018:17, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use std::alloc; |
| 2 | use cap::Cap; |
| 3 | |
| 4 | #[global_allocator] |
| 5 | static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::max_value()); |
| 6 | |
| 7 | use oxedyne_fe2o3_sand::treemap::{ |
| 8 | ByteKey, |
| 9 | TreeMap, |
| 10 | }; |
| 11 | use oxedyne_fe2o3_core::{debug}; |
| 12 | use oxedyne_fe2o3_core::data::{Stack}; |
| 13 | |
| 14 | use criterion::{ |
| 15 | criterion_group, |
| 16 | criterion_main, |
| 17 | Criterion, |
| 18 | BenchmarkId, |
| 19 | Throughput, |
| 20 | }; |
| 21 | |
| 22 | use std::collections::{ |
| 23 | BTreeMap, |
| 24 | HashMap, |
| 25 | }; |
| 26 | |
| 27 | use rand::Rng; |
| 28 | use rand::distributions::{ |
| 29 | Distribution, |
| 30 | Uniform, |
| 31 | }; |
| 32 | |
| 33 | fn create_keys(n: usize, len: usize) -> Vec<Vec<u8>> { |
| 34 | let mut result = Vec::new(); |
| 35 | for _ in 0..n { |
| 36 | result.push((0..len).map(|_| { rand::random::<u8>() }).collect()); |
| 37 | } |
| 38 | result |
| 39 | } |
| 40 | |
| 41 | fn create_data(len: usize) -> Vec<u8> { |
| 42 | (0..len).map(|_| { rand::random::<u8>() }).collect() |
| 43 | } |
| 44 | |
| 45 | fn hashmap_insertions<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>)) -> (HashMap<Vec<u8>, &'a Vec<u8>>, usize) { |
| 46 | let (keys, data) = input; |
| 47 | let mem = ALLOCATOR.allocated(); |
| 48 | let mut map = HashMap::new(); |
| 49 | for key in keys { |
| 50 | map.insert(key.clone(), data); |
| 51 | } |
| 52 | (map, ALLOCATOR.allocated() - mem) |
| 53 | } |
| 54 | |
| 55 | fn hashmap_reads<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>), map: HashMap<Vec<u8>, &'a Vec<u8>>) { |
| 56 | let (keys, _) = input; |
| 57 | for key in keys { |
| 58 | map.get(&key.clone()); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | fn btreemap_insertions<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>)) -> (BTreeMap<Vec<u8>, &'a Vec<u8>>, usize) { |
| 63 | let (keys, data) = input; |
| 64 | let mem = ALLOCATOR.allocated(); |
| 65 | let mut map = BTreeMap::new(); |
| 66 | for key in keys { |
| 67 | map.insert(key.clone(), data); |
| 68 | } |
| 69 | (map, ALLOCATOR.allocated() - mem) |
| 70 | } |
| 71 | |
| 72 | fn btreemap_reads<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>), map: BTreeMap<Vec<u8>, &'a Vec<u8>>) { |
| 73 | let (keys, _) = input; |
| 74 | for key in keys { |
| 75 | map.get(&key.clone()); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | fn treemap_insertions<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>)) -> (TreeMap<Stack<&'a Vec<u8>>>, usize) { |
| 80 | let (keys, data) = input; |
| 81 | let mem = ALLOCATOR.allocated(); |
| 82 | let mut map = TreeMap::new(); |
| 83 | for key in keys { |
| 84 | map.insert_data(ByteKey::new(key.clone()), data); |
| 85 | } |
| 86 | (map, ALLOCATOR.allocated() - mem) |
| 87 | } |
| 88 | |
| 89 | fn treemap_reads<'a>(input: (&'a Vec<Vec<u8>>, &'a Vec<u8>), map: TreeMap<Stack<&'a Vec<u8>>>) { |
| 90 | let (keys, _) = input; |
| 91 | for key in keys { |
| 92 | map.get_data_ref(ByteKey::new(key.clone())); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | fn bench_map_insertions(c: &mut Criterion) { |
| 97 | // Set the limit to 500 [MiB]. |
| 98 | debug!("*********************************************"); |
| 99 | debug!("* BENCHMARK MAP INSERTIONS *"); |
| 100 | debug!("*********************************************"); |
| 101 | ALLOCATOR.set_limit(500 * 1024 * 1024).unwrap(); |
| 102 | debug!("Currently allocated: {} [B]", ALLOCATOR.allocated()); |
| 103 | static N: usize = 1000; |
| 104 | let mut group = c.benchmark_group("Maps"); |
| 105 | |
| 106 | for len in [10, 50, 100].iter() { |
| 107 | let keys = create_keys(N, *len); |
| 108 | let data = create_data(10); |
| 109 | |
| 110 | // Estimate memory usage |
| 111 | debug!("Insertions: {}, key length: {}", N, len); |
| 112 | let (hashmap, mem) = hashmap_insertions((&keys, &data)); |
| 113 | debug!("std::collections::HashMap memory: {} [KB]", mem/1024); |
| 114 | let (btreemap, mem) = btreemap_insertions((&keys, &data)); |
| 115 | debug!("std::collections::BTreeMap memory: {} [KB]", mem/1024); |
| 116 | let (treemap, mem) = treemap_insertions((&keys, &data)); |
| 117 | debug!("fe2o3::treemap::TreeMap memory: {} [KB]", mem/1024); |
| 118 | |
| 119 | group.throughput(Throughput::Bytes(*len as u64)); |
| 120 | group.bench_with_input( |
| 121 | BenchmarkId::new("std::collections::HashMap", len), |
| 122 | &(&keys, &data), |
| 123 | |b, (keys, data)| { |
| 124 | b.iter(|| hashmap_insertions((&keys, &data))); |
| 125 | } |
| 126 | ); |
| 127 | group.bench_with_input( |
| 128 | BenchmarkId::new("std::collections::BTreeMap", len), |
| 129 | &(&keys, &data), |
| 130 | |b, (keys, data)| { |
| 131 | b.iter(|| btreemap_insertions((&keys, &data))); |
| 132 | } |
| 133 | ); |
| 134 | group.bench_with_input( |
| 135 | BenchmarkId::new("fe2o3::treemap::TreeMap", len), |
| 136 | &(&keys, &data), |
| 137 | |b, (keys, data)| { |
| 138 | b.iter(|| treemap_insertions((&keys, &data))); |
| 139 | } |
| 140 | ); |
| 141 | } |
| 142 | group.finish(); |
| 143 | } |
| 144 | |
| 145 | fn bench_map_retrievals(c: &mut Criterion) { |
| 146 | // Set the limit to 500 [MiB]. |
| 147 | debug!("*********************************************"); |
| 148 | debug!("* BENCHMARK MAP RETRIEVALS *"); |
| 149 | debug!("*********************************************"); |
| 150 | ALLOCATOR.set_limit(500 * 1024 * 1024).unwrap(); |
| 151 | debug!("Currently allocated: {} [B]", ALLOCATOR.allocated()); |
| 152 | static N: usize = 1000; |
| 153 | let mut group = c.benchmark_group("Maps"); |
| 154 | |
| 155 | for len in [6, 10, 50, 100].iter() { |
| 156 | let keys = create_keys(N, *len); |
| 157 | let data = create_data(10); |
| 158 | |
| 159 | // Estimate memory usage |
| 160 | debug!("Retrievals: {}, key length: {}", N, len); |
| 161 | let (mut hashmap, mem) = hashmap_insertions((&keys, &data)); |
| 162 | debug!("std::collections::HashMap memory: {} [KB]", mem/1024); |
| 163 | let (mut btreemap, mem) = btreemap_insertions((&keys, &data)); |
| 164 | debug!("std::collections::BTreeMap memory: {} [KB]", mem/1024); |
| 165 | let (mut treemap, mem) = treemap_insertions((&keys, &data)); |
| 166 | debug!("fe2o3::treemap::TreeMap memory: {} [KB]", mem/1024); |
| 167 | |
| 168 | group.throughput(Throughput::Bytes(*len as u64)); |
| 169 | group.bench_with_input( |
| 170 | BenchmarkId::new("std::collections::HashMap", len), |
| 171 | &(&keys, &data), |
| 172 | |b, (keys, data)| { |
| 173 | b.iter(|| hashmap_reads( |
| 174 | (&keys, &data), |
| 175 | std::mem::replace( |
| 176 | &mut hashmap, |
| 177 | HashMap::new(), |
| 178 | ), |
| 179 | )); |
| 180 | } |
| 181 | ); |
| 182 | group.bench_with_input( |
| 183 | BenchmarkId::new("std::collections::BTreeMap", len), |
| 184 | &(&keys, &data), |
| 185 | |b, (keys, data)| { |
| 186 | b.iter(|| btreemap_reads( |
| 187 | (&keys, &data), |
| 188 | std::mem::replace( |
| 189 | &mut btreemap, |
| 190 | BTreeMap::new(), |
| 191 | ), |
| 192 | )); |
| 193 | } |
| 194 | ); |
| 195 | group.bench_with_input( |
| 196 | BenchmarkId::new("fe2o3::treemap::TreeMap", len), |
| 197 | &(&keys, &data), |
| 198 | |b, (keys, data)| { |
| 199 | b.iter(|| treemap_reads( |
| 200 | (&keys, &data), |
| 201 | std::mem::replace( |
| 202 | &mut treemap, |
| 203 | TreeMap::new(), |
| 204 | ), |
| 205 | )); |
| 206 | } |
| 207 | ); |
| 208 | } |
| 209 | group.finish(); |
| 210 | } |
| 211 | |
| 212 | criterion_group!(benches, bench_map_insertions, bench_map_retrievals); |
| 213 | criterion_main!(benches); |