Skip to main content

runmat_vm/interpreter/
timing.rs

1#[cfg(not(target_arch = "wasm32"))]
2use runmat_time::Instant;
3
4#[cfg(not(target_arch = "wasm32"))]
5pub struct InterpreterTiming {
6    enabled: bool,
7    host_span_start: Option<(Instant, usize)>,
8    host_span_last_pc: Option<usize>,
9    host_span_instrs: u64,
10    seq: u64,
11}
12
13#[cfg(not(target_arch = "wasm32"))]
14impl InterpreterTiming {
15    pub fn new() -> Self {
16        let enabled = std::env::var("RUNMAT_INTERPRETER_TIMING")
17            .map(|v| v == "1" || v.eq_ignore_ascii_case("true") || v.eq_ignore_ascii_case("yes"))
18            .unwrap_or(false);
19        Self {
20            enabled,
21            host_span_start: None,
22            host_span_last_pc: None,
23            host_span_instrs: 0,
24            seq: 0,
25        }
26    }
27
28    pub fn note_host_instr(&mut self, pc: usize) {
29        if !self.enabled {
30            return;
31        }
32        if self.host_span_start.is_none() {
33            self.host_span_start = Some((Instant::now(), pc));
34            self.host_span_instrs = 0;
35        }
36        self.host_span_instrs += 1;
37        self.host_span_last_pc = Some(pc);
38    }
39
40    pub fn flush_host_span(&mut self, reason: &str, detail: Option<&str>) {
41        if !self.enabled {
42            return;
43        }
44        let Some((start, start_pc)) = self.host_span_start.take() else {
45            return;
46        };
47        let duration = start.elapsed();
48        let end_pc = self.host_span_last_pc.unwrap_or(start_pc);
49        let instrs = self.host_span_instrs.max(1);
50        if let Some(extra) = detail {
51            log::debug!(
52                "interpreter_host_span seq={} reason={} detail={} pc_span=[{}..{}] instrs={} duration_ns={}",
53                self.seq,
54                reason,
55                extra,
56                start_pc,
57                end_pc,
58                instrs,
59                duration.as_nanos()
60            );
61        } else {
62            log::debug!(
63                "interpreter_host_span seq={} reason={} pc_span=[{}..{}] instrs={} duration_ns={}",
64                self.seq,
65                reason,
66                start_pc,
67                end_pc,
68                instrs,
69                duration.as_nanos()
70            );
71        }
72        self.seq += 1;
73        self.host_span_last_pc = None;
74        self.host_span_instrs = 0;
75    }
76}
77
78#[cfg(not(target_arch = "wasm32"))]
79impl Default for InterpreterTiming {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85#[cfg(not(target_arch = "wasm32"))]
86impl Drop for InterpreterTiming {
87    fn drop(&mut self) {
88        self.flush_host_span("drop", None);
89    }
90}
91
92#[cfg(target_arch = "wasm32")]
93pub struct InterpreterTiming;
94
95#[cfg(target_arch = "wasm32")]
96impl InterpreterTiming {
97    pub fn new() -> Self {
98        Self
99    }
100
101    pub fn note_host_instr(&mut self, _pc: usize) {}
102
103    pub fn flush_host_span(&mut self, _reason: &str, _detail: Option<&str>) {}
104}
105
106#[cfg(target_arch = "wasm32")]
107impl Default for InterpreterTiming {
108    fn default() -> Self {
109        Self::new()
110    }
111}
112
113#[cfg(target_arch = "wasm32")]
114impl Drop for InterpreterTiming {
115    fn drop(&mut self) {}
116}