device-driver-core 2.0.0

Internal compiler crate for the device-driver toolkit
Documentation
use std::time::Duration;

use annotate_snippets::{Group, Level};
use device_driver_common::instant::Instant;
use device_driver_diagnostics::Diagnostic;
use device_driver_mir::PassTiming;

use crate::TimingsMode;

#[derive(Debug)]
pub struct Timings {
    mode: TimingsMode,
    lexer: Duration,
    parser: Duration,
    mir: Duration,
    mir_passes: Vec<PassTiming>,
    lir: Duration,
    codegen: Duration,
}

impl Timings {
    pub const fn new(mode: TimingsMode) -> Self {
        Self {
            mode,
            lexer: Duration::ZERO,
            parser: Duration::ZERO,
            mir: Duration::ZERO,
            mir_passes: Vec::new(),
            lir: Duration::ZERO,
            codegen: Duration::ZERO,
        }
    }

    pub fn start_lexer(&mut self) -> Timer<'_> {
        Timer::new(&mut self.lexer)
    }
    pub fn start_parser(&mut self) -> Timer<'_> {
        Timer::new(&mut self.parser)
    }
    pub fn start_mir(&mut self) -> Timer<'_> {
        Timer::new(&mut self.mir)
    }
    pub fn start_lir(&mut self) -> Timer<'_> {
        Timer::new(&mut self.lir)
    }
    pub fn start_codegen(&mut self) -> Timer<'_> {
        Timer::new(&mut self.codegen)
    }

    pub fn set_mir_timings(&mut self, mir_timings: Vec<PassTiming>) {
        if matches!(self.mode, TimingsMode::Verbose) {
            self.mir_passes = mir_timings;
        }
    }
}

impl Diagnostic for Timings {
    fn is_error(&self) -> bool {
        false
    }

    fn as_report<'a>(&'a self, _source: &'a str, _path: &'a str) -> Vec<Group<'a>> {
        [Level::INFO
            .primary_title("timings")
            .element(
                Level::INFO
                    .with_name(Some("lexer"))
                    .message(format!("  {:>8.3}ms", self.lexer.as_secs_f64() * 1000.0)),
            )
            .element(
                Level::INFO
                    .with_name(Some("parser"))
                    .message(format!(" {:>8.3}ms", self.parser.as_secs_f64() * 1000.0)),
            )
            .element(
                Level::INFO
                    .with_name(Some("mir"))
                    .message(format!("    {:>8.3}ms", self.mir.as_secs_f64() * 1000.0)),
            )
            .elements(self.mir_passes.iter().map(|pass| {
                Level::INFO.no_name().message(format!(
                    "- {}: {:0.3}ms",
                    pass.name.split("::").last().unwrap(),
                    pass.duration.as_secs_f64() * 1000.0
                ))
            }))
            .element(
                Level::INFO
                    .with_name(Some("lir"))
                    .message(format!("    {:>8.3}ms", self.lir.as_secs_f64() * 1000.0)),
            )
            .element(
                Level::INFO
                    .with_name(Some("codegen"))
                    .message(format!("{:>8.3}ms", self.codegen.as_secs_f64() * 1000.0)),
            )]
        .to_vec()
    }
}

pub struct Timer<'a> {
    start: Instant,
    result: &'a mut Duration,
}

impl<'a> Timer<'a> {
    pub fn new(result: &'a mut Duration) -> Self {
        Self {
            start: Instant::now(),
            result,
        }
    }
}

impl Drop for Timer<'_> {
    fn drop(&mut self) {
        *self.result = self.start.elapsed();
    }
}