bench/
bench.rs

1use std::{
2    sync::{
3        Arc,
4        atomic::{AtomicI32, Ordering},
5    },
6    time::Instant,
7};
8
9use hypercounter::HyperCounter;
10
11const THREADS: i32 = 12;
12
13fn pretty_int(i: i32) -> String {
14    let mut s = String::new();
15    let i_str = i.to_string();
16    let chars_rev = i_str.chars().rev().enumerate();
17
18    for (idx, val) in chars_rev {
19        if idx != 0 && idx % 3 == 0 {
20            s.insert(0, ',');
21        }
22        s.insert(0, val);
23    }
24
25    s
26}
27
28fn main() {
29    load_ops_per_second_single_threaded_fetch_add_single_key();
30    load_ops_per_second_single_threaded_fetch_add_multi_key();
31    load_ops_per_second_single_threaded_insert();
32    load_ops_per_second_single_threaded_remove();
33    load_ops_per_second_single_threaded_churn();
34    load_ops_per_second_multi_threaded_fetch_add_single_key();
35    load_ops_per_second_multi_threaded_fetch_add_multi_key();
36    load_ops_per_second_multi_threaded_insert();
37    load_ops_per_second_multi_threaded_remove();
38    load_ops_per_second_multi_threaded_churn();
39}
40
41fn load_ops_per_second_single_threaded_fetch_add_single_key() {
42    let counter: HyperCounter<i32, AtomicI32> = HyperCounter::new();
43
44    let now = Instant::now();
45    let mut i = 0;
46
47    loop {
48        counter.fetch_add(1, 1, Ordering::Relaxed);
49        i += 1;
50
51        if now.elapsed().as_secs() >= 1 {
52            break;
53        }
54    }
55
56    println!("Single-threaded single-key load ops/sec: {}", pretty_int(i));
57}
58
59fn load_ops_per_second_single_threaded_fetch_add_multi_key() {
60    let counter: HyperCounter<i32, AtomicI32> = HyperCounter::new();
61
62    let now = Instant::now();
63    let mut i = 0;
64
65    loop {
66        let key = i % 1000;
67        counter.fetch_add(key, 1, Ordering::Relaxed);
68        i += 1;
69
70        if now.elapsed().as_secs() >= 1 {
71            break;
72        }
73    }
74
75    println!("Single-threaded multi-key load ops/sec: {}", pretty_int(i));
76}
77
78fn load_ops_per_second_single_threaded_insert() {
79    let counter: HyperCounter<i32, AtomicI32> = HyperCounter::new();
80
81    let now = Instant::now();
82    let mut i = 0;
83
84    loop {
85        counter.fetch_add(i, 1, Ordering::Relaxed);
86        i += 1;
87
88        if now.elapsed().as_secs() >= 1 {
89            break;
90        }
91    }
92
93    println!("Single-threaded insert ops/sec: {}", pretty_int(i));
94}
95
96fn load_ops_per_second_single_threaded_remove() {
97    let counter: HyperCounter<i32, AtomicI32> = HyperCounter::new();
98
99    for i in 0..2_000_000 {
100        counter.fetch_add(i, 1, Ordering::Relaxed);
101    }
102
103    let now = Instant::now();
104    let mut i = 0;
105
106    loop {
107        counter.fetch_sub(i, 1, Ordering::Relaxed);
108        i += 1;
109
110        if now.elapsed().as_secs() >= 1 {
111            break;
112        }
113    }
114
115    println!("Single-threaded remove ops/sec: {}", pretty_int(i));
116}
117
118fn load_ops_per_second_single_threaded_churn() {
119    let counter: HyperCounter<i32, AtomicI32> = HyperCounter::new();
120
121    let now = Instant::now();
122    let mut i = 0;
123
124    loop {
125        if i % 2 == 0 {
126            counter.fetch_add(i, 1, Ordering::Relaxed);
127        } else {
128            counter.fetch_sub(i, 1, Ordering::Relaxed);
129        }
130
131        i += 1;
132
133        if now.elapsed().as_secs() >= 1 {
134            break;
135        }
136    }
137
138    println!("Single-threaded churn op/s: {}", pretty_int(i));
139}
140
141fn load_ops_per_second_multi_threaded_fetch_add_single_key() {
142    let counter: Arc<HyperCounter<i32, AtomicI32>> = Arc::new(HyperCounter::new());
143
144    let mut handles = vec![];
145
146    for _ in 0..THREADS {
147        let counter = counter.clone();
148
149        let handle = std::thread::spawn(move || {
150            let now = Instant::now();
151
152            loop {
153                counter.fetch_add(1, 1, Ordering::Relaxed);
154
155                if now.elapsed().as_secs() >= 1 {
156                    break;
157                }
158            }
159        });
160
161        handles.push(handle);
162    }
163
164    for handle in handles {
165        handle.join().unwrap();
166    }
167
168    let i = counter.load(&1, Ordering::Relaxed);
169
170    println!("Multi-threaded single-key load ops/sec: {}", pretty_int(i));
171}
172
173fn load_ops_per_second_multi_threaded_fetch_add_multi_key() {
174    let counter: Arc<HyperCounter<i32, AtomicI32>> = Arc::new(HyperCounter::new());
175
176    let mut handles = vec![];
177
178    for thread_id in 0..THREADS {
179        let counter = counter.clone();
180
181        let handle = std::thread::spawn(move || {
182            let now = Instant::now();
183
184            for i in 0.. {
185                let key = (i + thread_id) % 1000;
186                counter.fetch_add(key, 1, Ordering::Relaxed);
187
188                if now.elapsed().as_secs() >= 1 {
189                    break;
190                }
191            }
192        });
193
194        handles.push(handle);
195    }
196
197    for handle in handles {
198        handle.join().unwrap();
199    }
200
201    let mut i = 0;
202
203    for key in 0..1000 {
204        i += counter.load(&key, Ordering::Relaxed);
205    }
206
207    println!("Multi-threaded multi-key load ops/sec: {}", pretty_int(i));
208}
209
210fn load_ops_per_second_multi_threaded_insert() {
211    let counter: Arc<HyperCounter<i32, AtomicI32>> = Arc::new(HyperCounter::new());
212
213    let mut handles = vec![];
214
215    for thread_id in 0..THREADS {
216        let counter = counter.clone();
217
218        let handle = std::thread::spawn(move || {
219            let now = Instant::now();
220
221            for i in 0.. {
222                let key = i + thread_id * 1_000_000;
223                counter.fetch_add(key, 1, Ordering::Relaxed);
224
225                if now.elapsed().as_secs() >= 1 {
226                    break;
227                }
228            }
229        });
230
231        handles.push(handle);
232    }
233
234    for handle in handles {
235        handle.join().unwrap();
236    }
237
238    let i = counter.len();
239
240    println!("Multi-threaded insert ops/sec: {}", pretty_int(i as i32));
241}
242
243fn load_ops_per_second_multi_threaded_remove() {
244    let counter: Arc<HyperCounter<i32, AtomicI32>> = Arc::new(HyperCounter::new());
245
246    for i in 0..8_000_000 {
247        counter.fetch_add(i, 1, Ordering::Relaxed);
248    }
249
250    let mut handles = vec![];
251
252    for thread_id in 0..THREADS {
253        let counter = counter.clone();
254
255        let handle = std::thread::spawn(move || {
256            let now = Instant::now();
257
258            for i in 0.. {
259                let key = i + thread_id * 1_000_000;
260                counter.fetch_sub(key, 1, Ordering::Relaxed);
261
262                if now.elapsed().as_secs() >= 1 {
263                    break;
264                }
265            }
266        });
267
268        handles.push(handle);
269    }
270
271    for handle in handles {
272        handle.join().unwrap();
273    }
274
275    let i = counter.len();
276
277    println!(
278        "Multi-threaded remove ops/sec: {}",
279        pretty_int(8_000_000 - i as i32)
280    );
281}
282
283fn load_ops_per_second_multi_threaded_churn() {
284    let counter: Arc<HyperCounter<i32, AtomicI32>> = Arc::new(HyperCounter::new());
285
286    let mut handles = vec![];
287
288    for _ in 0..THREADS {
289        let counter = counter.clone();
290
291        let handle = std::thread::spawn(move || {
292            let now = Instant::now();
293            let mut i = 0;
294
295            loop {
296                if i % 2 == 0 {
297                    counter.fetch_add(1, 1, Ordering::Relaxed);
298                } else {
299                    counter.fetch_sub(1, 1, Ordering::Relaxed);
300                }
301
302                i += 1;
303
304                if now.elapsed().as_secs() >= 1 {
305                    break;
306                }
307            }
308
309            i
310        });
311
312        handles.push(handle);
313    }
314
315    let mut i = 0;
316
317    for handle in handles {
318        i += handle.join().unwrap();
319    }
320
321    println!("Multi-threaded churn op/s: {}", pretty_int(i));
322}