1use std::time;
5use std::thread;
6use std::sync::{Arc, Mutex};
7use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
8
9use lazy_static;
10use fnv::FnvHashMap;
11use parking_lot::RwLock;
12use crossbeam_queue::ArrayQueue;
13
14use atom::Atom;
15
16const MIN_DYNAMIC_COUNTER_CAPACITY: usize = 10;
20
21const DEFAULT_DYNAMIC_COUNTER_CAPACITY: usize = 1000000;
25
26const MIN_STATIC_COUNTER_CAPACITY: usize = 1;
30
31const DEFAULT_STATIC_COUNTER_CAPACITY: usize = 1000;
35
36lazy_static! {
40 pub static ref GLOBAL_PREF_COLLECT: PrefCollect = PrefCollect::new(DEFAULT_DYNAMIC_COUNTER_CAPACITY, DEFAULT_STATIC_COUNTER_CAPACITY);
41}
42
43pub fn check_counter(name: &str, cid: u64) -> bool {
47 Atom::from(name).str_hash() as u64 == cid
48}
49
50#[derive(Debug, Clone)]
54pub struct PrefCounter(Arc<AtomicUsize>);
55
56unsafe impl Send for PrefCounter {}
57unsafe impl Sync for PrefCounter {}
58
59impl PrefCounter {
60 pub fn get(&self) -> usize {
62 self.0.load(Ordering::SeqCst)
63 }
64
65 pub fn set(&self, count: usize) {
67 self.0.store(count, Ordering::SeqCst);
68 }
69
70 pub fn sum(&self, count: usize) {
72 self.0.fetch_add(count, Ordering::Relaxed);
73 }
74}
75
76type StartTime = time::Instant;
80
81#[derive(Debug, Clone)]
85pub struct PrefTimer(Arc<AtomicUsize>);
86
87unsafe impl Send for PrefTimer {}
88unsafe impl Sync for PrefTimer {}
89
90impl PrefTimer {
91 pub fn get(&self) -> usize {
93 self.0.load(Ordering::Relaxed)
94 }
95
96 pub fn start(&self) -> StartTime {
98 StartTime::now()
99 }
100
101 pub fn timing(&self, start: StartTime) {
103 self.0.fetch_add((StartTime::now() - start).as_micros() as usize, Ordering::Relaxed);
104 }
105}
106
107pub struct DynamicIterator {
111 inner: Arc<InnerCollect>,
112 cache: Vec<(u64, Arc<AtomicUsize>)>,
113}
114
115impl Drop for DynamicIterator {
116 fn drop(&mut self) {
117 for _ in 0..self.cache.len() {
118 self.inner.dynamic_collect.push(self.cache.remove(0));
120 }
121 }
122}
123
124impl Iterator for DynamicIterator {
125 type Item = (u64, Arc<AtomicUsize>);
126
127 fn next(&mut self) -> Option<Self::Item> {
128 if let Ok(counter) = self.inner.dynamic_collect.pop() {
129 if Arc::strong_count(&(counter.1)) == 2 {
130 self.inner.dynamic_table.write().remove(&(counter.0));
132 return Some(counter);
133 }
134
135 let r = Some((counter.0, counter.1.clone()));
137 self.cache.push(counter);
138 return r;
139 }
140
141 None
142 }
143}
144
145pub struct StaticIterator {
149 inner: Arc<InnerCollect>,
150 cache: Vec<(u64, Arc<AtomicUsize>)>,
151}
152
153impl Drop for StaticIterator {
154 fn drop(&mut self) {
155 for _ in 0..self.cache.len() {
156 self.inner.static_collect.push(self.cache.remove(0));
158 }
159 }
160}
161
162impl Iterator for StaticIterator {
163 type Item = (u64, Arc<AtomicUsize>);
164
165 fn next(&mut self) -> Option<Self::Item> {
166 if let Ok(counter) = self.inner.static_collect.pop() {
167 let r = Some((counter.0, counter.1.clone()));
168 self.cache.push(counter);
169 return r;
170 }
171
172 None
173 }
174}
175
176#[derive(Clone)]
180pub struct PrefCollect(Arc<InnerCollect>);
181
182unsafe impl Send for PrefCollect {}
183unsafe impl Sync for PrefCollect {}
184
185struct InnerCollect {
186 dynamic_table: RwLock<FnvHashMap<u64, Arc<AtomicUsize>>>, dynamic_collect: ArrayQueue<(u64, Arc<AtomicUsize>)>, static_init: AtomicBool, static_collect: ArrayQueue<(u64, Arc<AtomicUsize>)>, }
191
192impl PrefCollect {
193 pub fn new(dynamic_capacity: usize, static_capacity: usize) -> Self {
195 if dynamic_capacity < MIN_DYNAMIC_COUNTER_CAPACITY {
196 panic!("invalid dynamic capacity");
197 }
198 if static_capacity < MIN_STATIC_COUNTER_CAPACITY {
199 panic!("invalid static capacity");
200 }
201
202 PrefCollect(Arc::new(InnerCollect {
203 dynamic_table: RwLock::new(FnvHashMap::default()),
204 dynamic_collect: ArrayQueue::new(dynamic_capacity),
205 static_init: AtomicBool::new(false),
206 static_collect: ArrayQueue::new(static_capacity),
207 }))
208 }
209
210 pub fn dynamic_is_full(&self) -> bool {
212 self.0.dynamic_collect.is_full()
213 }
214
215 pub fn dynamic_size(&self) -> usize {
217 self.0.dynamic_collect.len()
218 }
219
220 pub fn new_dynamic_counter(&self, target: Atom, init: usize) -> Option<PrefCounter> {
222 if self.0.dynamic_collect.is_full() {
223 return None;
225 }
226
227 let cid = target.str_hash();
228 if let Some(counter) = self.0.dynamic_table.read().get(&(cid as u64)) {
229 return Some(PrefCounter(counter.clone()));
231 }
232
233 let counter = Arc::new(AtomicUsize::new(init));
235 self.0.dynamic_collect.push((cid as u64, counter.clone()));
236 self.0.dynamic_table.write().insert(cid as u64, counter.clone());
237 Some(PrefCounter(counter))
238 }
239
240 pub fn new_dynamic_timer(&self, target: Atom, init: usize) -> Option<PrefTimer> {
242 if self.0.dynamic_collect.is_full() {
243 return None;
245 }
246
247 let cid = target.str_hash();
248 if let Some(counter) = self.0.dynamic_table.read().get(&(cid as u64)) {
249 return Some(PrefTimer(counter.clone()));
251 }
252
253 let counter = Arc::new(AtomicUsize::new(init));
255 self.0.dynamic_collect.push((cid as u64, counter.clone()));
256 self.0.dynamic_table.write().insert(cid as u64, counter.clone());
257 Some(PrefTimer(counter))
258 }
259
260 pub fn dynamic_iter(&self) -> DynamicIterator {
262 DynamicIterator {
263 inner: self.0.clone(),
264 cache: Vec::with_capacity(self.0.dynamic_collect.len()),
265 }
266 }
267
268 pub fn static_is_full(&self) -> bool {
270 self.0.static_collect.is_full()
271 }
272
273 pub fn static_size(&self) -> usize {
275 self.0.static_collect.len()
276 }
277
278 pub fn new_static_counter(&self, target: Atom, init: usize) -> Option<PrefCounter> {
280 if self.0.static_init.load(Ordering::SeqCst) {
281 return None;
283 }
284
285 let cid = target.str_hash();
286 let counter = Arc::new(AtomicUsize::new(init));
287 self.0.static_collect.push((cid as u64, counter.clone()));
288 Some(PrefCounter(counter))
289 }
290
291 pub fn new_static_timer(&self, target: Atom, init: usize) -> Option<PrefTimer> {
293 if self.0.static_init.load(Ordering::SeqCst) {
294 return None;
296 }
297
298 let cid = target.str_hash();
299 let counter = Arc::new(AtomicUsize::new(init));
300 self.0.static_collect.push((cid as u64, counter.clone()));
301 Some(PrefTimer(counter))
302 }
303
304 pub fn static_init_ok(&self) -> usize {
306 self.0.static_init.compare_and_swap(false, true, Ordering::SeqCst);
307 self.0.static_collect.len()
308 }
309
310 pub fn static_iter(&self) -> StaticIterator {
312 StaticIterator {
313 inner: self.0.clone(),
314 cache: Vec::with_capacity(self.0.static_collect.len()),
315 }
316 }
317}