use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
pub struct InstrumentedWindow {
pub index: usize,
pub start_time_ns: u64,
pub events: InstrumentedEventBuffer,
pub summary: InstrumentedWindowSummary,
pub dequeue_summary: InstrumentedWindowSummary,
}
impl InstrumentedWindow {
pub fn new() -> Self {
Self {
index: 0,
start_time_ns: 0,
events: InstrumentedEventBuffer::new(128),
summary: InstrumentedWindowSummary::new(16),
dequeue_summary: InstrumentedWindowSummary::new(16),
}
}
pub fn reinitialize(&mut self, index: usize, start_time_ns: u64, num_message_types: usize) {
self.index = index;
self.start_time_ns = start_time_ns;
self.events.clear();
self.summary.resize(num_message_types);
}
}
pub struct InstrumentedWindowSummary {
pub time_by_message_type: Vec<AggregatedMessageTypeStats>,
pub unknown_total: AggregatedMessageTypeStats,
}
impl InstrumentedWindowSummary {
pub fn new(initial_capacity: usize) -> Self {
Self {
time_by_message_type: (0..initial_capacity)
.map(|_| AggregatedMessageTypeStats::default())
.collect(),
unknown_total: AggregatedMessageTypeStats::default(),
}
}
pub fn resize(&mut self, num_message_types: usize) {
self.time_by_message_type.resize_with(num_message_types, Default::default);
self.time_by_message_type
.resize_with(self.time_by_message_type.capacity(), Default::default);
}
pub fn add_message_time(&self, window_index: usize, message_type_id: u32, time_ns: u64) {
if let Some(stats) = self.time_by_message_type.get(message_type_id as usize) {
stats.add(window_index, time_ns);
} else {
self.unknown_total.add(window_index, time_ns);
}
}
}
#[derive(Default)]
pub struct AggregatedMessageTypeStats {
pub window_index: AtomicUsize,
pub count: AtomicUsize,
pub total_time_ns: AtomicU64,
}
impl AggregatedMessageTypeStats {
pub fn add(&self, window_index: usize, time_ns: u64) {
let current_window_index = self.window_index.load(Ordering::Relaxed);
let (current_count, current_time) = if current_window_index == window_index {
(self.count.load(Ordering::Relaxed), self.total_time_ns.load(Ordering::Relaxed))
} else {
(0, 0)
};
self.count.store(current_count + 1, Ordering::Relaxed);
self.total_time_ns.store(current_time + time_ns, Ordering::Relaxed);
if current_window_index != window_index {
self.window_index.store(window_index, Ordering::Release);
}
}
}
pub struct InstrumentedEventBuffer {
pub buffer: Vec<InstrumentedEvent>,
pub len: AtomicUsize,
}
impl InstrumentedEventBuffer {
pub fn new(capacity: usize) -> Self {
Self {
buffer: (0..capacity).map(|_| InstrumentedEvent::default()).collect(),
len: AtomicUsize::new(0),
}
}
pub fn push(&self, encoded_event: u64, relative_timestamp_ns: u64) {
let len = self.len.load(std::sync::atomic::Ordering::Relaxed);
if len < self.buffer.len() {
let event = &self.buffer[len];
event.event.store(encoded_event, Ordering::Relaxed);
event.relative_timestamp_ns.store(relative_timestamp_ns, Ordering::Relaxed);
}
self.len.store(len + 1, Ordering::Release);
}
fn clear(&self) {
self.len.store(0, std::sync::atomic::Ordering::Relaxed);
}
}
#[derive(Default)]
pub struct InstrumentedEvent {
pub event: AtomicU64,
pub relative_timestamp_ns: AtomicU64,
}