mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(evm, trie): more metrics (#11613)
This commit is contained in:
@ -77,7 +77,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_with_state_witness<F>(
|
||||
fn execute_with_state_closure<F>(
|
||||
self,
|
||||
input: Self::Input<'_>,
|
||||
witness: F,
|
||||
@ -86,8 +86,8 @@ where
|
||||
F: FnMut(&State<DB>),
|
||||
{
|
||||
match self {
|
||||
Self::Left(a) => a.execute_with_state_witness(input, witness),
|
||||
Self::Right(b) => b.execute_with_state_witness(input, witness),
|
||||
Self::Left(a) => a.execute_with_state_closure(input, witness),
|
||||
Self::Right(b) => b.execute_with_state_closure(input, witness),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -38,12 +38,12 @@ pub trait Executor<DB> {
|
||||
/// The output of the block execution.
|
||||
fn execute(self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error>;
|
||||
|
||||
/// Executes the EVM with the given input and accepts a witness closure that is invoked with the
|
||||
/// EVM state after execution.
|
||||
fn execute_with_state_witness<F>(
|
||||
/// Executes the EVM with the given input and accepts a state closure that is invoked with
|
||||
/// the EVM state after execution.
|
||||
fn execute_with_state_closure<F>(
|
||||
self,
|
||||
input: Self::Input<'_>,
|
||||
witness: F,
|
||||
state: F,
|
||||
) -> Result<Self::Output, Self::Error>
|
||||
where
|
||||
F: FnMut(&State<DB>);
|
||||
@ -203,7 +203,7 @@ mod tests {
|
||||
Err(BlockExecutionError::msg("execution unavailable for tests"))
|
||||
}
|
||||
|
||||
fn execute_with_state_witness<F>(
|
||||
fn execute_with_state_closure<F>(
|
||||
self,
|
||||
_: Self::Input<'_>,
|
||||
_: F,
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
//! Executor metrics.
|
||||
//!
|
||||
//! Block processing related to syncing should take care to update the metrics by using e.g.
|
||||
//! [`ExecutorMetrics::metered`].
|
||||
//! Block processing related to syncing should take care to update the metrics by using either
|
||||
//! [`ExecutorMetrics::execute_metered`] or [`ExecutorMetrics::metered_one`].
|
||||
use std::time::Instant;
|
||||
|
||||
use metrics::{Counter, Gauge, Histogram};
|
||||
use reth_execution_types::BlockExecutionInput;
|
||||
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput};
|
||||
use reth_metrics::Metrics;
|
||||
use reth_primitives::BlockWithSenders;
|
||||
|
||||
use crate::execute::Executor;
|
||||
|
||||
/// Executor metrics.
|
||||
// TODO(onbjerg): add sload/sstore, acc load/acc change, bytecode metrics
|
||||
// TODO(onbjerg): add sload/sstore
|
||||
#[derive(Metrics, Clone)]
|
||||
#[metrics(scope = "sync.execution")]
|
||||
pub struct ExecutorMetrics {
|
||||
@ -18,31 +20,106 @@ pub struct ExecutorMetrics {
|
||||
pub gas_processed_total: Counter,
|
||||
/// The instantaneous amount of gas processed per second.
|
||||
pub gas_per_second: Gauge,
|
||||
|
||||
/// The Histogram for amount of time taken to execute blocks.
|
||||
pub execution_histogram: Histogram,
|
||||
/// The total amount of time it took to execute the latest block.
|
||||
pub execution_duration: Gauge,
|
||||
|
||||
/// The Histogram for number of accounts loaded when executing the latest block.
|
||||
pub accounts_loaded_histogram: Histogram,
|
||||
/// The Histogram for number of storage slots loaded when executing the latest block.
|
||||
pub storage_slots_loaded_histogram: Histogram,
|
||||
/// The Histogram for number of bytecodes loaded when executing the latest block.
|
||||
pub bytecodes_loaded_histogram: Histogram,
|
||||
|
||||
/// The Histogram for number of accounts updated when executing the latest block.
|
||||
pub accounts_updated_histogram: Histogram,
|
||||
/// The Histogram for number of storage slots updated when executing the latest block.
|
||||
pub storage_slots_updated_histogram: Histogram,
|
||||
/// The Histogram for number of bytecodes updated when executing the latest block.
|
||||
pub bytecodes_updated_histogram: Histogram,
|
||||
}
|
||||
|
||||
impl ExecutorMetrics {
|
||||
/// Execute the given block and update metrics for the execution.
|
||||
pub fn metered<F, R>(&self, input: BlockExecutionInput<'_, BlockWithSenders>, f: F) -> R
|
||||
fn metered<F, R>(&self, block: &BlockWithSenders, f: F) -> R
|
||||
where
|
||||
F: FnOnce(BlockExecutionInput<'_, BlockWithSenders>) -> R,
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
let gas_used = input.block.gas_used;
|
||||
|
||||
// Execute the block and record the elapsed time.
|
||||
let execute_start = Instant::now();
|
||||
let output = f(input);
|
||||
let output = f();
|
||||
let execution_duration = execute_start.elapsed().as_secs_f64();
|
||||
|
||||
// Update gas metrics.
|
||||
self.gas_processed_total.increment(gas_used);
|
||||
self.gas_per_second.set(gas_used as f64 / execution_duration);
|
||||
self.gas_processed_total.increment(block.gas_used);
|
||||
self.gas_per_second.set(block.gas_used as f64 / execution_duration);
|
||||
self.execution_histogram.record(execution_duration);
|
||||
self.execution_duration.set(execution_duration);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Execute the given block using the provided [`Executor`] and update metrics for the
|
||||
/// execution.
|
||||
///
|
||||
/// Compared to [`Self::metered_one`], this method additionally updates metrics for the number
|
||||
/// of accounts, storage slots and bytecodes loaded and updated.
|
||||
pub fn execute_metered<'a, E, DB, O, Error>(
|
||||
&self,
|
||||
executor: E,
|
||||
input: BlockExecutionInput<'a, BlockWithSenders>,
|
||||
) -> Result<BlockExecutionOutput<O>, Error>
|
||||
where
|
||||
E: Executor<
|
||||
DB,
|
||||
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
|
||||
Output = BlockExecutionOutput<O>,
|
||||
Error = Error,
|
||||
>,
|
||||
{
|
||||
let output = self.metered(input.block, || {
|
||||
executor.execute_with_state_closure(input, |state: &revm::db::State<DB>| {
|
||||
// Update the metrics for the number of accounts, storage slots and bytecodes
|
||||
// loaded
|
||||
let accounts = state.cache.accounts.len();
|
||||
let storage_slots = state
|
||||
.cache
|
||||
.accounts
|
||||
.values()
|
||||
.filter_map(|account| {
|
||||
account.account.as_ref().map(|account| account.storage.len())
|
||||
})
|
||||
.sum::<usize>();
|
||||
let bytecodes = state.cache.contracts.len();
|
||||
|
||||
// Record all state present in the cache state as loaded even though some might have
|
||||
// been newly created.
|
||||
// TODO: Consider spitting these into loaded and newly created.
|
||||
self.accounts_loaded_histogram.record(accounts as f64);
|
||||
self.storage_slots_loaded_histogram.record(storage_slots as f64);
|
||||
self.bytecodes_loaded_histogram.record(bytecodes as f64);
|
||||
})
|
||||
})?;
|
||||
|
||||
// Update the metrics for the number of accounts, storage slots and bytecodes updated
|
||||
let accounts = output.state.state.len();
|
||||
let storage_slots =
|
||||
output.state.state.values().map(|account| account.storage.len()).sum::<usize>();
|
||||
let bytecodes = output.state.contracts.len();
|
||||
|
||||
self.accounts_updated_histogram.record(accounts as f64);
|
||||
self.storage_slots_updated_histogram.record(storage_slots as f64);
|
||||
self.bytecodes_updated_histogram.record(bytecodes as f64);
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Execute the given block and update metrics for the execution.
|
||||
pub fn metered_one<F, R>(&self, input: BlockExecutionInput<'_, BlockWithSenders>, f: F) -> R
|
||||
where
|
||||
F: FnOnce(BlockExecutionInput<'_, BlockWithSenders>) -> R,
|
||||
{
|
||||
self.metered(input.block, || f(input))
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ impl<DB> Executor<DB> for NoopBlockExecutorProvider {
|
||||
Err(BlockExecutionError::msg(UNAVAILABLE_FOR_NOOP))
|
||||
}
|
||||
|
||||
fn execute_with_state_witness<F>(
|
||||
fn execute_with_state_closure<F>(
|
||||
self,
|
||||
_: Self::Input<'_>,
|
||||
_: F,
|
||||
|
||||
@ -66,26 +66,26 @@ impl<DB> Executor<DB> for MockExecutorProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn execute_with_state_witness<F>(
|
||||
fn execute_with_state_closure<F>(
|
||||
self,
|
||||
_: Self::Input<'_>,
|
||||
input: Self::Input<'_>,
|
||||
_: F,
|
||||
) -> Result<Self::Output, Self::Error>
|
||||
where
|
||||
F: FnMut(&State<DB>),
|
||||
{
|
||||
unimplemented!()
|
||||
<Self as Executor<DB>>::execute(self, input)
|
||||
}
|
||||
|
||||
fn execute_with_state_hook<F>(
|
||||
self,
|
||||
_: Self::Input<'_>,
|
||||
input: Self::Input<'_>,
|
||||
_: F,
|
||||
) -> Result<Self::Output, Self::Error>
|
||||
where
|
||||
F: OnStateHook,
|
||||
{
|
||||
unimplemented!()
|
||||
<Self as Executor<DB>>::execute(self, input)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user