use crate::pool::Pool;
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::time::Instant;
const CAPACITY: usize = 1 << 14;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Kind {
Enter = 1,
SectionBegin,
SectionEnd,
ParkEnter,
ParkExit,
LentBegin,
LentEnd,
Leave,
Publish,
}
impl Kind {
fn from_u64(v: u64) -> Option<Kind> {
Some(match v {
1 => Kind::Enter,
2 => Kind::SectionBegin,
3 => Kind::SectionEnd,
4 => Kind::ParkEnter,
5 => Kind::ParkExit,
6 => Kind::LentBegin,
7 => Kind::LentEnd,
8 => Kind::Leave,
9 => Kind::Publish,
_ => return None,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Event {
pub member: usize,
pub ns: u64,
pub kind: Kind,
}
struct Ring {
head: AtomicUsize,
buf: Box<[AtomicU64]>,
}
impl Ring {
fn new() -> Self {
Ring {
head: AtomicUsize::new(0),
buf: (0..CAPACITY).map(|_| AtomicU64::new(0)).collect(),
}
}
}
pub(crate) struct Trace {
base: Instant,
rings: Box<[Ring]>,
}
impl Trace {
pub(crate) fn new(width: usize) -> Self {
Trace {
base: Instant::now(),
rings: (0..=width).map(|_| Ring::new()).collect(),
}
}
pub(crate) fn record(&self, id: Option<usize>, kind: Kind) {
let ring = &self.rings[id.unwrap_or(self.rings.len() - 1)];
let ns = u64::try_from(self.base.elapsed().as_nanos()).unwrap_or(u64::MAX >> 4);
let i = ring.head.fetch_add(1, Ordering::Relaxed) % CAPACITY;
ring.buf[i].store((ns << 4) | kind as u64, Ordering::Relaxed);
}
fn events(&self) -> Vec<Event> {
let mut out = Vec::new();
for (r, ring) in self.rings.iter().enumerate() {
let head = ring.head.load(Ordering::Relaxed);
let member = if r + 1 == self.rings.len() {
usize::MAX
} else {
r
};
let (from, to) = (head.saturating_sub(CAPACITY), head);
for k in from..to {
let v = ring.buf[k % CAPACITY].load(Ordering::Relaxed);
if let Some(kind) = Kind::from_u64(v & 0xF) {
out.push(Event {
member,
ns: v >> 4,
kind,
});
}
}
}
out.sort_by_key(|e| e.ns);
out
}
fn clear(&self) {
for ring in self.rings.iter() {
ring.head.store(0, Ordering::Relaxed);
}
}
pub(crate) fn now_ns(&self) -> u64 {
u64::try_from(self.base.elapsed().as_nanos()).unwrap_or(u64::MAX >> 4)
}
}
pub fn events(pool: &Pool) -> Vec<Event> {
pool.awake.trace.events()
}
pub fn clear(pool: &Pool) {
pool.awake.trace.clear();
}
pub fn now_ns(pool: &Pool) -> u64 {
pool.awake.trace.now_ns()
}