State metrics possible changes (#5168)

* Registering state from overlay.

* fix

* fix2

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
cheme
2020-04-01 19:46:40 +02:00
committed by GitHub
parent a8aedfa16f
commit 58578af074
17 changed files with 232 additions and 33 deletions
@@ -206,13 +206,16 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
(root, txs)
}
/// Register stats from overlay of state machine.
///
/// By default nothing is registered.
fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats);
/// Query backend usage statistics (i/o, memory)
///
/// Not all implementations are expected to be able to do this. In the
/// case when they don't, empty statistics is returned.
fn usage_info(&self) -> UsageInfo {
UsageInfo::empty()
}
fn usage_info(&self) -> UsageInfo;
/// Wipe the state database.
fn wipe(&self) -> Result<(), Self::Error> {
@@ -308,10 +311,12 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
(*self).for_key_values_with_prefix(prefix, f);
}
fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats) { }
fn usage_info(&self) -> UsageInfo {
(*self).usage_info()
}
}
}
/// Trait that allows consolidate two transactions together.
pub trait Consolidate {
@@ -469,6 +469,7 @@ mod test {
].into_iter().collect(),
},
collect_extrinsics: true,
stats: Default::default(),
};
let config = Configuration { digest_interval: 4, digest_levels: 2 };
@@ -587,6 +587,7 @@ mod tests {
].into_iter().collect(),
committed: Default::default(),
collect_extrinsics: true,
stats: Default::default(),
}
}
@@ -20,6 +20,7 @@ use crate::{
StorageKey, StorageValue, StorageCollection,
trie_backend::TrieBackend,
backend::{Backend, insert_into_memory_db},
stats::UsageInfo,
};
use std::{error, fmt, collections::{BTreeMap, HashMap}, marker::PhantomData, ops};
use hash_db::Hasher;
@@ -357,6 +358,12 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
self.trie = Some(TrieBackend::new(mdb, root));
self.trie.as_ref()
}
fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats) { }
fn usage_info(&self) -> UsageInfo {
UsageInfo::empty()
}
}
#[cfg(test)]
+14 -4
View File
@@ -18,7 +18,7 @@
#![warn(missing_docs)]
use std::{fmt, result, collections::HashMap, panic::UnwindSafe, marker::PhantomData};
use std::{fmt, result, collections::HashMap, panic::UnwindSafe};
use log::{warn, trace};
use hash_db::Hasher;
use codec::{Decode, Encode, Codec};
@@ -73,7 +73,7 @@ pub use trie_backend_essence::{TrieBackendStorage, Storage};
pub use trie_backend::TrieBackend;
pub use error::{Error, ExecutionError};
pub use in_memory_backend::InMemory as InMemoryBackend;
pub use stats::{UsageInfo, UsageUnit};
pub use stats::{UsageInfo, UsageUnit, StateMachineStats};
pub use sp_core::traits::CloneableSpawn;
type CallResult<R, E> = Result<NativeOrEncoded<R>, E>;
@@ -189,9 +189,19 @@ pub struct StateMachine<'a, B, H, N, Exec>
overlay: &'a mut OverlayedChanges,
extensions: Extensions,
changes_trie_state: Option<ChangesTrieState<'a, H, N>>,
_marker: PhantomData<(H, N)>,
storage_transaction_cache: Option<&'a mut StorageTransactionCache<B::Transaction, H, N>>,
runtime_code: &'a RuntimeCode<'a>,
stats: StateMachineStats,
}
impl<'a, B, H, N, Exec> Drop for StateMachine<'a, B, H, N, Exec> where
H: Hasher,
B: Backend<H>,
N: ChangesTrieBlockNumber,
{
fn drop(&mut self) {
self.backend.register_overlay_stats(&self.stats);
}
}
impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
@@ -224,9 +234,9 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
extensions,
overlay,
changes_trie_state,
_marker: PhantomData,
storage_transaction_cache: None,
runtime_code,
stats: StateMachineStats::default(),
}
}
@@ -22,6 +22,7 @@ use crate::{
NO_EXTRINSIC_INDEX, BlockNumber, build_changes_trie,
State as ChangesTrieState,
},
stats::StateMachineStats,
};
#[cfg(test)]
@@ -57,6 +58,8 @@ pub struct OverlayedChanges {
pub(crate) committed: OverlayedChangeSet,
/// True if extrinsics stats must be collected.
pub(crate) collect_extrinsics: bool,
/// Collect statistic on this execution.
pub(crate) stats: StateMachineStats,
}
/// The storage value, used inside OverlayedChanges.
@@ -206,7 +209,11 @@ impl OverlayedChanges {
pub fn storage(&self, key: &[u8]) -> Option<Option<&[u8]>> {
self.prospective.top.get(key)
.or_else(|| self.committed.top.get(key))
.map(|x| x.value.as_ref().map(AsRef::as_ref))
.map(|x| {
let size_read = x.value.as_ref().map(|x| x.len() as u64).unwrap_or(0);
self.stats.tally_read_modified(size_read);
x.value.as_ref().map(AsRef::as_ref)
})
}
/// Returns a double-Option: None if the key is unknown (i.e. and the query should be referred
@@ -215,12 +222,16 @@ impl OverlayedChanges {
pub fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option<Option<&[u8]>> {
if let Some(map) = self.prospective.children.get(storage_key) {
if let Some(val) = map.0.get(key) {
let size_read = val.value.as_ref().map(|x| x.len() as u64).unwrap_or(0);
self.stats.tally_read_modified(size_read);
return Some(val.value.as_ref().map(AsRef::as_ref));
}
}
if let Some(map) = self.committed.children.get(storage_key) {
if let Some(val) = map.0.get(key) {
let size_read = val.value.as_ref().map(|x| x.len() as u64).unwrap_or(0);
self.stats.tally_read_modified(size_read);
return Some(val.value.as_ref().map(AsRef::as_ref));
}
}
@@ -232,6 +243,8 @@ impl OverlayedChanges {
///
/// `None` can be used to delete a value specified by the given key.
pub(crate) fn set_storage(&mut self, key: StorageKey, val: Option<StorageValue>) {
let size_write = val.as_ref().map(|x| x.len() as u64).unwrap_or(0);
self.stats.tally_write_overlay(size_write);
let extrinsic_index = self.extrinsic_index();
let entry = self.prospective.top.entry(key).or_default();
entry.value = val;
@@ -252,6 +265,8 @@ impl OverlayedChanges {
key: StorageKey,
val: Option<StorageValue>,
) {
let size_write = val.as_ref().map(|x| x.len() as u64).unwrap_or(0);
self.stats.tally_write_overlay(size_write);
let extrinsic_index = self.extrinsic_index();
let map_entry = self.prospective.children.entry(storage_key)
.or_insert_with(|| (Default::default(), child_info.to_owned()));
@@ -283,6 +283,12 @@ impl<'a, S, H> Backend<H> for ProvingBackend<'a, S, H>
{
self.0.child_storage_root(storage_key, child_info, delta)
}
fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats) { }
fn usage_info(&self) -> crate::stats::UsageInfo {
self.0.usage_info()
}
}
/// Create proof check backend.
@@ -17,6 +17,7 @@
//! Usage statistics for state db
use std::time::{Instant, Duration};
use std::cell::RefCell;
/// Measured count of operations and total bytes.
#[derive(Clone, Debug, Default)]
@@ -32,10 +33,19 @@ pub struct UsageUnit {
pub struct UsageInfo {
/// Read statistics (total).
pub reads: UsageUnit,
/// Write statistics.
/// Write statistics (total).
pub writes: UsageUnit,
/// Write trie nodes statistics.
pub nodes_writes: UsageUnit,
/// Write into cached state machine
/// change overlay.
pub overlay_writes: UsageUnit,
/// Removed trie nodes statistics.
pub removed_nodes: UsageUnit,
/// Cache read statistics.
pub cache_reads: UsageUnit,
/// Modified value read statistics.
pub modified_reads: UsageUnit,
/// Memory used.
pub memory: usize,
@@ -45,6 +55,35 @@ pub struct UsageInfo {
pub span: Duration,
}
/// Accumulated usage statistics specific to state machine
/// crate.
#[derive(Debug, Default, Clone)]
pub struct StateMachineStats {
/// Number of read query from runtime
/// that hit a modified value (in state
/// machine overlay).
pub reads_modified: RefCell<u64>,
/// Size in byte of read queries that
/// hit a modified value.
pub bytes_read_modified: RefCell<u64>,
/// Number of time a write operation
/// occurs into the state machine overlay.
pub writes_overlay: RefCell<u64>,
/// Size in bytes of the writes overlay
/// operation.
pub bytes_writes_overlay: RefCell<u64>,
}
impl StateMachineStats {
/// Accumulates some registered stats.
pub fn add(&self, other: &StateMachineStats) {
*self.reads_modified.borrow_mut() += *other.reads_modified.borrow();
*self.bytes_read_modified.borrow_mut() += *other.bytes_read_modified.borrow();
*self.writes_overlay.borrow_mut() += *other.writes_overlay.borrow();
*self.bytes_writes_overlay.borrow_mut() += *other.bytes_writes_overlay.borrow();
}
}
impl UsageInfo {
/// Empty statistics.
///
@@ -53,10 +92,34 @@ impl UsageInfo {
Self {
reads: UsageUnit::default(),
writes: UsageUnit::default(),
overlay_writes: UsageUnit::default(),
nodes_writes: UsageUnit::default(),
removed_nodes: UsageUnit::default(),
cache_reads: UsageUnit::default(),
modified_reads: UsageUnit::default(),
memory: 0,
started: Instant::now(),
span: Default::default(),
}
}
/// Add collected state machine to this state.
pub fn include_state_machine_states(&mut self, count: &StateMachineStats) {
self.modified_reads.ops += *count.reads_modified.borrow();
self.modified_reads.bytes += *count.bytes_read_modified.borrow();
self.overlay_writes.ops += *count.writes_overlay.borrow();
self.overlay_writes.bytes += *count.bytes_writes_overlay.borrow();
}
}
impl StateMachineStats {
/// Tally one read modified operation, of some length.
pub fn tally_read_modified(&self, data_bytes: u64) {
*self.reads_modified.borrow_mut() += 1;
*self.bytes_read_modified.borrow_mut() += data_bytes;
}
/// Tally one write overlay operation, of some length.
pub fn tally_write_overlay(&self, data_bytes: u64) {
*self.writes_overlay.borrow_mut() += 1;
*self.bytes_writes_overlay.borrow_mut() += data_bytes;
}
}
@@ -240,6 +240,12 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, H>> {
Some(self)
}
fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats) { }
fn usage_info(&self) -> crate::UsageInfo {
crate::UsageInfo::empty()
}
}
#[cfg(test)]