|
| 1 | +use criterion::{ |
| 2 | + black_box, criterion_group, criterion_main, BatchSize::SmallInput, BenchmarkId, Criterion, |
| 3 | +}; |
| 4 | +use indexmap::IndexMap; |
| 5 | +use opentelemetry_api::{Key, KeyValue, Value}; |
| 6 | +use opentelemetry_sdk::trace::EvictedHashMap; |
| 7 | +use pprof::criterion::{Output, PProfProfiler}; |
| 8 | +use std::iter::Iterator; |
| 9 | + |
| 10 | +fn criterion_benchmark(c: &mut Criterion) { |
| 11 | + let cap = 32; |
| 12 | + let input = [(2, 32, cap), (8, 32, cap), (32, 32, cap)]; |
| 13 | + populate_benchmark(c, &input); |
| 14 | + lookup_benchmark(c, &input); |
| 15 | + populate_and_lookup_benchmark(c, &input); |
| 16 | +} |
| 17 | + |
| 18 | +fn populate_benchmark(c: &mut Criterion, input: &[(usize, u32, usize)]) { |
| 19 | + let mut group = c.benchmark_group("populate"); |
| 20 | + for &(n, max, capacity) in input { |
| 21 | + let parameter_string = format!("{n:02}/{max:02}/{capacity:02}"); |
| 22 | + |
| 23 | + group.bench_function( |
| 24 | + BenchmarkId::new("EvictedHashMap", parameter_string.clone()), |
| 25 | + |b| { |
| 26 | + b.iter(|| populate_evicted_hashmap(n, max, capacity)); |
| 27 | + }, |
| 28 | + ); |
| 29 | + group.bench_function( |
| 30 | + BenchmarkId::new("IndexMap", parameter_string.clone()), |
| 31 | + |b| { |
| 32 | + b.iter(|| populate_indexmap(n, max, capacity)); |
| 33 | + }, |
| 34 | + ); |
| 35 | + group.bench_function(BenchmarkId::new("TwoVecs", parameter_string.clone()), |b| { |
| 36 | + b.iter(|| populate_twovecs(n, max, capacity)); |
| 37 | + }); |
| 38 | + group.bench_function(BenchmarkId::new("OneVec", parameter_string.clone()), |b| { |
| 39 | + b.iter(|| populate_onevec(n, max, capacity)); |
| 40 | + }); |
| 41 | + } |
| 42 | + group.finish(); |
| 43 | +} |
| 44 | + |
| 45 | +fn lookup_benchmark(c: &mut Criterion, input: &[(usize, u32, usize)]) { |
| 46 | + let mut group = c.benchmark_group("lookup"); |
| 47 | + for &(n, max, capacity) in input { |
| 48 | + let lookup_keys = &MAP_KEYS[n - 2..n]; |
| 49 | + let parameter_string = format!("{n:02}/{max:02}/{capacity:02}"); |
| 50 | + group.bench_function( |
| 51 | + BenchmarkId::new("EvictedHashMap", parameter_string.clone()), |
| 52 | + |b| { |
| 53 | + b.iter_batched( |
| 54 | + || populate_evicted_hashmap(n, max, capacity), |
| 55 | + |map| lookup_evicted_hashmap(&map, lookup_keys), |
| 56 | + SmallInput, |
| 57 | + ); |
| 58 | + }, |
| 59 | + ); |
| 60 | + group.bench_function( |
| 61 | + BenchmarkId::new("IndexMap", parameter_string.clone()), |
| 62 | + |b| { |
| 63 | + b.iter_batched( |
| 64 | + || populate_indexmap(n, max, capacity), |
| 65 | + |map| lookup_indexmap(&map, lookup_keys), |
| 66 | + SmallInput, |
| 67 | + ); |
| 68 | + }, |
| 69 | + ); |
| 70 | + group.bench_function(BenchmarkId::new("OneVec", parameter_string.clone()), |b| { |
| 71 | + b.iter_batched( |
| 72 | + || populate_onevec(n, max, capacity), |
| 73 | + |vec| lookup_onevec(&vec, lookup_keys), |
| 74 | + SmallInput, |
| 75 | + ); |
| 76 | + }); |
| 77 | + group.bench_function(BenchmarkId::new("TwoVecs", parameter_string.clone()), |b| { |
| 78 | + b.iter_batched( |
| 79 | + || populate_twovecs(n, max, capacity), |
| 80 | + |(keys, vals)| lookup_twovec(&keys, &vals, lookup_keys), |
| 81 | + SmallInput, |
| 82 | + ); |
| 83 | + }); |
| 84 | + } |
| 85 | + group.finish(); |
| 86 | +} |
| 87 | + |
| 88 | +fn populate_and_lookup_benchmark(c: &mut Criterion, input: &[(usize, u32, usize)]) { |
| 89 | + let mut group = c.benchmark_group("populate_and_lookup"); |
| 90 | + for &(n, max, capacity) in input { |
| 91 | + let lookup_keys = &MAP_KEYS[n - 2..n]; |
| 92 | + let parameter_string = format!("{n:02}/{max:02}/{capacity:02}"); |
| 93 | + group.bench_function( |
| 94 | + BenchmarkId::new("EvictedHashMap", parameter_string.clone()), |
| 95 | + |b| { |
| 96 | + b.iter(|| { |
| 97 | + let map = populate_evicted_hashmap(n, max, capacity); |
| 98 | + lookup_evicted_hashmap(&map, lookup_keys); |
| 99 | + }); |
| 100 | + }, |
| 101 | + ); |
| 102 | + group.bench_function( |
| 103 | + BenchmarkId::new("IndexMap", parameter_string.clone()), |
| 104 | + |b| { |
| 105 | + b.iter(|| { |
| 106 | + let map = populate_indexmap(n, max, capacity); |
| 107 | + lookup_indexmap(&map, lookup_keys); |
| 108 | + }); |
| 109 | + }, |
| 110 | + ); |
| 111 | + group.bench_function(BenchmarkId::new("OneVec", parameter_string.clone()), |b| { |
| 112 | + b.iter(|| { |
| 113 | + let vec = populate_onevec(n, max, capacity); |
| 114 | + lookup_onevec(&vec, lookup_keys); |
| 115 | + }); |
| 116 | + }); |
| 117 | + group.bench_function(BenchmarkId::new("TwoVecs", parameter_string.clone()), |b| { |
| 118 | + b.iter(|| { |
| 119 | + let (keys, vals) = populate_twovecs(n, max, capacity); |
| 120 | + lookup_twovec(&keys, &vals, lookup_keys); |
| 121 | + }); |
| 122 | + }); |
| 123 | + } |
| 124 | + group.finish(); |
| 125 | +} |
| 126 | + |
| 127 | +fn populate_evicted_hashmap(n: usize, max: u32, capacity: usize) -> EvictedHashMap { |
| 128 | + let mut map = EvictedHashMap::new(max, capacity); |
| 129 | + for (idx, key) in MAP_KEYS.iter().enumerate().take(n) { |
| 130 | + map.insert(KeyValue::new(*key, idx as i64)); |
| 131 | + } |
| 132 | + map |
| 133 | +} |
| 134 | + |
| 135 | +fn lookup_evicted_hashmap(map: &EvictedHashMap, keys: &[&'static str]) { |
| 136 | + for key in keys { |
| 137 | + black_box(map.get(&Key::new(*key))); |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +fn populate_indexmap(n: usize, max: u32, _capacity: usize) -> IndexMap<Key, Value> { |
| 142 | + let mut map = IndexMap::with_capacity(max as usize); |
| 143 | + for (idx, key) in MAP_KEYS.iter().enumerate().take(n) { |
| 144 | + map.insert(Key::new(*key), Value::I64(idx as i64)); |
| 145 | + } |
| 146 | + map |
| 147 | +} |
| 148 | + |
| 149 | +fn lookup_indexmap(map: &IndexMap<Key, Value>, keys: &[&'static str]) { |
| 150 | + for key in keys { |
| 151 | + black_box(map.get(&Key::new(*key))); |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +fn populate_onevec(n: usize, max: u32, _capacity: usize) -> Vec<(Key, Value)> { |
| 156 | + let mut tuples = Vec::with_capacity(max as usize); |
| 157 | + for (idx, key) in MAP_KEYS.iter().enumerate().take(n) { |
| 158 | + tuples.push((Key::new(*key), Value::I64(idx as i64))); |
| 159 | + } |
| 160 | + tuples |
| 161 | +} |
| 162 | + |
| 163 | +fn lookup_onevec(vec: &[(Key, Value)], keys: &[&'static str]) { |
| 164 | + for key in keys { |
| 165 | + black_box( |
| 166 | + vec.iter() |
| 167 | + .position(|(k, _v)| *k == Key::new(*key)) |
| 168 | + .map(|idx| vec.get(idx)), |
| 169 | + ); |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +fn populate_twovecs(n: usize, max: u32, _capacity: usize) -> (Vec<Key>, Vec<Value>) { |
| 174 | + let mut keys = Vec::with_capacity(max as usize); |
| 175 | + let mut vals = Vec::with_capacity(max as usize); |
| 176 | + for (idx, key) in MAP_KEYS.iter().enumerate().take(n) { |
| 177 | + keys.push(Key::new(*key)); |
| 178 | + vals.push(Value::I64(idx as i64)); |
| 179 | + } |
| 180 | + (keys, vals) |
| 181 | +} |
| 182 | + |
| 183 | +fn lookup_twovec(keys: &[Key], vals: &[Value], lookup_keys: &[&'static str]) { |
| 184 | + for key in lookup_keys { |
| 185 | + black_box( |
| 186 | + keys.iter() |
| 187 | + .position(|k| *k == Key::new(*key)) |
| 188 | + .map(|idx| vals.get(idx)), |
| 189 | + ); |
| 190 | + } |
| 191 | +} |
| 192 | + |
| 193 | +const MAP_KEYS: [&str; 64] = [ |
| 194 | + "key.1", "key.2", "key.3", "key.4", "key.5", "key.6", "key.7", "key.8", "key.9", "key.10", |
| 195 | + "key.11", "key.12", "key.13", "key.14", "key.15", "key.16", "key.17", "key.18", "key.19", |
| 196 | + "key.20", "key.21", "key.22", "key.23", "key.24", "key.25", "key.26", "key.27", "key.28", |
| 197 | + "key.29", "key.30", "key.31", "key.32", "key.33", "key.34", "key.35", "key.36", "key.37", |
| 198 | + "key.38", "key.39", "key.40", "key.41", "key.42", "key.43", "key.44", "key.45", "key.46", |
| 199 | + "key.47", "key.48", "key.49", "key.50", "key.51", "key.52", "key.53", "key.54", "key.55", |
| 200 | + "key.56", "key.57", "key.58", "key.59", "key.60", "key.61", "key.62", "key.63", "key.64", |
| 201 | +]; |
| 202 | + |
| 203 | +criterion_group! { |
| 204 | + name = benches; |
| 205 | + config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); |
| 206 | + targets = criterion_benchmark |
| 207 | +} |
| 208 | +criterion_main!(benches); |
0 commit comments