pub use metrics::*;
#[cfg(feature = "profiler")]
pub use with_profiler::*;
#[cfg(not(feature = "profiler"))]
pub use without_profiler::*;
use crate::{network::Coord, scheduler::BlockId};
#[cfg(feature = "profiler")]
mod backend;
mod metrics;
pub trait Profiler {
fn items_in(&mut self, from: Coord, to: Coord, amount: usize);
fn items_out(&mut self, from: Coord, to: Coord, amount: usize);
fn net_bytes_in(&mut self, from: Coord, to: Coord, amount: usize);
fn net_bytes_out(&mut self, from: Coord, to: Coord, amount: usize);
fn iteration_boundary(&mut self, leader_block_id: BlockId);
}
#[cfg(feature = "profiler")]
mod with_profiler {
use std::cell::UnsafeCell;
use std::sync::Mutex;
use std::time::Instant;
use crate::channel::{UnboundedReceiver, UnboundedSender};
use crate::profiler::backend::ProfilerBackend;
use crate::profiler::metrics::ProfilerResult;
static CHANNEL: Lazy<Mutex<(Option<ProfilerSender>, Option<ProfilerReceiver>)>> =
Lazy::new(|| {
let (sender, receiver) = ProfilerReceiver::new();
Mutex::new((Some(sender), Some(receiver)))
});
static START_TIME: Lazy<Instant> = Lazy::new(|| Instant::now());
thread_local! {
static PROFILER: UnsafeCell<ProfilerBackend> = UnsafeCell::new(ProfilerBackend::new(*START_TIME));
}
type ProfilerSender = UnboundedChannelSender<ProfilerResult>;
type ProfilerReceiver = UnboundedChannelReceiver<ProfilerResult>;
pub(crate) fn get_sender() -> ProfilerSender {
let channels = CHANNEL.lock().unwrap();
channels.0.clone().expect("Profiler sender already dropped")
}
pub fn get_profiler() -> &'static mut ProfilerBackend {
PROFILER.with(|t| unsafe { &mut *t.get() })
}
pub fn wait_profiler() -> Vec<ProfilerResult> {
let mut channels = CHANNEL.lock().unwrap();
let profiler_receiver = channels.1.take().expect("Profiler receiver already taken");
channels.0.take().expect("Profiler sender already dropped");
let mut results = vec![];
while let Ok(profiler_res) = profiler_receiver.recv() {
results.push(profiler_res);
}
let (sender, receiver) = ProfilerReceiver::new();
channels.0 = Some(sender);
channels.1 = Some(receiver);
results
}
}
#[cfg(not(feature = "profiler"))]
mod without_profiler {
use crate::network::Coord;
use crate::profiler::*;
static mut PROFILER: NoOpProfiler = NoOpProfiler;
#[derive(Debug, Clone, Copy, Default)]
pub struct NoOpProfiler;
impl Profiler for NoOpProfiler {
#[inline(always)]
fn items_in(&mut self, _from: Coord, _to: Coord, _amount: usize) {}
#[inline(always)]
fn items_out(&mut self, _from: Coord, _to: Coord, _amount: usize) {}
#[inline(always)]
fn net_bytes_in(&mut self, _from: Coord, _to: Coord, _amount: usize) {}
#[inline(always)]
fn net_bytes_out(&mut self, _from: Coord, _to: Coord, _amount: usize) {}
#[inline(always)]
fn iteration_boundary(&mut self, _leader_block_id: BlockId) {}
}
pub fn get_profiler() -> &'static mut NoOpProfiler {
unsafe { &mut PROFILER }
}
pub fn wait_profiler() -> Vec<ProfilerResult> {
Default::default()
}
}