diff --git a/Cargo.toml b/Cargo.toml index 475291a7..9399fa6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,5 +35,6 @@ harness = false [dependencies] subtle = "2.2.1" crossbeam-utils = "0.7" +metrics = "0.13.0-alpha.8" num_cpus = "1.13" rand = "0.7" diff --git a/src/lib.rs b/src/lib.rs index 49441e8f..c20d88d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,5 @@ pub mod plonk; pub mod poly; pub mod transcript; pub mod tweedle; + +pub mod model; diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 00000000..c979bcec --- /dev/null +++ b/src/model.rs @@ -0,0 +1,110 @@ +//! Helpers for modelling halo2 circuit performance. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt; +use std::sync::Arc; + +use metrics::{Key, Recorder, Unit}; + +/// A [`metrics`] recorder for examining halo2 metrics. +/// +/// # Examples +/// +/// ``` +/// use halo2::model::ModelRecorder; +/// +/// fn main() { +/// let recorder = Box::leak(Box::new(ModelRecorder::default())); +/// metrics::set_recorder(recorder).unwrap(); +/// +/// // Create circuit, build and/or verify proof. +/// +/// println!("{}", recorder); +/// } +/// ``` +#[derive(Debug)] +pub struct ModelRecorder { + counters: Arc>>, +} + +impl Default for ModelRecorder { + fn default() -> Self { + ModelRecorder { + counters: Default::default(), + } + } +} + +impl fmt::Display for ModelRecorder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut counters = self + .counters + .try_borrow() + .unwrap() + .iter() + .map(|(k, v)| (k.clone(), *v)) + .collect::>(); + + counters.sort_by(|(k1, _), (k2, _)| { + let key1 = ( + k1.name(), + k1.labels() + .map(|l| (l.key(), l.value())) + .collect::>(), + ); + let key2 = ( + k2.name(), + k2.labels() + .map(|l| (l.key(), l.value())) + .collect::>(), + ); + key1.cmp(&key2) + }); + + writeln!(f, "Recorded metrics:")?; + for (key, value) in counters.iter() { + writeln!(f, "- {}: {}", key, value)?; + } + Ok(()) + } +} + +impl Recorder for ModelRecorder { + fn register_counter(&self, _key: Key, _unit: Option, _description: Option<&'static str>) { + } + + fn register_gauge(&self, _key: Key, _unit: Option, _description: Option<&'static str>) {} + + fn register_histogram( + &self, + _key: Key, + _unit: Option, + _description: Option<&'static str>, + ) { + } + + fn increment_counter(&self, key: Key, value: u64) { + *self + .counters + .try_borrow_mut() + .unwrap() + .entry(key) + .or_default() += value; + } + + fn update_gauge(&self, _key: Key, _value: f64) { + unimplemented!() + } + + fn record_histogram(&self, _key: Key, _value: u64) { + unimplemented!() + } +} + +impl ModelRecorder { + /// Clear all recorded metrics. + pub fn clear(&self) { + self.counters.try_borrow_mut().unwrap().clear(); + } +}