HyperCounter

Struct HyperCounter 

Source
pub struct HyperCounter<K, V, H = DefaultHasher>
where K: Eq + Hash, V: AtomicNumber, H: Hasher + Default,
{ /* private fields */ }

Implementations§

Source§

impl<K, V, H> HyperCounter<K, V, H>
where K: Eq + Hash, V: AtomicNumber, H: Hasher + Default,

Source

pub fn new() -> Self

Creates a new, empty HyperCounter.

Returns:

Examples found in repository?
examples/bench.rs (line 42)
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}
Source

pub fn len(&self) -> usize

Returns the current amount of occupied entries in the HyperCounter.

Returns:

  • usize - The current length.
Examples found in repository?
examples/bench.rs (line 238)
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}
Source

pub fn is_empty(&self) -> bool

Checks if the HyperCounter is empty.

Returns:

  • true - if the HyperCounter is empty.
  • false - otherwise.
Source

pub fn capacity(&self) -> usize

Returns the current capacity of the HyperCounter.

Returns:

  • usize - The current capacity.
Source

pub fn load(&self, key: &K, ordering: Ordering) -> V::Primitive

Atomically loads the value for the given key.

Arguments:

  • key - The key to load.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The current value associated with the key, or zero if the key is missing.
Examples found in repository?
examples/bench.rs (line 168)
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}
Source

pub fn swap( &self, key: K, new_value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically swaps the value for the given key.

If the new value is zero, the entry is removed.

If the key is missing, a new entry is created with the new value.

Arguments:

  • key - The key to swap.
  • new_value - The new value to set.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before swap)
Source

pub fn fetch_add( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically adds a value to the counter for the given key.

If the key ends up being zero after addition, the entry is removed.

If the key is missing, a new entry is created with the given value.

Arguments:

  • key - The key to add to.
  • value - The value to add.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before addition)
Examples found in repository?
examples/bench.rs (line 48)
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}
Source

pub fn fetch_sub( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically subtracts a value from the counter for the given key.

If the key ends up being zero after subtraction, the entry is removed.

If the key is missing, a new entry is created with zero - the given value.

Arguments:

  • key - The key to subtract from.
  • value - The value to subtract.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before subtraction)
Examples found in repository?
examples/bench.rs (line 107)
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}
Source

pub fn fetch_and( &self, key: &K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically performs a bitwise AND operation on the counter for the given key.

If the key is missing, nothing is done and zero is returned.

Arguments:

  • key - The key to perform the AND operation on.
  • value - The value to AND with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before AND operation)
Source

pub fn fetch_nand( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically performs a bitwise NAND operation on the counter for the given key.

If the key is missing, the new value is inserted and all bits set (i.e., !0) is returned.

Arguments:

  • key - The key to perform the NAND operation on.
  • value - The value to NAND with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before NAND operation)
Source

pub fn fetch_or( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically performs a bitwise OR operation on the counter for the given key.

If the key is missing, the new value is inserted and zero is returned.

Arguments:

  • key - The key to perform the OR operation on.
  • value - The value to OR with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before OR operation)
Source

pub fn fetch_xor( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically performs a bitwise XOR operation on the counter for the given key.

If the key is missing, the new value is inserted and zero is returned.

If the resulting value is zero after the XOR operation, the entry is removed.

Arguments:

  • key - The key to perform the XOR operation on.
  • value - The value to XOR with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before XOR operation)
Source

pub fn fetch_max( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically sets the counter for the given key to the maximum of its current value and the given value.

If the key is missing and the value is higher than zero, the new value is inserted and zero is returned. Otherwise, nothing is done and zero is returned.

Arguments:

  • key - The key to perform the max operation on.
  • value - The value to compare with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before max operation)
Source

pub fn fetch_min( &self, key: K, value: V::Primitive, ordering: Ordering, ) -> V::Primitive

Atomically sets the counter for the given key to the minimum of its current value and the given value.

If the key is missing and the value is lower than zero, the new value is inserted and zero is returned. Otherwise, nothing is done and zero is returned.

Arguments:

  • key - The key to perform the min operation on.
  • value - The value to compare with.
  • ordering - The memory ordering to use.

Returns:

  • [V::Primitive] - The previous value associated with the key. (before min operation)

Trait Implementations§

Source§

impl<K, V> Default for HyperCounter<K, V>
where K: Eq + Hash, V: AtomicNumber,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K, V, H = DefaultHasher> !Freeze for HyperCounter<K, V, H>

§

impl<K, V, H> RefUnwindSafe for HyperCounter<K, V, H>

§

impl<K, V, H> Send for HyperCounter<K, V, H>
where H: Send, K: Sync + Send, V: Sync + Send,

§

impl<K, V, H> Sync for HyperCounter<K, V, H>
where H: Sync, K: Sync + Send, V: Sync + Send,

§

impl<K, V, H> Unpin for HyperCounter<K, V, H>
where H: Unpin,

§

impl<K, V, H> UnwindSafe for HyperCounter<K, V, H>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.