use alloc::{boxed::Box, string::String};
use miden_core::operations::Operation;
mod op_histogram_global;
mod op_histogram_proc;
pub use op_histogram_global::OpHistogramGlobal;
pub use op_histogram_proc::OpHistogramProc;
pub trait Instrument {
fn name(&self) -> &'static str;
fn on_operation_execution_cycle(&mut self, op: Operation, proc: Option<&str>);
fn write_report_to(&self, writer: &mut dyn OutputWriter) -> OutputResult<()>;
}
pub type OutputError = Box<dyn core::error::Error + 'static>;
pub type OutputResult<T> = Result<T, OutputError>;
pub trait OutputWriter {
fn write_all(&mut self, buf: &[u8]) -> OutputResult<()>;
fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()>;
}
#[cfg(feature = "std")]
impl<T: std::io::Write> OutputWriter for T {
#[inline]
fn write_all(&mut self, buf: &[u8]) -> OutputResult<()> {
std::io::Write::write_all(self, buf).map_err(|err| Box::new(err) as Box<_>)
}
#[inline]
fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()> {
std::io::Write::write_fmt(self, args).map_err(|err| Box::new(err) as Box<_>)
}
}
#[cfg(not(feature = "std"))]
impl OutputWriter for alloc::vec::Vec<u8> {
fn write_all(&mut self, buf: &[u8]) -> OutputResult<()> {
self.extend_from_slice(buf);
Ok(())
}
fn write_fmt(&mut self, args: core::fmt::Arguments<'_>) -> OutputResult<()> {
use alloc::string::ToString;
let formatted = args.to_string();
self.extend_from_slice(formatted.as_bytes());
Ok(())
}
}
pub trait InstrumentRegistration: Sized + Instrument + 'static {
const NAME: &'static str;
fn build(config: &super::ProfilerConfig) -> Result<Self, InstrumentError>;
}
#[derive(Debug, thiserror::Error)]
pub enum InstrumentError {
#[error("unknown profiling instrument '{0}'")]
Undefined(String),
#[error("failed to construct instrument '{name}': {reason}")]
Build { name: String, reason: String },
}
#[cfg(feature = "std")]
pub fn instrument_from_name(
name: &str,
config: &super::ProfilerConfig,
) -> Result<Box<dyn Instrument>, InstrumentError> {
use alloc::string::ToString;
for instrument in inventory::iter::<InstrumentRegistrationInfo>() {
if instrument.name == name {
return (instrument.builder)(config);
}
}
Err(InstrumentError::Undefined(name.to_string()))
}
#[cfg(feature = "std")]
#[doc(hidden)]
pub struct InstrumentRegistrationInfo {
name: &'static str,
builder: fn(&super::ProfilerConfig) -> Result<Box<dyn Instrument>, InstrumentError>,
}
#[cfg(feature = "std")]
impl InstrumentRegistrationInfo {
pub const fn new<T: InstrumentRegistration>() -> Self {
let name = <T as InstrumentRegistration>::NAME;
Self {
name,
builder: build_instrument::<T>,
}
}
}
#[cfg(feature = "std")]
#[macro_export]
macro_rules! register_instrument {
($t:ty) => {
inventory::submit!($crate::profiling::instrument::InstrumentRegistrationInfo::new::<$t>());
};
}
#[cfg(feature = "std")]
inventory::collect!(InstrumentRegistrationInfo);
#[cfg(feature = "std")]
#[inline]
fn build_instrument<T: InstrumentRegistration>(
config: &super::ProfilerConfig,
) -> Result<Box<dyn Instrument>, InstrumentError> {
<T as InstrumentRegistration>::build(config).map(|inst| Box::new(inst) as Box<dyn Instrument>)
}