miden_debug_engine/profiling/instrument/
mod.rs1use alloc::{boxed::Box, string::String};
7
8use miden_core::operations::Operation;
9
10mod op_histogram_global;
11mod op_histogram_proc;
12
13pub use op_histogram_global::OpHistogramGlobal;
14pub use op_histogram_proc::OpHistogramProc;
15
16pub trait Instrument {
18 fn name(&self) -> &'static str;
22 fn on_operation_execution_cycle(&mut self, op: Operation, proc: Option<&str>);
28 fn write_report_to(&self, writer: &mut dyn OutputWriter) -> OutputResult<()>;
30}
31
32pub type OutputError = Box<dyn core::error::Error + 'static>;
33pub type OutputResult<T> = Result<T, OutputError>;
34
35pub trait OutputWriter {
36 fn write_all(&mut self, buf: &[u8]) -> OutputResult<()>;
37 fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()>;
38}
39
40#[cfg(feature = "std")]
41impl<T: std::io::Write> OutputWriter for T {
42 #[inline]
43 fn write_all(&mut self, buf: &[u8]) -> OutputResult<()> {
44 std::io::Write::write_all(self, buf).map_err(|err| Box::new(err) as Box<_>)
45 }
46
47 #[inline]
48 fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()> {
49 std::io::Write::write_fmt(self, args).map_err(|err| Box::new(err) as Box<_>)
50 }
51}
52
53#[cfg(not(feature = "std"))]
54impl OutputWriter for alloc::vec::Vec<u8> {
55 fn write_all(&mut self, buf: &[u8]) -> OutputResult<()> {
56 self.extend_from_slice(buf);
57 Ok(())
58 }
59
60 fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()> {
61 use alloc::string::ToString;
62 let formatted = args.to_string();
63 self.extend_from_slice(formatted.as_bytes());
64 Ok(())
65 }
66}
67
68pub trait InstrumentRegistration: Sized + Instrument + 'static {
70 const NAME: &'static str;
72
73 fn build(config: &super::ProfilerConfig) -> Result<Self, InstrumentError>;
75}
76
77#[derive(Debug, thiserror::Error)]
78pub enum InstrumentError {
79 #[error("unknown profiling instrument '{0}'")]
81 Undefined(String),
82 #[error("failed to construct instrument '{name}': {reason}")]
84 Build { name: String, reason: String },
85}
86
87#[cfg(feature = "std")]
92pub fn instrument_from_name(
93 name: &str,
94 config: &super::ProfilerConfig,
95) -> Result<Box<dyn Instrument>, InstrumentError> {
96 use alloc::string::ToString;
97
98 for instrument in inventory::iter::<InstrumentRegistrationInfo>() {
99 if instrument.name == name {
100 return (instrument.builder)(config);
101 }
102 }
103 Err(InstrumentError::Undefined(name.to_string()))
104}
105
106#[cfg(feature = "std")]
107#[doc(hidden)]
108pub struct InstrumentRegistrationInfo {
109 name: &'static str,
110 builder: fn(&super::ProfilerConfig) -> Result<Box<dyn Instrument>, InstrumentError>,
111}
112
113#[cfg(feature = "std")]
114impl InstrumentRegistrationInfo {
115 pub const fn new<T: InstrumentRegistration>() -> Self {
116 let name = <T as InstrumentRegistration>::NAME;
117 Self {
118 name,
119 builder: build_instrument::<T>,
120 }
121 }
122}
123
124#[cfg(feature = "std")]
125#[macro_export]
126macro_rules! register_instrument {
127 ($t:ty) => {
128 inventory::submit!($crate::profiling::instrument::InstrumentRegistrationInfo::new::<$t>());
129 };
130}
131
132#[cfg(feature = "std")]
133inventory::collect!(InstrumentRegistrationInfo);
134
135#[cfg(feature = "std")]
136#[inline]
137fn build_instrument<T: InstrumentRegistration>(
138 config: &super::ProfilerConfig,
139) -> Result<Box<dyn Instrument>, InstrumentError> {
140 <T as InstrumentRegistration>::build(config).map(|inst| Box::new(inst) as Box<dyn Instrument>)
141}