mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 00:45:18 +03:00
metrics: crate for collecting metrics
Summary: We start off simple here. Python only really has counters so we only implement counters. There are a lot of options on how to improve this and things get slightly complicated when we look at the how ecosystem and fb303. Anyway, simple start. Reviewed By: quark-zju Differential Revision: D23577874 fbshipit-source-id: d50f5b2ba302d900b254200308bff7446121ae1d
This commit is contained in:
parent
ead17552cf
commit
7f72a04c0e
8
eden/scm/lib/hg-metrics/Cargo.toml
Normal file
8
eden/scm/lib/hg-metrics/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "hg-metrics"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.4"
|
||||
parking_lot = "0.10.2"
|
113
eden/scm/lib/hg-metrics/src/lib.rs
Normal file
113
eden/scm/lib/hg-metrics/src/lib.rs
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
pub fn increment_counter(key: impl Key, value: usize) {
|
||||
METRICS.increment_counter(key, value)
|
||||
}
|
||||
|
||||
pub fn summarize() -> Vec<(String, usize)> {
|
||||
METRICS.summarize()
|
||||
}
|
||||
|
||||
pub trait Key: Into<String> + Borrow<str> {}
|
||||
impl<T> Key for T where T: Into<String> + Borrow<str> {}
|
||||
|
||||
pub static METRICS: Lazy<Metrics> = Lazy::new(Metrics::new);
|
||||
|
||||
pub struct Metrics {
|
||||
counters: RwLock<HashMap<String, AtomicUsize>>,
|
||||
}
|
||||
|
||||
impl Metrics {
|
||||
fn new() -> Self {
|
||||
let counters = RwLock::new(HashMap::new());
|
||||
|
||||
Self { counters }
|
||||
}
|
||||
|
||||
fn increment_counter(&self, key: impl Key, value: usize) {
|
||||
{
|
||||
let counters = self.counters.read();
|
||||
if let Some(counter) = counters.get(key.borrow()) {
|
||||
// We could use Relaxed ordering but it makes tests awkward if we were to run on a
|
||||
// weakly ordered system, (stress) tests are nice for this code.
|
||||
counter.fetch_add(value, Ordering::Release);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let mut counters = self.counters.write();
|
||||
counters
|
||||
.entry(key.into())
|
||||
.and_modify(|c| {
|
||||
c.fetch_add(value, Ordering::Release);
|
||||
})
|
||||
.or_insert_with(|| AtomicUsize::new(value));
|
||||
}
|
||||
|
||||
fn summarize(&self) -> Vec<(String, usize)> {
|
||||
let counters = self.counters.read();
|
||||
let mut summary: Vec<(String, usize)> = counters
|
||||
.iter()
|
||||
.map(|(k, v)| (k.into(), v.load(Ordering::Acquire)))
|
||||
.collect();
|
||||
summary.sort();
|
||||
summary
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::thread;
|
||||
|
||||
#[test]
|
||||
fn test_increment_string_key() {
|
||||
let metrics = Metrics::new();
|
||||
metrics.increment_counter(String::from("hello"), 2);
|
||||
metrics.increment_counter(String::from("world"), 3);
|
||||
metrics.increment_counter(String::from("hello"), 4);
|
||||
assert_eq!(
|
||||
metrics.summarize(),
|
||||
vec![(String::from("hello"), 6), (String::from("world"), 3)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increment_str_key() {
|
||||
let metrics = Metrics::new();
|
||||
metrics.increment_counter("hello", 2);
|
||||
metrics.increment_counter("world", 3);
|
||||
metrics.increment_counter("hello", 4);
|
||||
assert_eq!(
|
||||
metrics.summarize(),
|
||||
vec![(String::from("hello"), 6), (String::from("world"), 3)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increment_on_many_threads() {
|
||||
static MY_METRICS: Lazy<Metrics> = Lazy::new(Metrics::new);
|
||||
let handle = thread::spawn(move || {
|
||||
for _i in 0..10000 {
|
||||
MY_METRICS.increment_counter("key", 2);
|
||||
}
|
||||
});
|
||||
for _i in 0..10000 {
|
||||
MY_METRICS.increment_counter("key", 3);
|
||||
}
|
||||
handle.join().expect("waiting for spawned thread");
|
||||
assert_eq!(MY_METRICS.summarize(), vec![(String::from("key"), 50000)]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user