Skip to main content

miden_debug_engine/profiling/instrument/
mod.rs

1//! Every distinct kind of profiling data collection is an [`Instrument`] implementation that
2//! lives in a submodule.
3//!
4//! Each instrument is uniquely identified by its [`Instrument::name`].
5
6use miden_core::operations::Operation;
7
8mod op_histogram;
9
10pub use op_histogram::OpHistogram;
11
12/// The functionality required for an instrument to be plugged in to `Profiler`.
13pub trait Instrument {
14    /// The human readable name of this instrument used in CLI arguments and user output
15    ///
16    /// This should be the same name as the corresponding `InstrumentRegistration::NAME` constant
17    fn name(&self) -> &'static str;
18    /// To be called each vm cycle an `Operation` is executed.
19    fn on_operation_execution_cycle(&mut self, op: Operation);
20    /// Write this instrumentation's collected output as a report to `writer`
21    fn write_report_to(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()>;
22}
23
24/// Represents the information needed to construct an [Instrument] dynamically
25pub trait InstrumentRegistration: Sized + Instrument + 'static {
26    /// The human readable name of this instrument used in CLI arguments and user output
27    const NAME: &'static str;
28
29    /// Create an instance of this instrument with the provided configuration
30    fn build(config: &super::ProfilerConfig) -> Result<Self, InstrumentError>;
31}
32
33#[derive(Debug, thiserror::Error)]
34pub enum InstrumentError {
35    /// The given instrument name is not registered to any known instrument
36    #[error("unknown profiling instrument '{0}'")]
37    Undefined(String),
38    /// We failed to construct the named instrument
39    #[error("failed to construct instrument '{name}': {reason}")]
40    Build { name: String, reason: String },
41}
42
43/// Get an instance of instrument `name`, if one has been registered by that name.
44///
45/// Returns `Err` if no such instrument is registered, or the instrument constructor returned an
46/// error
47pub fn instrument_from_name(
48    name: &str,
49    config: &super::ProfilerConfig,
50) -> Result<Box<dyn Instrument>, InstrumentError> {
51    for instrument in inventory::iter::<InstrumentRegistrationInfo>() {
52        if instrument.name == name {
53            return (instrument.builder)(config);
54        }
55    }
56    Err(InstrumentError::Undefined(name.to_string()))
57}
58
59#[doc(hidden)]
60pub struct InstrumentRegistrationInfo {
61    name: &'static str,
62    builder: fn(&super::ProfilerConfig) -> Result<Box<dyn Instrument>, InstrumentError>,
63}
64
65impl InstrumentRegistrationInfo {
66    pub const fn new<T: InstrumentRegistration>() -> Self {
67        let name = <T as InstrumentRegistration>::NAME;
68        Self {
69            name,
70            builder: build_instrument::<T>,
71        }
72    }
73}
74
75#[macro_export]
76macro_rules! register_instrument {
77    ($t:ty) => {
78        inventory::submit!($crate::profiling::instrument::InstrumentRegistrationInfo::new::<$t>());
79    };
80}
81
82inventory::collect!(InstrumentRegistrationInfo);
83
84#[inline]
85fn build_instrument<T: InstrumentRegistration>(
86    config: &super::ProfilerConfig,
87) -> Result<Box<dyn Instrument>, InstrumentError> {
88    <T as InstrumentRegistration>::build(config).map(|inst| Box::new(inst) as Box<dyn Instrument>)
89}