runtime_tracing/
lib.rs

1// allow it, because I am not sure we need it?
2// better to explicitly turn into the newtype types
3// but i might be wrong
4// also for now, allowing it to pass `cargo clippy`
5#![allow(clippy::from_over_into)]
6//! Runtime tracing structures and helpers for the CodeTracer debugger.
7//!
8//! This crate provides the [`Tracer`] type for emitting trace events and a
9//! collection of serializable structures describing the trace format.
10//! The format is documented in `docs/` and the README.
11mod abstract_trace_writer;
12mod base64;
13mod capnptrace;
14
15#[cfg(target_arch = "wasm32")]
16#[path = "./cbor_zstd_reader_wasm.rs"]
17mod cbor_zstd_reader;
18#[cfg(target_arch = "wasm32")]
19#[path = "./cbor_zstd_writer_wasm.rs"]
20mod cbor_zstd_writer;
21
22#[cfg(not(target_arch = "wasm32"))]
23mod cbor_zstd_reader;
24#[cfg(not(target_arch = "wasm32"))]
25mod cbor_zstd_writer;
26
27mod non_streaming_trace_writer;
28mod trace_readers;
29mod trace_writer;
30mod tracer;
31mod types;
32
33pub use crate::non_streaming_trace_writer::NonStreamingTraceWriter;
34pub use crate::trace_readers::TraceReader;
35pub use crate::trace_writer::TraceWriter;
36pub use crate::tracer::{NONE_TYPE_ID, NONE_VALUE, TraceEventsFileFormat, create_trace_reader, create_trace_writer};
37pub use crate::types::*;
38
39pub mod trace_capnp {
40    include!(concat!(env!("OUT_DIR"), "/src/trace_capnp.rs"));
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use std::path::Path;
47    // use std::path::PathBuf;
48
49    #[test]
50    fn test_simple_trace() {
51        let mut tracer = NonStreamingTraceWriter::new("path.small", &vec![]);
52        let path = Path::new("/test/path.small");
53        tracer.start(path, Line(1));
54        tracer.register_step(path, Line(1));
55        tracer.register_step(path, Line(2));
56        tracer.register_asm(&["asm0".to_string(), "asm1".to_string()]);
57        tracer.register_special_event(EventLogKind::Write, "test");
58        tracer.register_special_event(EventLogKind::Write, "test2");
59        tracer.register_special_event(EventLogKind::Error, "testError");
60
61        let function_path_id = tracer.ensure_path_id(&path);
62        let function_line = Line(3);
63        // -> function_id 1 after top level;
64        let function_id = tracer.ensure_function_id("function", &path, function_line);
65        assert!(function_id == FunctionId(1));
66
67        let before_temp_step = tracer.events.len();
68        tracer.register_step(path, function_line);
69        tracer.drop_last_step();
70        // drop last step: drops steps[-1]/variables[-]
71        assert_eq!(before_temp_step + 2, tracer.events.len());
72        assert!(matches!(tracer.events.last().unwrap(), TraceLowLevelEvent::DropLastStep));
73
74        let args = vec![tracer.arg("a", NONE_VALUE), tracer.arg("b", NONE_VALUE)];
75        tracer.register_call(function_id, args);
76        // => arg-related variable/value events; auto call-step event; potentially variables; call event
77
78        assert!(tracer.events.len() > 3);
79        // println!("{:#?}", tracer.events);
80        // -4, -3 should be variables
81        let should_be_step = &tracer.events[tracer.events.len() - 2];
82        let should_be_call = &tracer.events[tracer.events.len() - 1];
83        if let TraceLowLevelEvent::Step(StepRecord { path_id, line }) = should_be_step {
84            assert_eq!(*path_id, function_path_id);
85            assert_eq!(*line, function_line);
86        } else {
87            assert!(false, "expected a auto-registered step event before the last call one");
88        }
89        assert!(matches!(should_be_call, TraceLowLevelEvent::Call(CallRecord { .. })));
90
91        let int_value_1 = ValueRecord::Int {
92            i: 1,
93            type_id: tracer.ensure_type_id(TypeKind::Int, "Int"),
94        };
95        let int_value_2 = ValueRecord::Int {
96            i: 2,
97            type_id: tracer.ensure_type_id(TypeKind::Int, "Int"),
98        };
99        let int_value_3 = ValueRecord::Int {
100            i: 3,
101            type_id: tracer.ensure_type_id(TypeKind::Int, "Int"),
102        };
103
104        tracer.register_variable_with_full_value("test_variable", int_value_1.clone());
105
106        let not_supported_value = ValueRecord::Error {
107            msg: "not supported".to_string(),
108            type_id: NONE_TYPE_ID,
109        };
110        tracer.register_variable_with_full_value("test_variable2", not_supported_value);
111
112        tracer.register_cell_value(Place(0), int_value_1.clone());
113        let type_id = tracer.ensure_type_id(TypeKind::Seq, "Vector<Int>");
114        tracer.register_compound_value(
115            Place(1),
116            ValueRecord::Sequence {
117                elements: vec![ValueRecord::Cell { place: Place(0) }], // #0
118                is_slice: false,
119                type_id,
120            },
121        );
122        tracer.register_variable("test_variable3", Place(1));
123        tracer.assign_cell(Place(1), int_value_2.clone());
124        tracer.register_cell_value(Place(2), int_value_2.clone());
125        tracer.assign_compound_item(Place(0), 0, Place(2));
126
127        tracer.register_return(NONE_VALUE);
128        tracer.drop_variable("test_variable3");
129
130        // example of the history events
131        tracer.bind_variable("variable1", Place(1));
132        tracer.bind_variable("variable2", Place(2));
133        tracer.bind_variable("variable3", Place(3));
134
135        tracer.register_variable_with_full_value("variable1", int_value_1.clone());
136        tracer.register_variable_with_full_value("variable2", int_value_2.clone());
137        tracer.register_variable_with_full_value("variable3", int_value_3.clone());
138
139        // tracer.assign_simple("variable1", "variable2", PassBy::Value);
140        // tracer.assign_compound("variable1", &["variable2", "variable3"], PassBy::Value);
141
142        // more future-proof hopefully, if we add other kinds of RValue
143        let rvalue_1 = tracer.simple_rvalue("variable2");
144        tracer.assign("variable1", rvalue_1, PassBy::Value);
145        let rvalue_2 = tracer.compound_rvalue(&["variable2".to_string(), "variable3".to_string()]);
146        tracer.assign("variable1", rvalue_2, PassBy::Value);
147
148        // example for reference types
149        let reference_type = TypeRecord {
150            kind: TypeKind::Pointer,
151            lang_type: "MyReference<Int>".to_string(),
152            specific_info: TypeSpecificInfo::Pointer {
153                dereference_type_id: tracer.ensure_type_id(TypeKind::Int, "Int"),
154            },
155        };
156        let reference_type_id = tracer.ensure_raw_type_id(reference_type);
157        let _reference_value = ValueRecord::Reference {
158            dereferenced: Box::new(int_value_1.clone()),
159            address: 0,
160            mutable: false,
161            type_id: reference_type_id,
162        };
163
164        tracer.drop_variables(&["variable1".to_string(), "variable2".to_string(), "variable3".to_string()]);
165
166        assert_eq!(tracer.events.len(), 47);
167        // visible with
168        // cargo tets -- --nocapture
169        // println!("{:#?}", tracer.events);
170
171        // tracer.store_trace_metadata(&PathBuf::from("trace_metadata.json")).unwrap();
172        // tracer.store_trace_paths(&PathBuf::from("trace_paths.json")).unwrap();
173        // tracer.store_trace_events(&PathBuf::from("trace.json")).unwrap();
174    }
175
176    #[test]
177    fn test_equality_of_value_records() {
178        let a = ValueRecord::Int { i: 0, type_id: TypeId(0) }; // just an example type_id
179        let b = ValueRecord::Int { i: 0, type_id: TypeId(0) };
180        let different = ValueRecord::Int { i: 1, type_id: TypeId(0) };
181
182        assert_eq!(a, b);
183        assert_ne!(a, different);
184    }
185}