use vize_l0::profiler::{SpanAttribution, global_profiler};
use super::{FailEvent, PassEvent, PassObserver, Pipeline};
#[derive(Debug)]
pub struct TimingObserver {
key: &'static str,
open: Option<WalkSpan>,
pub recorded_walks: u32,
}
#[derive(Debug)]
struct WalkSpan {
timer: vize_l0::profiler::Timer,
attribution: SpanAttribution,
}
impl Default for TimingObserver {
fn default() -> Self {
Self::new()
}
}
impl TimingObserver {
pub const WALK_KEY: &'static str = "davinci.pass.walk";
#[must_use]
pub const fn new() -> Self {
Self::with_key(Self::WALK_KEY)
}
#[must_use]
pub const fn with_key(key: &'static str) -> Self {
Self {
key,
open: None,
recorded_walks: 0,
}
}
fn attribution(event: &PassEvent<'_>) -> SpanAttribution {
SpanAttribution::new()
.with_stage(event.pipeline.stage)
.with_pass((event.pipeline.passes.get(event.group.start)).map_or("", |pass| pass.name))
}
}
impl PassObserver for TimingObserver {
fn before_pipeline(&mut self, _pipeline: &Pipeline) {
self.open = None;
}
fn before_pass(&mut self, event: &PassEvent<'_>) {
if !event.is_group_entry() {
return;
}
let profiler = global_profiler();
if let Some(timer) = profiler.timer(self.key) {
self.open = Some(WalkSpan {
timer,
attribution: Self::attribution(event),
});
}
}
fn after_pass(&mut self, event: &PassEvent<'_>) {
if !event.is_group_exit() {
return;
}
if let Some(span) = self.open.take() {
let elapsed = span.timer.stop();
global_profiler().record_attributed(self.key, span.attribution, elapsed);
self.recorded_walks += 1;
}
}
fn on_fail(&mut self, _event: &FailEvent<'_>) {
self.open = None;
}
}