use super::exec_graph::ExecutionNode;
use super::profiling::{cached_nanos_or_now, cpu_cycles};
#[derive(Debug, Clone)]
pub struct AsyncTaskProfiler {
pub name: String,
pub poll_count: u64,
pub yield_count: u64,
pub total_poll_ns: u64,
last_poll_start: u64,
last_poll_cycles: u64,
pub total_poll_cycles: u64,
}
impl AsyncTaskProfiler {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
poll_count: 0,
yield_count: 0,
total_poll_ns: 0,
last_poll_start: 0,
last_poll_cycles: 0,
total_poll_cycles: 0,
}
}
#[inline]
pub fn on_poll_start(&mut self) {
self.poll_count += 1;
self.last_poll_start = cached_nanos_or_now();
self.last_poll_cycles = cpu_cycles();
}
#[inline]
pub fn on_poll_end(&mut self, is_ready: bool) {
let now = cached_nanos_or_now();
let cycles = cpu_cycles();
self.total_poll_ns += now.saturating_sub(self.last_poll_start);
self.total_poll_cycles += cycles.saturating_sub(self.last_poll_cycles);
if !is_ready {
self.yield_count += 1;
}
}
#[must_use]
pub fn efficiency(&self) -> f64 {
if self.poll_count == 0 {
0.0
} else {
1.0 / self.poll_count as f64
}
}
#[must_use]
pub fn avg_poll_us(&self) -> f64 {
if self.poll_count == 0 {
0.0
} else {
self.total_poll_ns as f64 / self.poll_count as f64 / 1000.0
}
}
#[must_use]
pub fn yield_ratio(&self) -> f64 {
if self.poll_count == 0 {
0.0
} else {
self.yield_count as f64 / self.poll_count as f64
}
}
pub fn to_execution_node(&self) -> ExecutionNode {
ExecutionNode::AsyncTask {
name: self.name.clone(),
poll_count: self.poll_count,
yield_count: self.yield_count,
total_poll_ns: self.total_poll_ns,
}
}
}
impl Default for AsyncTaskProfiler {
fn default() -> Self {
Self::new("unnamed")
}
}