stak_profiler/
stack_profiler.rs

1use crate::{COLUMN_SEPARATOR, FRAME_SEPARATOR, ProcedureOperation};
2use stak_vm::{Cons, Memory, Profiler, StackSlot};
3use std::{io::Write, time::Instant};
4
5/// A stack profiler.
6pub struct StackProfiler<T: Write> {
7    writer: T,
8    start_time: Instant,
9}
10
11impl<T: Write> StackProfiler<T> {
12    /// Creates a stack profiler.
13    pub fn new(writer: T) -> Self {
14        Self {
15            writer,
16            start_time: Instant::now(),
17        }
18    }
19
20    fn write_column_separator(&mut self) {
21        write!(self.writer, "{COLUMN_SEPARATOR}").unwrap();
22    }
23
24    fn write_frame_separator(&mut self) {
25        write!(self.writer, "{FRAME_SEPARATOR}").unwrap();
26    }
27
28    fn write_time(&mut self) {
29        writeln!(
30            &mut self.writer,
31            "{}",
32            Instant::now().duration_since(self.start_time).as_nanos()
33        )
34        .unwrap();
35    }
36
37    fn write_procedure(&mut self, memory: &Memory, code: Cons) {
38        let operand = memory.car(code);
39
40        if let Some(symbol) = operand.to_cons() {
41            let mut string = memory.cdr_value(memory.cdr(symbol)).assume_cons();
42
43            while string != memory.null() {
44                write!(
45                    self.writer,
46                    "{}",
47                    char::from_u32(memory.car(string).assume_number().to_i64() as _).unwrap_or('�')
48                )
49                .unwrap();
50                string = memory.cdr(string).assume_cons();
51            }
52        }
53    }
54
55    fn write_stack(&mut self, memory: &Memory) {
56        let mut stack = memory.stack();
57        let mut first = true;
58
59        while stack != memory.null() {
60            stack = if memory.cdr(stack).tag() == StackSlot::Frame as _ {
61                if !first {
62                    self.write_frame_separator();
63                }
64
65                first = false;
66
67                self.write_procedure(memory, memory.car_value(memory.car(stack)).assume_cons());
68
69                memory.cdr_value(memory.car(stack)).assume_cons()
70            } else {
71                memory.cdr(stack).assume_cons()
72            };
73        }
74    }
75}
76
77impl<T: Write> Profiler for StackProfiler<T> {
78    fn profile_call(&mut self, memory: &Memory, call_code: Cons, r#return: bool) {
79        write!(
80            self.writer,
81            "{}",
82            if r#return {
83                ProcedureOperation::ReturnCall
84            } else {
85                ProcedureOperation::Call
86            }
87        )
88        .unwrap();
89        self.write_column_separator();
90        self.write_procedure(memory, call_code);
91        self.write_frame_separator();
92        self.write_stack(memory);
93        self.write_column_separator();
94        self.write_time();
95    }
96
97    fn profile_return(&mut self, memory: &Memory) {
98        write!(self.writer, "{}", ProcedureOperation::Return).unwrap();
99        self.write_column_separator();
100        self.write_stack(memory);
101        self.write_column_separator();
102        self.write_time();
103    }
104
105    fn profile_event(&mut self, name: &str) {
106        write!(self.writer, "{name}").unwrap();
107        self.write_column_separator();
108        self.write_time();
109    }
110}