Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Histogram support in runtime metrics #6935

Merged
merged 21 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 42 additions & 20 deletions node/metrics/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,33 @@
//! tracing support. This requires that the custom profiler (`TraceHandler`) to be
//! registered in substrate via a `logger_hook()`. Events emitted from runtime are
//! then captured/processed by the `TraceHandler` implementation.
//!
//! Don't add logs in this file because it gets executed before the logger is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

//! initialized and they won't be delivered. Add println! statements if you need
//! to debug this code.

#![cfg(feature = "runtime-metrics")]

use codec::Decode;
use primitives::{
metric_definitions::{CounterDefinition, CounterVecDefinition},
metric_definitions::{CounterDefinition, CounterVecDefinition, HistogramDefinition},
RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricUpdate,
};
use std::{
collections::hash_map::HashMap,
sync::{Arc, Mutex, MutexGuard},
};
use substrate_prometheus_endpoint::{
register, Counter, CounterVec, Opts, PrometheusError, Registry, U64,
register, Counter, CounterVec, Histogram, HistogramOpts, Opts, PrometheusError, Registry, U64,
};
mod parachain;

const LOG_TARGET: &'static str = "metrics::runtime";

/// Holds the registered Prometheus metric collections.
#[derive(Clone, Default)]
pub struct Metrics {
counter_vecs: Arc<Mutex<HashMap<String, CounterVec<U64>>>>,
counters: Arc<Mutex<HashMap<String, Counter<U64>>>>,
histograms: Arc<Mutex<HashMap<String, Histogram>>>,
}

/// Runtime metrics wrapper.
Expand Down Expand Up @@ -80,7 +83,20 @@ impl RuntimeMetricsProvider {
})
}

/// Increment a counter with labels by a value.
/// Register a histogram metric
pub fn register_histogram(&self, hist: HistogramDefinition) {
self.with_histograms_lock_held(|mut hashmap| {
hashmap.entry(hist.name.to_owned()).or_insert(register(
Histogram::with_opts(
HistogramOpts::new(hist.name, hist.description).buckets(hist.buckets.to_vec()),
)?,
&self.0,
)?);
return Ok(())
})
}

/// Increment a counter with labels by a value (in seconds)
pub fn inc_counter_vec_by(&self, name: &str, value: u64, labels: &RuntimeMetricLabelValues) {
self.with_counter_vecs_lock_held(|mut hashmap| {
hashmap.entry(name.to_owned()).and_modify(|counter_vec| {
Expand All @@ -101,28 +117,33 @@ impl RuntimeMetricsProvider {
})
}

/// Observe a histogram
pub fn observe_histogram(&self, name: &str, value: f64) {
self.with_histograms_lock_held(|mut hashmap| {
hashmap.entry(name.to_owned()).and_modify(|histogram| histogram.observe(value));
Ok(())
})
}

fn with_counters_lock_held<F>(&self, do_something: F)
where
F: FnOnce(MutexGuard<'_, HashMap<String, Counter<U64>>>) -> Result<(), PrometheusError>,
{
let _ = self.1.counters.lock().map(do_something).or_else(|error| {
gum::error!(target: LOG_TARGET, "Cannot acquire the counter hashmap lock: {:?}", error);
Err(error)
});
let _ = self.1.counters.lock().map(do_something).or_else(|error| Err(error));
}

fn with_counter_vecs_lock_held<F>(&self, do_something: F)
where
F: FnOnce(MutexGuard<'_, HashMap<String, CounterVec<U64>>>) -> Result<(), PrometheusError>,
{
let _ = self.1.counter_vecs.lock().map(do_something).or_else(|error| {
gum::error!(
target: LOG_TARGET,
"Cannot acquire the countervec hashmap lock: {:?}",
error
);
Err(error)
});
let _ = self.1.counter_vecs.lock().map(do_something).or_else(|error| Err(error));
}

fn with_histograms_lock_held<F>(&self, do_something: F)
where
F: FnOnce(MutexGuard<'_, HashMap<String, Histogram>>) -> Result<(), PrometheusError>,
{
let _ = self.1.histograms.lock().map(do_something).or_else(|error| Err(error));
}
}

Expand All @@ -149,8 +170,8 @@ impl sc_tracing::TraceHandler for RuntimeMetricsProvider {
Ok(update_op) => {
self.parse_metric_update(update_op);
},
Err(e) => {
gum::error!(target: LOG_TARGET, "TraceEvent decode failed: {:?}", e);
Err(_) => {
// do nothing
},
}
}
Expand All @@ -165,6 +186,8 @@ impl RuntimeMetricsProvider {
self.inc_counter_vec_by(update.metric_name(), value, labels),
RuntimeMetricOp::IncrementCounter(value) =>
self.inc_counter_by(update.metric_name(), value),
RuntimeMetricOp::ObserveHistogram(value) =>
self.observe_histogram(update.metric_name(), value),
}
}

Expand All @@ -191,7 +214,6 @@ impl RuntimeMetricsProvider {
pub fn logger_hook() -> impl FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration) -> () {
|logger_builder, config| {
if config.prometheus_registry().is_none() {
gum::debug!(target: LOG_TARGET, "Prometheus registry is not configured.",);
return
}
let registry = config.prometheus_registry().cloned().unwrap();
Expand Down
3 changes: 2 additions & 1 deletion node/metrics/src/runtime/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use primitives::metric_definitions::{
PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS,
PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED, PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED,
PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED, PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED,
PARACHAIN_INHERENT_DATA_WEIGHT,
PARACHAIN_INHERENT_DATA_WEIGHT, PARACHAIN_VERIFY_DISPUTE_SIGNATURE,
};

/// Register the parachain runtime metrics.
Expand All @@ -35,4 +35,5 @@ pub fn register_metrics(runtime_metrics_provider: &RuntimeMetricsProvider) {
runtime_metrics_provider.register_countervec(PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED);
runtime_metrics_provider
.register_countervec(PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS);
runtime_metrics_provider.register_histogram(PARACHAIN_VERIFY_DISPUTE_SIGNATURE);
}
22 changes: 22 additions & 0 deletions primitives/src/v4/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub enum RuntimeMetricOp {
IncrementCounterVec(u64, RuntimeMetricLabelValues),
/// Increment a counter metric by value.
IncrementCounter(u64),
/// Observe histogram value
ObserveHistogram(f64),
}

/// Runtime metric update event.
Expand Down Expand Up @@ -127,6 +129,16 @@ pub mod metric_definitions {
pub labels: &'a [&'static str],
}

/// `Histogram` metric definition
pub struct HistogramDefinition<'a> {
/// The name of the metric.
pub name: &'static str,
/// The description of the metric.
pub description: &'static str,
/// The buckets for the histogram
pub buckets: &'a [f64],
}

/// Counts parachain inherent data weights. Use `before` and `after` labels to differentiate
/// between the weight before and after filtering.
pub const PARACHAIN_INHERENT_DATA_WEIGHT: CounterVecDefinition = CounterVecDefinition {
Expand Down Expand Up @@ -176,4 +188,14 @@ pub mod metric_definitions {
description: "Counts the number of bitfields signature checked in `enter_inner`.",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This metric doesn't work (before and after my changes) for some reason - it's not reported at all by prometheus. I'll investigate further.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a follow up issue for this: https://github.com/paritytech/polkadot/issues/6943

labels: &["validity"],
};

/// Measures how much time does it take to verify a single validator signature of a dispute statement
pub const PARACHAIN_VERIFY_DISPUTE_SIGNATURE: HistogramDefinition =
HistogramDefinition {
name: "polkadot_parachain_verify_dispute_signature",
description: "How much time does it take to verify a single validator signature of a dispute statement, in microseconds",
buckets: &[10.0, 50.0, 100.0, 200.0, 400.0, 800.0, 1000.0, 1500.0, 2000.0, 2500.0],


};
}
5 changes: 3 additions & 2 deletions runtime/metrics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ edition.workspace = true
[dependencies]
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false}
sp-tracing = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
parity-scale-codec = { version = "3.3.0", default-features = false }
parity-scale-codec = { version = "3.3.0", default-features = false, features = ["full"]}
primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }

bs58 = { version = "0.4.0", default-features = false, features = ["alloc"] }

Expand All @@ -21,4 +22,4 @@ std = [
"primitives/std",
"bs58/std"
]
runtime-metrics = ["sp-tracing/with-tracing"]
runtime-metrics = ["sp-tracing/with-tracing", "frame-benchmarking"]
41 changes: 35 additions & 6 deletions runtime/metrics/src/with_runtime_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! This module provides an implementation for the runtime metrics types: `Counter`
//! and `CounterVec`. These types expose a Prometheus like interface and same functionality.
//! Each instance of a runtime metric is mapped to a Prometheus metric on the client side.
//! The runtime metrics must be registered with the registry in the client, otherwise
//! they will not be published.
//! This module provides an implementation for the runtime metrics types: `Counter`,
//! `CounterVec` and `Histogram`. These types expose a Prometheus like interface and
//! same functionality. Each instance of a runtime metric is mapped to a Prometheus
//! metric on the client side. The runtime metrics must be registered with the registry
//! in the client, otherwise they will not be published.

const TRACING_TARGET: &'static str = "metrics";

use parity_scale_codec::Encode;
use primitives::{
metric_definitions::{CounterDefinition, CounterVecDefinition},
metric_definitions::{CounterDefinition, CounterVecDefinition, HistogramDefinition},
RuntimeMetricLabelValues, RuntimeMetricOp, RuntimeMetricUpdate,
};

Expand All @@ -41,6 +41,10 @@ pub struct Counter {
name: &'static str,
}

pub struct Histogram {
name: &'static str,
}

/// Convenience trait implemented for all metric types.
trait MetricEmitter {
fn emit(metric_op: &RuntimeMetricUpdate) {
Expand Down Expand Up @@ -77,6 +81,7 @@ impl LabeledMetric {

impl MetricEmitter for LabeledMetric {}
impl MetricEmitter for Counter {}
impl MetricEmitter for Histogram {}

impl CounterVec {
/// Create a new counter as specified by `definition`. This metric needs to be registered
Expand Down Expand Up @@ -116,3 +121,27 @@ impl Counter {
self.inc_by(1);
}
}

impl Histogram {
/// Create a new histogram as specified by `definition`. This metric needs to be registered
/// in the client before it can be used.
pub const fn new(definition: HistogramDefinition) -> Self {
// No register op is emitted since the metric is supposed to be registered
// on the client by the time `inc()` is called.
Histogram { name: definition.name }
}

// Observe a value in the histogram
pub fn observe(&self, value: f64) {
let metric_update = RuntimeMetricUpdate {
metric_name: Vec::from(self.name),
op: RuntimeMetricOp::ObserveHistogram(value),
};
Self::emit(&metric_update);
}
}

/// Returns current time in ns
pub fn get_current_time() -> u128 {
frame_benchmarking::benchmarking::current_time()
}
24 changes: 23 additions & 1 deletion runtime/metrics/src/without_runtime_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@
//! provide a dummy implementation for the native runtime to avoid cluttering the runtime code
//! with `#[cfg(feature = "runtime-metrics")]`.

use primitives::metric_definitions::{CounterDefinition, CounterVecDefinition};
use primitives::metric_definitions::{
CounterDefinition, CounterVecDefinition, HistogramDefinition,
};

/// A dummy `Counter`.
pub struct Counter;
/// A dummy `CounterVec`.
pub struct CounterVec;

/// A dummy `Histogram`
pub struct Histogram;

/// Dummy implementation.
impl CounterVec {
/// Constructor.
Expand Down Expand Up @@ -52,3 +57,20 @@ impl Counter {
/// Increment counter, implementation is a `no op`.
pub fn inc(&self) {}
}

/// Dummy implementation
impl Histogram {
/// Create a new histogram as specified by `definition`. This metric needs to be registered
/// in the client before it can be used.
pub const fn new(_definition: HistogramDefinition) -> Self {
Histogram
}

// Observe a value in the histogram
pub fn observe(&self, _value: f64) {}
}

/// Dummy implementation - always 0
pub fn get_current_time() -> u128 {
0
}
20 changes: 14 additions & 6 deletions runtime/parachains/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

//! Runtime component for handling disputes of parachain candidates.

use crate::{configuration, initializer::SessionChangeNotification, session_info};
use crate::{
configuration, initializer::SessionChangeNotification, metrics::METRICS, session_info,
};
use bitvec::{bitvec, order::Lsb0 as BitOrderLsb0};
use frame_support::{ensure, traits::Get, weights::Weight};
use frame_system::pallet_prelude::*;
use parity_scale_codec::{Decode, Encode};
use polkadot_runtime_metrics::get_current_time;
use primitives::{
byzantine_threshold, supermajority_threshold, ApprovalVote, CandidateHash,
CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CompactStatement, ConsensusLog,
Expand Down Expand Up @@ -1357,9 +1360,14 @@ fn check_signature(
ExplicitDisputeStatement { valid: false, candidate_hash, session }.signing_payload(),
};

if validator_signature.verify(&payload[..], &validator_public) {
Ok(())
} else {
Err(())
}
let start = get_current_time();

let res =
if validator_signature.verify(&payload[..], &validator_public) { Ok(()) } else { Err(()) };

let end = get_current_time();

METRICS.on_signature_check_complete(((end - start) / 1_000_000_000) as f64); // ns -> sec

res
}
Loading