diff --git a/substrate/client/db/src/bench.rs b/substrate/client/db/src/bench.rs index f0c187bd37..2704676207 100644 --- a/substrate/client/db/src/bench.rs +++ b/substrate/client/db/src/bench.rs @@ -23,7 +23,7 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; use hash_db::{Prefix, Hasher}; -use sp_trie::{MemoryDB, prefixed_key}; +use sp_trie::{MemoryDB, prefixed_key, StorageProof}; use sp_core::{ storage::{ChildInfo, TrackedStorageKey}, hexdisplay::HexDisplay @@ -31,9 +31,10 @@ use sp_core::{ use sp_runtime::traits::{Block as BlockT, HashFor}; use sp_runtime::Storage; use sp_state_machine::{ - DBValue, backend::Backend as StateBackend, StorageCollection, ChildStorageCollection + DBValue, backend::Backend as StateBackend, StorageCollection, ChildStorageCollection, ProofRecorder, }; use kvdb::{KeyValueDB, DBTransaction}; +use codec::Encode; use crate::storage_cache::{CachingState, SharedCache, new_shared_cache}; type DbState = sp_state_machine::TrieBackend< @@ -44,14 +45,25 @@ type State = CachingState, B>; struct StorageDb { db: Arc, + proof_recorder: Option>>, _block: std::marker::PhantomData, } impl sp_state_machine::Storage> for StorageDb { fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result, String> { - let key = prefixed_key::>(key, prefix); - self.db.get(0, &key) - .map_err(|e| format!("Database backend error: {:?}", e)) + let prefixed_key = prefixed_key::>(key, prefix); + if let Some(recorder) = &self.proof_recorder { + if let Some(v) = recorder.read().get(&key) { + return Ok(v.clone()); + } + let backend_value = self.db.get(0, &prefixed_key) + .map_err(|e| format!("Database backend error: {:?}", e))?; + recorder.write().insert(key.clone(), backend_value.clone()); + Ok(backend_value) + } else { + self.db.get(0, &prefixed_key) + .map_err(|e| format!("Database backend error: {:?}", e)) + } } } @@ -105,11 +117,12 @@ pub struct BenchmarkingState { child_key_tracker: RefCell, HashMap, KeyTracker>>>, read_write_tracker: RefCell, whitelist: RefCell>, + proof_recorder: Option>>, } impl BenchmarkingState { /// Create a new instance that creates a database in a temporary dir. - pub fn new(genesis: Storage, _cache_size_mb: Option) -> Result { + pub fn new(genesis: Storage, _cache_size_mb: Option, record_proof: bool) -> Result { let mut root = B::Hash::default(); let mut mdb = MemoryDB::>::default(); sp_state_machine::TrieDBMut::>::new(&mut mdb, &mut root); @@ -126,6 +139,7 @@ impl BenchmarkingState { child_key_tracker: Default::default(), read_write_tracker: Default::default(), whitelist: Default::default(), + proof_recorder: record_proof.then(Default::default), }; state.add_whitelist_to_tracker(); @@ -153,7 +167,14 @@ impl BenchmarkingState { None => Arc::new(::kvdb_memorydb::create(1)), }; self.db.set(Some(db.clone())); - let storage_db = Arc::new(StorageDb:: { db, _block: Default::default() }); + if let Some(recorder) = &self.proof_recorder { + recorder.write().clear(); + } + let storage_db = Arc::new(StorageDb:: { + db, + proof_recorder: self.proof_recorder.clone(), + _block: Default::default() + }); *self.state.borrow_mut() = Some(State::new( DbState::::new(storage_db, self.root.get()), self.shared_cache.clone(), @@ -495,6 +516,17 @@ impl StateBackend> for BenchmarkingState { fn usage_info(&self) -> sp_state_machine::UsageInfo { self.state.borrow().as_ref().map_or(sp_state_machine::UsageInfo::empty(), |s| s.usage_info()) } + + fn proof_size(&self) -> Option { + self.proof_recorder.as_ref().map(|recorder| { + let proof = StorageProof::new(recorder + .read() + .iter() + .filter_map(|(_k, v)| v.as_ref().map(|v| v.to_vec())) + .collect()); + proof.encoded_size() as u32 + }) + } } impl std::fmt::Debug for BenchmarkingState { @@ -510,7 +542,7 @@ mod test { #[test] fn read_to_main_and_child_tries() { - let bench_state = BenchmarkingState::::new(Default::default(), None) + let bench_state = BenchmarkingState::::new(Default::default(), None, false) .unwrap(); for _ in 0..2 { diff --git a/substrate/frame/benchmarking/src/analysis.rs b/substrate/frame/benchmarking/src/analysis.rs index a9657fd7b1..7b6d8838fd 100644 --- a/substrate/frame/benchmarking/src/analysis.rs +++ b/substrate/frame/benchmarking/src/analysis.rs @@ -38,6 +38,7 @@ pub enum BenchmarkSelector { StorageRootTime, Reads, Writes, + ProofSize, } #[derive(Debug)] @@ -86,6 +87,7 @@ impl Analysis { BenchmarkSelector::StorageRootTime => result.storage_root_time, BenchmarkSelector::Reads => result.reads.into(), BenchmarkSelector::Writes => result.writes.into(), + BenchmarkSelector::ProofSize => result.proof_size.into(), } ).collect(); @@ -126,6 +128,7 @@ impl Analysis { BenchmarkSelector::StorageRootTime => result.storage_root_time, BenchmarkSelector::Reads => result.reads.into(), BenchmarkSelector::Writes => result.writes.into(), + BenchmarkSelector::ProofSize => result.proof_size.into(), }; (result.components[i].1, data) }) @@ -190,6 +193,7 @@ impl Analysis { BenchmarkSelector::StorageRootTime => result.storage_root_time, BenchmarkSelector::Reads => result.reads.into(), BenchmarkSelector::Writes => result.writes.into(), + BenchmarkSelector::ProofSize => result.proof_size.into(), }) } @@ -370,6 +374,7 @@ mod tests { repeat_reads: 0, writes, repeat_writes: 0, + proof_size: 0, } } diff --git a/substrate/frame/benchmarking/src/lib.rs b/substrate/frame/benchmarking/src/lib.rs index b134e79ca2..ea1bfbd681 100644 --- a/substrate/frame/benchmarking/src/lib.rs +++ b/substrate/frame/benchmarking/src/lib.rs @@ -764,12 +764,21 @@ macro_rules! impl_benchmark { "Start Benchmark: {:?}", c ); + let start_pov = $crate::benchmarking::proof_size(); let start_extrinsic = $crate::benchmarking::current_time(); closure_to_benchmark()?; let finish_extrinsic = $crate::benchmarking::current_time(); - let elapsed_extrinsic = finish_extrinsic - start_extrinsic; + let end_pov = $crate::benchmarking::proof_size(); + + // Calculate the diff caused by the benchmark. + let elapsed_extrinsic = finish_extrinsic.saturating_sub(start_extrinsic); + let diff_pov = match (start_pov, end_pov) { + (Some(start), Some(end)) => end.saturating_sub(start), + _ => Default::default(), + }; + // Commit the changes to get proper write count $crate::benchmarking::commit_db(); $crate::log::trace!( @@ -796,6 +805,7 @@ macro_rules! impl_benchmark { repeat_reads: read_write_count.1, writes: read_write_count.2, repeat_writes: read_write_count.3, + proof_size: diff_pov, }); } diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index 1574e47454..2db7b2e95d 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -62,6 +62,7 @@ pub struct BenchmarkResults { pub repeat_reads: u32, pub writes: u32, pub repeat_writes: u32, + pub proof_size: u32, } /// Configuration used to setup and run runtime benchmarks. @@ -162,6 +163,11 @@ pub trait Benchmarking { whitelist.retain(|x| x.key != remove); self.set_whitelist(whitelist); } + + /// Get current estimated proof size. + fn proof_size(&self) -> Option { + self.proof_size() + } } /// The pallet benchmarking trait. diff --git a/substrate/primitives/externalities/src/lib.rs b/substrate/primitives/externalities/src/lib.rs index 1077f41048..c90881b76e 100644 --- a/substrate/primitives/externalities/src/lib.rs +++ b/substrate/primitives/externalities/src/lib.rs @@ -281,6 +281,16 @@ pub trait Externalities: ExtensionStore { /// /// Adds new storage keys to the DB tracking whitelist. fn set_whitelist(&mut self, new: Vec); + + /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + /// Benchmarking related functionality and shouldn't be used anywhere else! + /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + /// + /// Returns estimated proof size for the state queries so far. + /// Proof is reset on commit and wipe. + fn proof_size(&self) -> Option { + None + } } /// Extension for the [`Externalities`] trait. diff --git a/substrate/primitives/state-machine/src/backend.rs b/substrate/primitives/state-machine/src/backend.rs index eb1c566c6d..1a8892f8dd 100644 --- a/substrate/primitives/state-machine/src/backend.rs +++ b/substrate/primitives/state-machine/src/backend.rs @@ -245,6 +245,11 @@ pub trait Backend: sp_std::fmt::Debug { /// Update the whitelist for tracking db reads/writes fn set_whitelist(&self, _: Vec) {} + + /// Estimate proof size + fn proof_size(&self) -> Option { + unimplemented!() + } } impl<'a, T: Backend, H: Hasher> Backend for &'a T { diff --git a/substrate/primitives/state-machine/src/ext.rs b/substrate/primitives/state-machine/src/ext.rs index 65b7b638a9..424a3c6c42 100644 --- a/substrate/primitives/state-machine/src/ext.rs +++ b/substrate/primitives/state-machine/src/ext.rs @@ -712,6 +712,10 @@ where fn set_whitelist(&mut self, new: Vec) { self.backend.set_whitelist(new) } + + fn proof_size(&self) -> Option { + self.backend.proof_size() + } } /// Implement `Encode` by forwarding the stored raw vec. diff --git a/substrate/utils/frame/benchmarking-cli/src/command.rs b/substrate/utils/frame/benchmarking-cli/src/command.rs index 146b0aa841..80d95d1c86 100644 --- a/substrate/utils/frame/benchmarking-cli/src/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/command.rs @@ -63,7 +63,7 @@ impl BenchmarkCmd { let genesis_storage = spec.build_storage()?; let mut changes = Default::default(); let cache_size = Some(self.database_cache_size as usize); - let state = BenchmarkingState::::new(genesis_storage, cache_size)?; + let state = BenchmarkingState::::new(genesis_storage, cache_size, self.record_proof)?; let executor = NativeExecutor::::new( wasm_method, self.heap_pages, @@ -126,19 +126,20 @@ impl BenchmarkCmd { // Print the table header batch.results[0].components.iter().for_each(|param| print!("{:?},", param.0)); - print!("extrinsic_time,storage_root_time,reads,repeat_reads,writes,repeat_writes\n"); + print!("extrinsic_time_ns,storage_root_time_ns,reads,repeat_reads,writes,repeat_writes,proof_size_bytes\n"); // Print the values batch.results.iter().for_each(|result| { let parameters = &result.components; parameters.iter().for_each(|param| print!("{:?},", param.1)); // Print extrinsic time and storage root time - print!("{:?},{:?},{:?},{:?},{:?},{:?}\n", + print!("{:?},{:?},{:?},{:?},{:?},{:?},{:?}\n", result.extrinsic_time, result.storage_root_time, result.reads, result.repeat_reads, result.writes, result.repeat_writes, + result.proof_size, ); }); diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 6784b1ecab..9862a5a5b8 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -97,6 +97,10 @@ pub struct BenchmarkCmd { #[structopt(long)] pub extra: bool, + /// Estimate PoV size. + #[structopt(long)] + pub record_proof: bool, + #[allow(missing_docs)] #[structopt(flatten)] pub shared_params: sc_cli::SharedParams, diff --git a/substrate/utils/frame/benchmarking-cli/src/writer.rs b/substrate/utils/frame/benchmarking-cli/src/writer.rs index aeed6ea1c9..6fd6cc6eef 100644 --- a/substrate/utils/frame/benchmarking-cli/src/writer.rs +++ b/substrate/utils/frame/benchmarking-cli/src/writer.rs @@ -421,6 +421,7 @@ mod test { repeat_reads: 0, writes: (base + slope * i).into(), repeat_writes: 0, + proof_size: 0, } ) }