stak_profiler/
stack_profiler.rs1use crate::{COLUMN_SEPARATOR, FRAME_SEPARATOR, ProcedureOperation};
2use stak_vm::{Cons, Error, Heap, Memory, Profiler, StackSlot};
3use std::{io::Write, time::Instant};
4
5pub struct StackProfiler<T: Write> {
7 writer: T,
8 start_time: Instant,
9}
10
11impl<T: Write> StackProfiler<T> {
12 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<H: Heap>(&mut self, memory: &Memory<H>, code: Cons) -> Result<(), Error> {
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 _)
48 .unwrap_or('�')
49 )
50 .unwrap();
51 string = memory.cdr(string)?.assume_cons();
52 }
53 }
54
55 Ok(())
56 }
57
58 fn write_stack<H: Heap>(&mut self, memory: &Memory<H>) -> Result<(), Error> {
59 let mut stack = memory.stack();
60 let mut first = true;
61
62 while stack != memory.null()? {
63 stack = if memory.cdr(stack)?.tag() == StackSlot::Frame as _ {
64 if !first {
65 self.write_frame_separator();
66 }
67
68 first = false;
69
70 self.write_procedure(memory, memory.car_value(memory.car(stack)?)?.assume_cons())?;
71
72 memory.cdr_value(memory.car(stack)?)?.assume_cons()
73 } else {
74 memory.cdr(stack)?.assume_cons()
75 };
76 }
77
78 Ok(())
79 }
80}
81
82impl<T: Write, H: Heap> Profiler<H> for StackProfiler<T> {
83 fn profile_call(
84 &mut self,
85 memory: &Memory<H>,
86 call_code: Cons,
87 r#return: bool,
88 ) -> Result<(), Error> {
89 write!(
90 self.writer,
91 "{}",
92 if r#return {
93 ProcedureOperation::ReturnCall
94 } else {
95 ProcedureOperation::Call
96 }
97 )
98 .unwrap();
99 self.write_column_separator();
100 self.write_procedure(memory, call_code)?;
101 self.write_frame_separator();
102 self.write_stack(memory)?;
103 self.write_column_separator();
104 self.write_time();
105
106 Ok(())
107 }
108
109 fn profile_return(&mut self, memory: &Memory<H>) -> Result<(), Error> {
110 write!(self.writer, "{}", ProcedureOperation::Return).unwrap();
111 self.write_column_separator();
112 self.write_stack(memory)?;
113 self.write_column_separator();
114 self.write_time();
115
116 Ok(())
117 }
118
119 fn profile_event(&mut self, name: &str) -> Result<(), Error> {
120 write!(self.writer, "{name}").unwrap();
121 self.write_column_separator();
122 self.write_time();
123
124 Ok(())
125 }
126}