diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock index 0e99ef84e556f0e82f0282af91e2aa4ab6e272ed..0195d5673b084e21f4f62e6540a3c1d3a3e9e3fb 100644 --- a/polkadot/Cargo.lock +++ b/polkadot/Cargo.lock @@ -5407,6 +5407,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", "rand_core 0.5.1", diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 84577e41df63442fa69b9e9aa9bf0a1535c63a41..c0779e786f3bceea1bc826aec60e460398e4a864 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -17,7 +17,8 @@ kvdb = "0.9.0" kvdb-rocksdb = "0.11.0" derive_more = "0.99.1" -polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" } +polkadot-node-subsystem = { path = "../../subsystem" } +polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-overseer = { path = "../../overseer" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index 1ad981f74a4452f04ebae6732c3680d294df9ca9..f902fbb058639c73c106a038e130174925541998 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -28,7 +28,7 @@ //! //! We maintain a rolling window of session indices. This starts as empty -use polkadot_subsystem::{ +use polkadot_node_subsystem::{ messages::{ RuntimeApiMessage, RuntimeApiRequest, ChainApiMessage, ApprovalDistributionMessage, }, @@ -708,7 +708,7 @@ mod tests { use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_primitives::approval::{VRFOutput, VRFProof}; use polkadot_primitives::v1::ValidatorIndex; - use polkadot_subsystem::messages::AllMessages; + use polkadot_node_subsystem::messages::AllMessages; use sp_core::testing::TaskExecutor; use sp_runtime::{Digest, DigestItem}; use sp_consensus_babe::Epoch as BabeEpoch; diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 60f1135f70e0fa08370c659e50b6d0d18cf0f4f0..7fcfd475c1b7736242b84e4958877bde69f09c92 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -21,7 +21,7 @@ //! of others. It uses this information to determine when candidates and blocks have //! been sufficiently approved to finalize. -use polkadot_subsystem::{ +use polkadot_node_subsystem::{ messages::{ AssignmentCheckResult, ApprovalCheckResult, ApprovalVotingMessage, RuntimeApiMessage, RuntimeApiRequest, ChainApiMessage, ApprovalDistributionMessage, @@ -31,6 +31,9 @@ use polkadot_subsystem::{ Subsystem, SubsystemContext, SubsystemError, SubsystemResult, SpawnedSubsystem, FromOverseer, OverseerSignal, }; +use polkadot_node_subsystem_util::{ + metrics::{self, prometheus}, +}; use polkadot_primitives::v1::{ ValidatorIndex, Hash, SessionIndex, SessionInfo, CandidateHash, CandidateReceipt, BlockNumber, PersistedValidationData, @@ -94,15 +97,79 @@ pub struct ApprovalVotingSubsystem { keystore: Arc<LocalKeystore>, slot_duration_millis: u64, db: Arc<dyn KeyValueDB>, + metrics: Metrics, +} + +#[derive(Clone)] +struct MetricsInner { + imported_candidates_total: prometheus::Counter<prometheus::U64>, + assignments_produced_total: prometheus::Counter<prometheus::U64>, + approvals_produced_total: prometheus::Counter<prometheus::U64>, +} + +/// Aproval Voting metrics. +#[derive(Default, Clone)] +pub struct Metrics(Option<MetricsInner>); + +impl Metrics { + fn on_candidate_imported(&self) { + if let Some(metrics) = &self.0 { + metrics.imported_candidates_total.inc(); + } + } + + fn on_assignment_produced(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_produced_total.inc(); + } + } + + fn on_approval_produced(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_produced_total.inc(); + } + } +} + +impl metrics::Metrics for Metrics { + fn try_register( + registry: &prometheus::Registry, + ) -> std::result::Result<Self, prometheus::PrometheusError> { + let metrics = MetricsInner { + imported_candidates_total: prometheus::register( + prometheus::Counter::new( + "parachain_imported_candidates_total", + "Number of candidates imported by the approval voting subsystem", + )?, + registry, + )?, + assignments_produced_total: prometheus::register( + prometheus::Counter::new( + "parachain_assignments_produced_total", + "Number of assignments produced by the approval voting subsystem", + )?, + registry, + )?, + approvals_produced_total: prometheus::register( + prometheus::Counter::new( + "parachain_approvals_produced_total", + "Number of approvals produced by the approval voting subsystem", + )?, + registry, + )?, + }; + Ok(Metrics(Some(metrics))) + } } impl ApprovalVotingSubsystem { - /// Create a new approval voting subsystem with the given keystore, slot duration, + /// Create a new approval voting subsystem with the given keystore and config, /// which creates a DB at the given path. This function will delete the directory /// at the given path if it already exists. pub fn with_config( config: Config, keystore: Arc<LocalKeystore>, + metrics: Metrics, ) -> std::io::Result<Self> { const DEFAULT_CACHE_SIZE: usize = 100 * 1024 * 1024; // 100MiB default should be fine unless finality stalls. @@ -115,6 +182,7 @@ impl ApprovalVotingSubsystem { keystore, slot_duration_millis: config.slot_duration_millis, db, + metrics, }) } } @@ -343,6 +411,7 @@ async fn run<C>( handle_from_overseer( &mut ctx, &mut state, + &subsystem.metrics, db_writer, next_msg?, &mut last_finalized_height, @@ -353,6 +422,7 @@ async fn run<C>( handle_background_request( &mut ctx, &mut state, + &subsystem.metrics, req, ).await? } else { @@ -363,6 +433,7 @@ async fn run<C>( if handle_actions( &mut ctx, + &subsystem.metrics, &mut wakeups, db_writer, &background_tx, @@ -378,6 +449,7 @@ async fn run<C>( // returns `true` if any of the actions was a `Conclude` command. async fn handle_actions( ctx: &mut impl SubsystemContext, + metrics: &Metrics, wakeups: &mut Wakeups, db: &dyn KeyValueDB, background_tx: &mpsc::Sender<BackgroundRequest>, @@ -406,6 +478,7 @@ async fn handle_actions( candidate, backing_group, } => { + metrics.on_assignment_produced(); let block_hash = indirect_cert.block_hash; let validator_index = indirect_cert.validator; @@ -439,6 +512,7 @@ async fn handle_actions( async fn handle_from_overseer( ctx: &mut impl SubsystemContext, state: &mut State<impl DBReader>, + metrics: &Metrics, db_writer: &dyn KeyValueDB, x: FromOverseer<ApprovalVotingMessage>, last_finalized_height: &mut Option<BlockNumber>, @@ -468,6 +542,8 @@ async fn handle_from_overseer( ); for (c_hash, c_entry) in block_batch.imported_candidates { + metrics.on_candidate_imported(); + let our_tranche = c_entry .approval_entry(&block_batch.block_hash) .and_then(|a| a.our_assignment().map(|a| a.tranche())); @@ -542,11 +618,12 @@ async fn handle_from_overseer( async fn handle_background_request( ctx: &mut impl SubsystemContext, state: &State<impl DBReader>, + metrics: &Metrics, request: BackgroundRequest, ) -> SubsystemResult<Vec<Action>> { match request { BackgroundRequest::ApprovalVote(vote_request) => { - issue_approval(ctx, state, vote_request).await + issue_approval(ctx, state, metrics, vote_request).await } BackgroundRequest::CandidateValidation( validation_data, @@ -1443,6 +1520,7 @@ async fn launch_approval( async fn issue_approval( ctx: &mut impl SubsystemContext, state: &State<impl DBReader>, + metrics: &Metrics, request: ApprovalVoteRequest, ) -> SubsystemResult<Vec<Action>> { let ApprovalVoteRequest { validator_index, block_hash, candidate_index } = request; @@ -1541,6 +1619,8 @@ async fn issue_approval( validator_index as _, )?; + metrics.on_approval_produced(); + // dispatch to approval distribution. ctx.send_message(ApprovalDistributionMessage::DistributeApproval(IndirectSignedApprovalVote { block_hash, diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 160ed7aadf79288e5091fc48f0941b4bcdcf1aa3..3959a1468be67e4a526c593849044ac0777fdb17 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -21,7 +21,7 @@ use polkadot_node_primitives::approval::{ RELAY_VRF_MODULO_CONTEXT, DelayTranche, }; use polkadot_node_subsystem_test_helpers::make_subsystem_context; -use polkadot_subsystem::messages::AllMessages; +use polkadot_node_subsystem::messages::AllMessages; use sp_core::testing::TaskExecutor; use parking_lot::Mutex; diff --git a/polkadot/node/service/src/grandpa_support.rs b/polkadot/node/service/src/grandpa_support.rs index 70df2be23ddde9697c439e1e1985a93a007c206b..991df8b6708fbbb423eed8472a1cb7f2b656d239 100644 --- a/polkadot/node/service/src/grandpa_support.rs +++ b/polkadot/node/service/src/grandpa_support.rs @@ -57,7 +57,7 @@ impl ApprovalCheckingDiagnostic { Some(prometheus_endpoint::register( prometheus_endpoint::Histogram::with_opts( prometheus_endpoint::HistogramOpts::new( - "approval_checking_finality_lag", + "parachain_approval_checking_finality_lag", "How far behind the head of the chain the Approval Checking protocol wants to vote", ).buckets(vec![1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0]) )?, diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index e1e816797968c2aef5d9cd26181f91fd4a078b01..ee3de73918a59b82745bc141dc0f8d8f9ecdf3a3 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -497,6 +497,7 @@ where approval_voting: ApprovalVotingSubsystem::with_config( approval_voting_config, keystore.clone(), + Metrics::register(registry)?, )?, gossip_support: GossipSupportSubsystem::new(), };