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

Commit

Permalink
Add PoV Tracking to Benchmarking Pipeline (#8559)
Browse files Browse the repository at this point in the history
* Added a function to estimate proof size for benchmarking

* integrate proof_size into benchmarking pipeline

* Update client/db/src/bench.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/db/src/bench.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* fix tests

* one more test

* Update bench.rs

* Update utils/frame/benchmarking-cli/src/writer.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update utils/frame/benchmarking-cli/src/command.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

Co-authored-by: arkpar <arkady.paronyan@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
  • Loading branch information
5 people authored Apr 8, 2021
1 parent 05445dc commit fea6aa2
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 12 deletions.
48 changes: 40 additions & 8 deletions client/db/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ 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
};
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<B> = sp_state_machine::TrieBackend<
Expand All @@ -44,14 +45,25 @@ type State<B> = CachingState<DbState<B>, B>;

struct StorageDb<Block: BlockT> {
db: Arc<dyn KeyValueDB>,
proof_recorder: Option<ProofRecorder<HashFor<Block>>>,
_block: std::marker::PhantomData<Block>,
}

impl<Block: BlockT> sp_state_machine::Storage<HashFor<Block>> for StorageDb<Block> {
fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result<Option<DBValue>, String> {
let key = prefixed_key::<HashFor<Block>>(key, prefix);
self.db.get(0, &key)
.map_err(|e| format!("Database backend error: {:?}", e))
let prefixed_key = prefixed_key::<HashFor<Block>>(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))
}
}
}

Expand Down Expand Up @@ -105,11 +117,12 @@ pub struct BenchmarkingState<B: BlockT> {
child_key_tracker: RefCell<HashMap<Vec<u8>, HashMap<Vec<u8>, KeyTracker>>>,
read_write_tracker: RefCell<ReadWriteTracker>,
whitelist: RefCell<Vec<TrackedStorageKey>>,
proof_recorder: Option<ProofRecorder<HashFor<B>>>,
}

impl<B: BlockT> BenchmarkingState<B> {
/// Create a new instance that creates a database in a temporary dir.
pub fn new(genesis: Storage, _cache_size_mb: Option<usize>) -> Result<Self, String> {
pub fn new(genesis: Storage, _cache_size_mb: Option<usize>, record_proof: bool) -> Result<Self, String> {
let mut root = B::Hash::default();
let mut mdb = MemoryDB::<HashFor<B>>::default();
sp_state_machine::TrieDBMut::<HashFor<B>>::new(&mut mdb, &mut root);
Expand All @@ -126,6 +139,7 @@ impl<B: BlockT> BenchmarkingState<B> {
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();
Expand Down Expand Up @@ -153,7 +167,14 @@ impl<B: BlockT> BenchmarkingState<B> {
None => Arc::new(::kvdb_memorydb::create(1)),
};
self.db.set(Some(db.clone()));
let storage_db = Arc::new(StorageDb::<B> { db, _block: Default::default() });
if let Some(recorder) = &self.proof_recorder {
recorder.write().clear();
}
let storage_db = Arc::new(StorageDb::<B> {
db,
proof_recorder: self.proof_recorder.clone(),
_block: Default::default()
});
*self.state.borrow_mut() = Some(State::new(
DbState::<B>::new(storage_db, self.root.get()),
self.shared_cache.clone(),
Expand Down Expand Up @@ -495,6 +516,17 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
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<u32> {
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<Block: BlockT> std::fmt::Debug for BenchmarkingState<Block> {
Expand All @@ -510,7 +542,7 @@ mod test {

#[test]
fn read_to_main_and_child_tries() {
let bench_state = BenchmarkingState::<crate::tests::Block>::new(Default::default(), None)
let bench_state = BenchmarkingState::<crate::tests::Block>::new(Default::default(), None, false)
.unwrap();

for _ in 0..2 {
Expand Down
5 changes: 5 additions & 0 deletions frame/benchmarking/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum BenchmarkSelector {
StorageRootTime,
Reads,
Writes,
ProofSize,
}

#[derive(Debug)]
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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)
})
Expand Down Expand Up @@ -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(),
})
}

Expand Down Expand Up @@ -370,6 +374,7 @@ mod tests {
repeat_reads: 0,
writes,
repeat_writes: 0,
proof_size: 0,
}
}

Expand Down
12 changes: 11 additions & 1 deletion frame/benchmarking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand All @@ -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,
});
}

Expand Down
6 changes: 6 additions & 0 deletions frame/benchmarking/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<u32> {
self.proof_size()
}
}

/// The pallet benchmarking trait.
Expand Down
10 changes: 10 additions & 0 deletions primitives/externalities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,16 @@ pub trait Externalities: ExtensionStore {
///
/// Adds new storage keys to the DB tracking whitelist.
fn set_whitelist(&mut self, new: Vec<TrackedStorageKey>);

/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// 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<u32> {
None
}
}

/// Extension for the [`Externalities`] trait.
Expand Down
5 changes: 5 additions & 0 deletions primitives/state-machine/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {

/// Update the whitelist for tracking db reads/writes
fn set_whitelist(&self, _: Vec<TrackedStorageKey>) {}

/// Estimate proof size
fn proof_size(&self) -> Option<u32> {
unimplemented!()
}
}

impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
Expand Down
4 changes: 4 additions & 0 deletions primitives/state-machine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,10 @@ where
fn set_whitelist(&mut self, new: Vec<TrackedStorageKey>) {
self.backend.set_whitelist(new)
}

fn proof_size(&self) -> Option<u32> {
self.backend.proof_size()
}
}

/// Implement `Encode` by forwarding the stored raw vec.
Expand Down
7 changes: 4 additions & 3 deletions utils/frame/benchmarking-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<BB>::new(genesis_storage, cache_size)?;
let state = BenchmarkingState::<BB>::new(genesis_storage, cache_size, self.record_proof)?;
let executor = NativeExecutor::<ExecDispatch>::new(
wasm_method,
self.heap_pages,
Expand Down Expand Up @@ -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,
);
});

Expand Down
4 changes: 4 additions & 0 deletions utils/frame/benchmarking-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions utils/frame/benchmarking-cli/src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ mod test {
repeat_reads: 0,
writes: (base + slope * i).into(),
repeat_writes: 0,
proof_size: 0,
}
)
}
Expand Down

0 comments on commit fea6aa2

Please sign in to comment.