diff --git a/Cargo.lock b/Cargo.lock index cc9ea18fe3..8d8ffc6aad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4266,8 +4266,10 @@ dependencies = [ "kona-derive", "kona-genesis", "kona-hardforks", + "kona-macros", "kona-protocol", "kona-registry", + "metrics", "op-alloy-consensus", "op-alloy-rpc-types-engine", "proptest", diff --git a/bin/node/Cargo.toml b/bin/node/Cargo.toml index 44173a45b6..81d68c2aa6 100644 --- a/bin/node/Cargo.toml +++ b/bin/node/Cargo.toml @@ -17,16 +17,16 @@ workspace = true [dependencies] # workspace kona-rpc.workspace = true -kona-derive.workspace = true kona-genesis.workspace = true kona-protocol.workspace = true kona-cli = { workspace = true, features = ["secrets"] } -kona-engine = { workspace = true, features = ["metrics"] } kona-p2p = { workspace = true, features = ["metrics"] } +kona-derive = { workspace = true, features = ["metrics"] } +kona-engine = { workspace = true, features = ["metrics"] } kona-registry = { workspace = true, features = ["tabled"] } -kona-node-service = { workspace = true, features = ["metrics"] } kona-sources = { workspace = true, features = ["metrics"] } +kona-node-service = { workspace = true, features = ["metrics"] } # alloy alloy-provider.workspace = true diff --git a/bin/node/src/flags/metrics.rs b/bin/node/src/flags/metrics.rs index 0ecd430eda..36616cb777 100644 --- a/bin/node/src/flags/metrics.rs +++ b/bin/node/src/flags/metrics.rs @@ -15,6 +15,7 @@ pub fn init_unified_metrics(args: &MetricsArgs) -> anyhow::Result<()> { kona_p2p::Metrics::init(); kona_engine::Metrics::init(); kona_node_service::Metrics::init(); + kona_derive::metrics::Metrics::init(); VersionInfo::from_build().register_version_metrics(); } Ok(()) diff --git a/crates/protocol/derive/Cargo.toml b/crates/protocol/derive/Cargo.toml index 0ece285fd2..1e2e49fb12 100644 --- a/crates/protocol/derive/Cargo.toml +++ b/crates/protocol/derive/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # Protocol +kona-macros.workspace = true kona-genesis.workspace = true kona-protocol.workspace = true kona-hardforks.workspace = true @@ -38,6 +39,9 @@ serde = { workspace = true, optional = true } spin = { workspace = true, optional = true } tracing-subscriber = { workspace = true, optional = true, features = ["fmt"] } +# `metrics` feature +metrics = { workspace = true, optional = true } + [dev-dependencies] kona-derive = { workspace = true, features = ["test-utils"] } spin.workspace = true @@ -52,6 +56,7 @@ op-alloy-consensus = { workspace = true, features = ["k256"] } [features] default = [] +metrics = ["dep:metrics"] serde = [ "dep:serde", "kona-protocol/serde", diff --git a/crates/protocol/derive/src/lib.rs b/crates/protocol/derive/src/lib.rs index 89aebb8a58..c6a282a7d1 100644 --- a/crates/protocol/derive/src/lib.rs +++ b/crates/protocol/derive/src/lib.rs @@ -5,7 +5,7 @@ issue_tracker_base_url = "https://github.com/op-rs/kona/issues/" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#![no_std] +#![cfg_attr(not(feature = "metrics"), no_std)] extern crate alloc; @@ -21,6 +21,7 @@ pub mod prelude { pub mod attributes; pub mod errors; +pub mod metrics; pub mod pipeline; pub mod sources; pub mod stages; diff --git a/crates/protocol/derive/src/metrics/mod.rs b/crates/protocol/derive/src/metrics/mod.rs new file mode 100644 index 0000000000..f56da96a39 --- /dev/null +++ b/crates/protocol/derive/src/metrics/mod.rs @@ -0,0 +1,51 @@ +//! Metrics for the derivation pipeline. + +/// Container for metrics. +#[derive(Debug, Clone)] +pub struct Metrics; + +impl Metrics { + /// Identifier for the pipeline origin gauge. + pub const PIPELINE_ORIGIN: &str = "kona_derive_pipeline_origin"; + + /// Identifier to track the amount of time it takes to advance the pipeline origin. + pub const PIPELINE_ORIGIN_ADVANCE: &str = "kona_derive_pipeline_origin_advance"; + + /// Identifier for the histogram that tracks when the system config is updated. + pub const SYSTEM_CONFIG_UPDATE: &str = "kona_derive_system_config_update"; +} + +impl Metrics { + /// Initializes metrics for the P2P stack. + /// + /// This does two things: + /// * Describes various metrics. + /// * Initializes metrics to 0 so they can be queried immediately. + #[cfg(feature = "metrics")] + pub fn init() { + Self::describe(); + Self::zero(); + } + + /// Describes metrics used in [`kona_p2p`][crate]. + #[cfg(feature = "metrics")] + pub fn describe() { + metrics::describe_gauge!( + Self::PIPELINE_ORIGIN, + "The block height of the pipeline l1 origin" + ); + metrics::describe_histogram!( + Self::PIPELINE_ORIGIN_ADVANCE, + "The amount of time it takes to advance the pipeline origin" + ); + metrics::describe_histogram!( + Self::SYSTEM_CONFIG_UPDATE, + "The time it takes to update the system config" + ); + } + + /// Initializes metrics to 0 so they can be queried immediately. + #[allow(clippy::missing_const_for_fn)] + #[cfg(feature = "metrics")] + pub fn zero() {} +} diff --git a/crates/protocol/derive/src/stages/l1_traversal.rs b/crates/protocol/derive/src/stages/l1_traversal.rs index bb4b74022d..15c40d9faa 100644 --- a/crates/protocol/derive/src/stages/l1_traversal.rs +++ b/crates/protocol/derive/src/stages/l1_traversal.rs @@ -60,6 +60,13 @@ impl L1Traversal { rollup_config: cfg, } } + + /// Update the origin block in the traversal stage. + fn update_origin(&mut self, block: BlockInfo) { + self.done = false; + self.block = Some(block); + kona_macros::set!(gauge, crate::metrics::Metrics::PIPELINE_ORIGIN, block.number as f64); + } } #[async_trait] @@ -68,6 +75,10 @@ impl OriginAdvancer for L1Traversal { /// This function fetches the next L1 [BlockInfo] from the data source and updates the /// [SystemConfig] with the receipts from the block. async fn advance_origin(&mut self) -> PipelineResult<()> { + // Advance start time for metrics. + #[cfg(feature = "metrics")] + let start_time = std::time::Instant::now(); + // Pull the next block or return EOF. // PipelineError::EOF has special handling further up the pipeline. let block = match self.block { @@ -101,8 +112,18 @@ impl OriginAdvancer for L1Traversal { let next_block_holocene = self.rollup_config.is_holocene_active(next_l1_origin.timestamp); // Update the block origin regardless of if a holocene activation is required. - self.block = Some(next_l1_origin); - self.done = false; + self.update_origin(next_l1_origin); + + // Record the origin as advanced. + #[cfg(feature = "metrics")] + { + let duration = start_time.elapsed(); + kona_macros::record!( + histogram, + crate::metrics::Metrics::PIPELINE_ORIGIN_ADVANCE, + duration.as_secs_f64() + ); + } // If the prev block is not holocene, but the next is, we need to flag this // so the pipeline driver will reset the pipeline for holocene activation. @@ -126,8 +147,7 @@ impl SignalReceiver for L1Traversal { match signal { Signal::Reset(ResetSignal { l1_origin, system_config, .. }) | Signal::Activation(ActivationSignal { l1_origin, system_config, .. }) => { - self.block = Some(l1_origin); - self.done = false; + self.update_origin(l1_origin); self.system_config = system_config.expect("System config must be provided."); } _ => {} diff --git a/crates/utilities/macros/src/lib.rs b/crates/utilities/macros/src/lib.rs index 6d19a3f9e2..f0796b849b 100644 --- a/crates/utilities/macros/src/lib.rs +++ b/crates/utilities/macros/src/lib.rs @@ -6,5 +6,6 @@ )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![no_std] mod metrics;