Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3f5b42c
feat(stream_api): introduced trait TraceWriter
nickysn Jul 11, 2025
7213328
feat(stream_api): added function create_trace_writer
nickysn Jul 11, 2025
aeb455f
feat(stream_api): added function begin_writing_trace_events() to the …
nickysn Jul 14, 2025
8721213
feat(stream_api): added field Tracer::format
nickysn Jul 14, 2025
93942a5
feat(stream_api): set format in create_trace_writer()
nickysn Jul 14, 2025
899d70e
feat(stream_api): added trait TraceReader
nickysn Jul 14, 2025
d6e7f0e
feat(stream_api): implemented trace readers for both the json and bin…
nickysn Jul 14, 2025
adf777a
feat(stream_api): added and implemented method TraceWriter::add_event()
nickysn Jul 14, 2025
79030a2
feat(stream_api): added and implemented method TraceWriter::append_ev…
nickysn Jul 14, 2025
fb48b0a
feat(stream_api): export create_trace_reader and create_trace_writer …
nickysn Jul 14, 2025
342c795
feat(stream_api): derive debug, clone and copy for the TraceEventsFil…
nickysn Jul 15, 2025
361b07c
feat(stream_api): use the new API in runtime_tracing_cli
nickysn Jul 15, 2025
40a9ac6
feat(stream_api): return Result in TraceWriter::begin_writing_trace_e…
nickysn Jul 15, 2025
9821197
feat(stream_api): store the path in begin_writing_trace_events
nickysn Jul 15, 2025
594c901
feat(stream_api): removed the format parameter from TraceWriter::stor…
nickysn Jul 15, 2025
ed68f58
feat(stream_api): removed the path parameter from TraceWriter::store_…
nickysn Jul 15, 2025
009d3dd
feat(stream_api): removed unused 'use'
nickysn Jul 15, 2025
7cdd9cd
feat(stream_api): store_trace_events() renamed finish_writing_trace_e…
nickysn Jul 15, 2025
100b5d7
feat(stream_api): update test test_binary_roundtrip to use the new API
nickysn Jul 15, 2025
3cde38a
feat(stream_api): the Tracer struct was renamed NonStreamingTraceWriter
nickysn Jul 15, 2025
b8cbbbe
feat(stream_api): added check and panic, when finish_writing_trace_ev…
nickysn Jul 15, 2025
6a21f95
feat(stream_api): introduced begin_writing_trace_metadata and begin_w…
nickysn Jul 15, 2025
9d8f046
feat(stream_api): method store_trace_metadata renamed finish_writing_…
nickysn Jul 15, 2025
775817a
feat(stream_api): method store_trace_paths renamed finish_writing_tra…
nickysn Jul 15, 2025
da7cff1
feat(stream_api): removed the parameter path from finish_writing_trac…
nickysn Jul 15, 2025
b1440f2
feat(stream_api): removed the parameter path from finish_writing_trac…
nickysn Jul 15, 2025
141001c
feat(stream_api): methods finish_writing_trace_* now take a mutable s…
nickysn Jul 15, 2025
64074a2
feat(stream_api): also reexport the TraceReader trait
nickysn Jul 15, 2025
4398822
chore: cargo fmt
nickysn Jul 15, 2025
edd7065
chore: bump runtime_tracing version to 0.13.0
nickysn Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion runtime_tracing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod tracer;
mod types;
mod base64;
mod capnptrace;
pub use crate::tracer::{Tracer, TraceEventsFileFormat, NONE_TYPE_ID, NONE_VALUE};
pub use crate::tracer::{Tracer, TraceWriter, TraceEventsFileFormat, NONE_TYPE_ID, NONE_VALUE};
pub use crate::types::*;

pub mod trace_capnp {
Expand Down
145 changes: 94 additions & 51 deletions runtime_tracing/src/tracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,48 @@ use crate::types::{
};
use crate::RValue;

pub trait TraceWriter {
fn start(&mut self, path: &Path, line: Line);
fn ensure_path_id(&mut self, path: &Path) -> PathId;
fn ensure_function_id(&mut self, function_name: &str, path: &Path, line: Line) -> FunctionId;
fn ensure_type_id(&mut self, kind: TypeKind, lang_type: &str) -> TypeId;
fn ensure_raw_type_id(&mut self, typ: TypeRecord) -> TypeId;
fn ensure_variable_id(&mut self, variable_name: &str) -> VariableId;
fn register_path(&mut self, path: &Path);
fn register_function(&mut self, name: &str, path: &Path, line: Line);
fn register_step(&mut self, path: &Path, line: Line);
fn register_call(&mut self, function_id: FunctionId, args: Vec<FullValueRecord>);
fn arg(&mut self, name: &str, value: ValueRecord) -> FullValueRecord;
fn register_return(&mut self, return_value: ValueRecord);
// TODO: add metadata arg
fn register_special_event(&mut self, kind: EventLogKind, content: &str);
fn to_raw_type(&self, kind: TypeKind, lang_type: &str) -> TypeRecord;
fn register_type(&mut self, kind: TypeKind, lang_type: &str);
fn register_raw_type(&mut self, typ: TypeRecord);
fn register_asm(&mut self, instructions: &[String]);
fn register_variable_with_full_value(&mut self, name: &str, value: ValueRecord);
fn register_variable_name(&mut self, variable_name: &str);
fn register_full_value(&mut self, variable_id: VariableId, value: ValueRecord);
fn register_compound_value(&mut self, place: Place, value: ValueRecord);
fn register_cell_value(&mut self, place: Place, value: ValueRecord);
fn assign_compound_item(&mut self, place: Place, index: usize, item_place: Place);
fn assign_cell(&mut self, place: Place, new_value: ValueRecord);
fn register_variable(&mut self, variable_name: &str, place: Place);
fn drop_variable(&mut self, variable_name: &str);
// history event helpers
fn assign(&mut self, variable_name: &str, rvalue: RValue, pass_by: PassBy);
fn bind_variable(&mut self, variable_name: &str, place: Place);
fn drop_variables(&mut self, variable_names: &[String]);
fn simple_rvalue(&mut self, variable_name: &str) -> RValue;
fn compound_rvalue(&mut self, variable_dependencies: &[String]) -> RValue;
fn drop_last_step(&mut self);

fn store_trace_metadata(&self, path: &Path) -> Result<(), Box<dyn Error>>;
fn store_trace_events(&self, path: &Path, format: TraceEventsFileFormat) -> Result<(), Box<dyn Error>>;
fn store_trace_paths(&self, path: &Path) -> Result<(), Box<dyn Error>>;
}


/// State machine used to record [`TraceLowLevelEvent`]s.
///
/// A `Tracer` instance accumulates events and can store them on disk via the
Expand Down Expand Up @@ -69,8 +111,25 @@ impl Tracer {
}
}

pub fn load_trace_events(&mut self, path: &Path, format: TraceEventsFileFormat) -> Result<(), Box<dyn Error>> {
match format {
TraceEventsFileFormat::Json => {
let json = std::fs::read_to_string(path)?;
self.events = serde_json::from_str(&json)?;
}
TraceEventsFileFormat::Binary => {
let file = fs::File::open(path)?;
let mut buf_reader = BufReader::new(file);
self.events = crate::capnptrace::read_trace(&mut buf_reader)?;
}
}
Ok(())
}
}

impl TraceWriter for Tracer {
/// Begin tracing of a program starting at the given source location.
pub fn start(&mut self, path: &Path, line: Line) {
fn start(&mut self, path: &Path, line: Line) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't realize i don't need to add pub for pub trait method implementations before: nice

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Actually, when implementing a trait, using 'pub' is not allowed and produces a compiler error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha, makes sense

let function_id = self.ensure_function_id("<toplevel>", path, line);
self.register_call(function_id, vec![]);
assert!(function_id == TOP_LEVEL_FUNCTION_ID);
Expand All @@ -84,15 +143,15 @@ impl Tracer {
assert!(NONE_TYPE_ID == self.ensure_type_id(TypeKind::None, "None"));
}

pub fn ensure_path_id(&mut self, path: &Path) -> PathId {
fn ensure_path_id(&mut self, path: &Path) -> PathId {
if !self.paths.contains_key(path) {
self.paths.insert(path.to_path_buf(), PathId(self.paths.len()));
self.register_path(path);
}
*self.paths.get(path).unwrap()
}

pub fn ensure_function_id(&mut self, function_name: &str, path: &Path, line: Line) -> FunctionId {
fn ensure_function_id(&mut self, function_name: &str, path: &Path, line: Line) -> FunctionId {
if !self.functions.contains_key(function_name) {
// same function names for different path line? TODO
self.functions.insert(function_name.to_string(), FunctionId(self.functions.len()));
Expand All @@ -101,33 +160,33 @@ impl Tracer {
*self.functions.get(function_name).unwrap()
}

pub fn ensure_type_id(&mut self, kind: TypeKind, lang_type: &str) -> TypeId {
fn ensure_type_id(&mut self, kind: TypeKind, lang_type: &str) -> TypeId {
let typ = self.to_raw_type(kind, lang_type);
self.ensure_raw_type_id(typ)
}

pub fn ensure_raw_type_id(&mut self, typ: TypeRecord) -> TypeId {
fn ensure_raw_type_id(&mut self, typ: TypeRecord) -> TypeId {
if !self.types.contains_key(&typ.lang_type) {
self.types.insert(typ.lang_type.clone(), TypeId(self.types.len()));
self.register_raw_type(typ.clone());
}
*self.types.get(&typ.lang_type).unwrap()
}

pub fn ensure_variable_id(&mut self, variable_name: &str) -> VariableId {
fn ensure_variable_id(&mut self, variable_name: &str) -> VariableId {
if !self.variables.contains_key(variable_name) {
self.variables.insert(variable_name.to_string(), VariableId(self.variables.len()));
self.register_variable_name(variable_name);
}
*self.variables.get(variable_name).unwrap()
}

pub fn register_path(&mut self, path: &Path) {
fn register_path(&mut self, path: &Path) {
self.path_list.push(path.to_path_buf());
self.events.push(TraceLowLevelEvent::Path(path.to_path_buf()));
}

pub fn register_function(&mut self, name: &str, path: &Path, line: Line) {
fn register_function(&mut self, name: &str, path: &Path, line: Line) {
let path_id = self.ensure_path_id(path);
self.function_list.push((name.to_string(), path_id, line));
self.events.push(TraceLowLevelEvent::Function(FunctionRecord {
Expand All @@ -137,12 +196,12 @@ impl Tracer {
}));
}

pub fn register_step(&mut self, path: &Path, line: Line) {
fn register_step(&mut self, path: &Path, line: Line) {
let path_id = self.ensure_path_id(path);
self.events.push(TraceLowLevelEvent::Step(StepRecord { path_id, line }));
}

pub fn register_call(&mut self, function_id: FunctionId, args: Vec<FullValueRecord>) {
fn register_call(&mut self, function_id: FunctionId, args: Vec<FullValueRecord>) {
// register a step for each call, the backend expects this for
// non-toplevel calls, so
// we ensure it directly from register_call
Expand All @@ -160,90 +219,89 @@ impl Tracer {
self.events.push(TraceLowLevelEvent::Call(CallRecord { function_id, args }));
}

pub fn arg(&mut self, name: &str, value: ValueRecord) -> FullValueRecord {
fn arg(&mut self, name: &str, value: ValueRecord) -> FullValueRecord {
let variable_id = self.ensure_variable_id(name);
FullValueRecord { variable_id, value }
}

pub fn register_return(&mut self, return_value: ValueRecord) {
fn register_return(&mut self, return_value: ValueRecord) {
self.events.push(TraceLowLevelEvent::Return(ReturnRecord { return_value }));
}

// TODO: add metadata arg
pub fn register_special_event(&mut self, kind: EventLogKind, content: &str) {
fn register_special_event(&mut self, kind: EventLogKind, content: &str) {
self.events.push(TraceLowLevelEvent::Event(RecordEvent {
kind,
metadata: "".to_string(),
content: content.to_string(),
}));
}

pub fn to_raw_type(&self, kind: TypeKind, lang_type: &str) -> TypeRecord {
fn to_raw_type(&self, kind: TypeKind, lang_type: &str) -> TypeRecord {
TypeRecord {
kind,
lang_type: lang_type.to_string(),
specific_info: TypeSpecificInfo::None,
}
}

pub fn register_type(&mut self, kind: TypeKind, lang_type: &str) {
fn register_type(&mut self, kind: TypeKind, lang_type: &str) {
let typ = self.to_raw_type(kind, lang_type);
self.events.push(TraceLowLevelEvent::Type(typ));
}

pub fn register_raw_type(&mut self, typ: TypeRecord) {
fn register_raw_type(&mut self, typ: TypeRecord) {
self.events.push(TraceLowLevelEvent::Type(typ));
}

pub fn register_asm(&mut self, instructions: &[String]) {
fn register_asm(&mut self, instructions: &[String]) {
self.events.push(TraceLowLevelEvent::Asm(instructions.to_vec()));
}

pub fn register_variable_with_full_value(&mut self, name: &str, value: ValueRecord) {
fn register_variable_with_full_value(&mut self, name: &str, value: ValueRecord) {
let variable_id = self.ensure_variable_id(name);
self.register_full_value(variable_id, value);
}

pub fn register_variable_name(&mut self, variable_name: &str) {
fn register_variable_name(&mut self, variable_name: &str) {
self.events.push(TraceLowLevelEvent::VariableName(variable_name.to_string()));
}

pub fn register_full_value(&mut self, variable_id: VariableId, value: ValueRecord) {
fn register_full_value(&mut self, variable_id: VariableId, value: ValueRecord) {
self.events.push(TraceLowLevelEvent::Value(FullValueRecord { variable_id, value }));
}

pub fn register_compound_value(&mut self, place: Place, value: ValueRecord) {
fn register_compound_value(&mut self, place: Place, value: ValueRecord) {
self.events.push(TraceLowLevelEvent::CompoundValue(CompoundValueRecord { place, value }));
}

pub fn register_cell_value(&mut self, place: Place, value: ValueRecord) {
fn register_cell_value(&mut self, place: Place, value: ValueRecord) {
self.events.push(TraceLowLevelEvent::CellValue(CellValueRecord { place, value }));
}

pub fn assign_compound_item(&mut self, place: Place, index: usize, item_place: Place) {
fn assign_compound_item(&mut self, place: Place, index: usize, item_place: Place) {
self.events.push(TraceLowLevelEvent::AssignCompoundItem(AssignCompoundItemRecord {
place,
index,
item_place,
}));
}
pub fn assign_cell(&mut self, place: Place, new_value: ValueRecord) {
fn assign_cell(&mut self, place: Place, new_value: ValueRecord) {
self.events.push(TraceLowLevelEvent::AssignCell(AssignCellRecord { place, new_value }));
}

pub fn register_variable(&mut self, variable_name: &str, place: Place) {
fn register_variable(&mut self, variable_name: &str, place: Place) {
let variable_id = self.ensure_variable_id(variable_name);
self.events
.push(TraceLowLevelEvent::VariableCell(VariableCellRecord { variable_id, place }));
}

pub fn drop_variable(&mut self, variable_name: &str) {
fn drop_variable(&mut self, variable_name: &str) {
let variable_id = self.ensure_variable_id(variable_name);
self.events.push(TraceLowLevelEvent::DropVariable(variable_id));
}

// history event helpers
pub fn assign(&mut self, variable_name: &str, rvalue: RValue, pass_by: PassBy) {
fn assign(&mut self, variable_name: &str, rvalue: RValue, pass_by: PassBy) {
let variable_id = self.ensure_variable_id(variable_name);
self.events.push(TraceLowLevelEvent::Assignment(AssignmentRecord {
to: variable_id,
Expand All @@ -252,13 +310,13 @@ impl Tracer {
}));
}

pub fn bind_variable(&mut self, variable_name: &str, place: Place) {
fn bind_variable(&mut self, variable_name: &str, place: Place) {
let variable_id = self.ensure_variable_id(variable_name);
self.events
.push(TraceLowLevelEvent::BindVariable(crate::BindVariableRecord { variable_id, place }));
}

pub fn drop_variables(&mut self, variable_names: &[String]) {
fn drop_variables(&mut self, variable_names: &[String]) {
let variable_ids: Vec<VariableId> = variable_names
.to_vec()
.iter()
Expand All @@ -267,12 +325,12 @@ impl Tracer {
self.events.push(TraceLowLevelEvent::DropVariables(variable_ids))
}

pub fn simple_rvalue(&mut self, variable_name: &str) -> RValue {
fn simple_rvalue(&mut self, variable_name: &str) -> RValue {
let variable_id = self.ensure_variable_id(variable_name);
RValue::Simple(variable_id)
}

pub fn compound_rvalue(&mut self, variable_dependencies: &[String]) -> RValue {
fn compound_rvalue(&mut self, variable_dependencies: &[String]) -> RValue {
let variable_ids: Vec<VariableId> = variable_dependencies
.to_vec()
.iter()
Expand All @@ -281,11 +339,11 @@ impl Tracer {
RValue::Compound(variable_ids)
}

pub fn drop_last_step(&mut self) {
fn drop_last_step(&mut self) {
self.events.push(TraceLowLevelEvent::DropLastStep);
}

pub fn store_trace_metadata(&self, path: &Path) -> Result<(), Box<dyn Error>> {
fn store_trace_metadata(&self, path: &Path) -> Result<(), Box<dyn Error>> {
let trace_metadata = TraceMetadata {
program: self.program.clone(),
args: self.args.clone(),
Expand All @@ -296,22 +354,7 @@ impl Tracer {
Ok(())
}

pub fn load_trace_events(&mut self, path: &Path, format: TraceEventsFileFormat) -> Result<(), Box<dyn Error>> {
match format {
TraceEventsFileFormat::Json => {
let json = std::fs::read_to_string(path)?;
self.events = serde_json::from_str(&json)?;
}
TraceEventsFileFormat::Binary => {
let file = fs::File::open(path)?;
let mut buf_reader = BufReader::new(file);
self.events = crate::capnptrace::read_trace(&mut buf_reader)?;
}
}
Ok(())
}

pub fn store_trace_events(&self, path: &Path, format: TraceEventsFileFormat) -> Result<(), Box<dyn Error>> {
fn store_trace_events(&self, path: &Path, format: TraceEventsFileFormat) -> Result<(), Box<dyn Error>> {
match format {
TraceEventsFileFormat::Json => {
let json = serde_json::to_string(&self.events)?;
Expand All @@ -325,7 +368,7 @@ impl Tracer {
Ok(())
}

pub fn store_trace_paths(&self, path: &Path) -> Result<(), Box<dyn Error>> {
fn store_trace_paths(&self, path: &Path) -> Result<(), Box<dyn Error>> {
let json = serde_json::to_string(&self.path_list)?;
fs::write(path, json)?;
Ok(())
Expand Down
3 changes: 1 addition & 2 deletions runtime_tracing_cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::path::Path;

use clap::{Args, Parser, Subcommand};
use runtime_tracing::{TraceEventsFileFormat, Tracer};

use runtime_tracing::{TraceEventsFileFormat, Tracer, TraceWriter};
use crate::fmt_trace_cmd::FmtTraceCommand;
mod fmt_trace_cmd;

Expand Down