Skip to main content

midenc_session/
statistics.rs

1use std::{
2    fmt,
3    sync::atomic::{AtomicU64, Ordering},
4    time::{Duration, Instant},
5};
6
7use crate::HumanDuration;
8
9const NOT_STARTED: u64 = u64::MAX;
10
11/// This struct contains various statistics about a compilation session
12pub struct Statistics {
13    /// The time at which the compiler session started
14    start_time: Instant,
15    /// The elapsed time at which parsing started
16    ///
17    /// Parsing here refers to one of two things:
18    ///
19    /// 1. Loading of a Wasm module into memory and converting it to HIR
20    /// 2. Parsing of an HIR module into memory
21    parse_time: AtomicU64,
22    /// The elapsed time at which optimizations/rewrites started
23    opt_time: AtomicU64,
24    /// The elapsed time at which codegen started
25    codegen_time: AtomicU64,
26}
27impl fmt::Debug for Statistics {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_struct("Statistics")
30            .field("elapsed", &self.elapsed())
31            .field("parsing", &self.parse_time())
32            .field("optimization", &self.opt_time())
33            .field("codegen", &self.codegen_time())
34            .finish()
35    }
36}
37impl Default for Statistics {
38    fn default() -> Statistics {
39        Self::new(Instant::now())
40    }
41}
42impl Clone for Statistics {
43    fn clone(&self) -> Self {
44        Self {
45            start_time: self.start_time,
46            parse_time: AtomicU64::new(self.parse_time.load(Ordering::Relaxed)),
47            opt_time: AtomicU64::new(self.opt_time.load(Ordering::Relaxed)),
48            codegen_time: AtomicU64::new(self.codegen_time.load(Ordering::Relaxed)),
49        }
50    }
51}
52impl Statistics {
53    pub fn new(start_time: Instant) -> Self {
54        Self {
55            start_time,
56            parse_time: AtomicU64::new(NOT_STARTED),
57            opt_time: AtomicU64::new(NOT_STARTED),
58            codegen_time: AtomicU64::new(NOT_STARTED),
59        }
60    }
61
62    /// Get the duration since the compiler session started
63    pub fn elapsed(&self) -> HumanDuration {
64        HumanDuration::since(self.start_time)
65    }
66
67    /// Get the time spent parsing/loading inputs, if applicable
68    pub fn parse_time(&self) -> Option<HumanDuration> {
69        load_duration(&self.parse_time)
70    }
71
72    /// Get the time spent optimizing the IR, if applicable
73    pub fn opt_time(&self) -> Option<HumanDuration> {
74        load_duration(&self.opt_time)
75    }
76
77    /// Get the time spent generating Miden Assembly, if applicable
78    pub fn codegen_time(&self) -> Option<HumanDuration> {
79        load_duration(&self.codegen_time)
80    }
81
82    /// Record that parsing/loading inputs has completed
83    pub fn parsing_completed(&self) {
84        store_duration(&self.parse_time, self.elapsed())
85    }
86
87    /// Record that optimization of the IR has completed
88    pub fn optimization_completed(&self) {
89        store_duration(&self.opt_time, self.elapsed())
90    }
91
92    /// Record that codegen of Miden Assembly has completed
93    pub fn codegen_completed(&self) {
94        store_duration(&self.codegen_time, self.elapsed())
95    }
96}
97
98fn store_duration(raw_secs_f64: &AtomicU64, duration: HumanDuration) {
99    let bits = duration.as_secs_f64().to_bits();
100    raw_secs_f64.store(bits, Ordering::Relaxed)
101}
102
103fn load_duration(raw_secs_f64: &AtomicU64) -> Option<HumanDuration> {
104    match raw_secs_f64.load(Ordering::Relaxed) {
105        NOT_STARTED => None,
106        bits => Some(Duration::from_secs_f64(f64::from_bits(bits)).into()),
107    }
108}