Skip to content

Commit

Permalink
[ci skip][skip ci][skip netlify] -bors-staging-tmp-2
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] committed Jan 21, 2021
2 parents 34f09d5 + 0b5621d commit 3144975
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 122 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.features": ["enable", "print_at_exit"]
}
60 changes: 59 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "countme"
description = "Counts the number of live instances of types"
version = "1.0.3"
version = "2.0.0-pre.1"
license = "MIT OR Apache-2.0"
repository = "https://github.com/matklad/countme"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
Expand All @@ -12,5 +12,15 @@ exclude = [".github/", "bors.toml", "rustfmt.toml"]
[workspace]
members = ["xtask"]

[[example]]
name = "print_at_exit"
required-features = ["print_at_exit"]

[dependencies]
dashmap = { version = "4", optional = true }
once_cell = { version = "1.5", optional = true }
rustc-hash = { version = "1.1", optional = true }

[features]
no-op = []
enable = [ "dashmap", "once_cell", "rustc-hash" ]
print_at_exit = ["enable"]
13 changes: 4 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@ A library to quickly get the live/total/max counts of allocated instances.
```rust
#[derive(Default)]
struct Widget {
_t: countme::Token<Self>,
}

impl countme::CountMe for Widget {
fn store() -> &'static countme::Store {
static S: countme::Store = countme::Store::new();
&S
}
_c: countme::Count<Self>,
}

let w1 = Widget::default();
Expand All @@ -20,6 +13,8 @@ drop(w1);

let counts = countme::get::<Widget>();
assert_eq!(counts.live, 2);
assert_eq!(counts.max, 3);
assert_eq!(counts.max_live, 3);
assert_eq!(counts.total, 3);

eprintln!("{}", countme::get_all());
```
11 changes: 11 additions & 0 deletions examples/print_at_exit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[derive(Default)]
struct Widget {
_t: countme::Count<Self>,
}

fn main() {
let w1 = Widget::default();
let _w2 = Widget::default();
drop(w1);
let _w3 = Widget::default();
}
114 changes: 114 additions & 0 deletions src/imp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::{
any::type_name,
hash::BuildHasherDefault,
os::raw::c_int,
sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed},
};

use dashmap::DashMap;
use once_cell::sync::OnceCell;
use rustc_hash::FxHasher;

use crate::{AllCounts, Counts};

static ENABLE: AtomicBool = AtomicBool::new(true);

type GlobalStore = DashMap<&'static str, Store, BuildHasherDefault<FxHasher>>;

#[inline]
fn global_store() -> &'static GlobalStore {
static MAP: OnceCell<GlobalStore> = OnceCell::new();
MAP.get_or_init(|| {
if cfg!(feature = "print_at_exit") {
extern "C" {
fn atexit(f: extern "C" fn()) -> c_int;
}
extern "C" fn print_at_exit() {
eprint!("{}", get_all());
}
unsafe {
atexit(print_at_exit);
}
}

GlobalStore::default()
})
}

pub(crate) fn enable(yes: bool) {
ENABLE.store(yes, Relaxed);
}

#[inline]
fn enabled() -> bool {
ENABLE.load(Relaxed)
}

#[inline]
pub(crate) fn dec<T>() {
if enabled() {
do_dec(type_name::<T>())
}
}
#[inline(never)]
fn do_dec(key: &'static str) {
global_store().entry(&key).or_default().value().dec();
}

#[inline]
pub(crate) fn inc<T>() {
if enabled() {
do_inc(type_name::<T>())
}
}
#[inline(never)]
fn do_inc(key: &'static str) {
global_store().entry(&key).or_default().value().inc();
}

pub(crate) fn get<T>() -> Counts {
do_get(type_name::<T>())
}
fn do_get(key: &'static str) -> Counts {
global_store().entry(&key).or_default().value().read()
}

pub(crate) fn get_all() -> AllCounts {
let entries = global_store().iter().map(|entry| (*entry.key(), entry.value().read())).collect();
AllCounts { entries }
}

#[derive(Default)]
struct Store {
total: AtomicUsize,
max_live: AtomicUsize,
live: AtomicUsize,
}

impl Store {
fn inc(&self) {
self.total.fetch_add(1, Relaxed);
let live = self.live.fetch_add(1, Relaxed) + 1;

let mut max = 0;
loop {
max = match self.max_live.compare_exchange_weak(max, live, Relaxed, Relaxed) {
Err(max) if max < live => max,
Err(_) | Ok(_) => break,
};
}
}

fn dec(&self) -> bool {
let live = self.live.fetch_sub(1, Relaxed) - 1;
live == 0
}

fn read(&self) -> Counts {
Counts {
total: self.total.load(Relaxed),
max_live: self.max_live.load(Relaxed),
live: self.live.load(Relaxed),
}
}
}
Loading

0 comments on commit 3144975

Please sign in to comment.