stak_profiler/
stack_profiler.rs1use crate::{COLUMN_SEPARATOR, FRAME_SEPARATOR, ProcedureOperation};
2use stak_vm::{Cons, 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(&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}