use crate::{
perftools::profiler::PROFILER,
runtime::types::demi_callback_t,
};
use ::std::{
cell::RefCell,
fmt::{
self,
Debug,
},
future::Future,
io,
pin::Pin,
rc::Rc,
task::{
Context,
Poll,
},
thread,
};
pub struct Scope {
name: &'static str,
pred: Option<Rc<RefCell<Scope>>>,
succs: Vec<Rc<RefCell<Scope>>>,
perf_callback: Option<demi_callback_t>,
num_calls: usize,
duration_sum: u64,
}
pub struct Guard {
enter_time: u64,
}
pub struct AsyncScope<'a, F: Future> {
scope: Rc<RefCell<Scope>>,
future: Pin<&'a mut F>,
}
impl Scope {
pub fn new(name: &'static str, pred: Option<Rc<RefCell<Scope>>>, perf_callback: Option<demi_callback_t>) -> Scope {
Scope {
name,
pred,
succs: Vec::new(),
num_calls: 0,
duration_sum: 0,
perf_callback,
}
}
pub fn get_name(&self) -> &'static str {
self.name
}
pub fn get_pred(&self) -> &Option<Rc<RefCell<Scope>>> {
&self.pred
}
pub fn get_succs(&self) -> &Vec<Rc<RefCell<Scope>>> {
&self.succs
}
pub fn add_succ(&mut self, succ: Rc<RefCell<Scope>>) {
self.succs.push(succ.clone())
}
#[cfg(test)]
pub fn get_num_calls(&self) -> usize {
self.num_calls
}
pub fn get_duration_sum(&self) -> u64 {
self.duration_sum
}
#[inline]
pub fn enter(&mut self) -> Guard {
Guard::enter()
}
#[inline]
pub fn leave(&mut self, duration: u64) {
if let Some(callback) = self.perf_callback {
callback(self.name.as_ptr() as *const i8, self.name.len() as u32, duration);
} else {
self.num_calls += 1;
self.duration_sum = self.duration_sum + duration;
}
}
pub fn write_recursive<W: io::Write>(
&self,
out: &mut W,
thread_id: thread::ThreadId,
total_duration: u64,
depth: usize,
max_depth: Option<usize>,
ns_per_cycle: f64,
) -> io::Result<()> {
if let Some(d) = max_depth {
if depth > d {
return Ok(());
}
}
let total_duration_secs = (total_duration) as f64;
let duration_sum_secs = (self.duration_sum) as f64;
let pred_sum_secs = self
.pred
.clone()
.map_or(total_duration_secs, |pred| (pred.borrow().duration_sum) as f64);
let percent_time = duration_sum_secs / pred_sum_secs * 100.0;
let mut markers = String::from("+");
for _ in 0..depth {
markers.push('+');
}
writeln!(
out,
"{},{},{},{},{}",
format!("{},{:?},{}", markers, thread_id, self.name),
self.num_calls,
percent_time,
duration_sum_secs / (self.num_calls as f64),
duration_sum_secs / (self.num_calls as f64) * ns_per_cycle,
)?;
for succ in &self.succs {
succ.borrow()
.write_recursive(out, thread_id, total_duration, depth + 1, max_depth, ns_per_cycle)?;
}
Ok(())
}
}
impl<'a, F: Future> AsyncScope<'a, F> {
pub fn new(scope: Rc<RefCell<Scope>>, future: Pin<&'a mut F>) -> Self {
Self { scope, future }
}
}
impl Guard {
#[inline]
pub fn enter() -> Self {
let (now, _): (u64, u32) = unsafe { x86::time::rdtscp() };
Self { enter_time: now }
}
}
impl Debug for Scope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl<'a, F: Future> Future for AsyncScope<'a, F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let self_: &mut Self = self.get_mut();
let _guard = PROFILER.with(|p| p.borrow_mut().enter_scope(self_.scope.clone()));
Future::poll(self_.future.as_mut(), ctx)
}
}
impl Drop for Guard {
#[inline]
fn drop(&mut self) {
let (now, _): (u64, u32) = unsafe { x86::time::rdtscp() };
let duration: u64 = now - self.enter_time;
PROFILER.with(|p| p.borrow_mut().leave_scope(duration));
}
}