From ea9a711b3112c7c18574511cfc68350960d45f9e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 16 Feb 2020 12:57:52 +0300 Subject: [PATCH 1/6] reorganize and optimize --- bin/node/testing/benches/import.rs | 327 +++++++++++++++-------------- 1 file changed, 172 insertions(+), 155 deletions(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index 86092a7836015..929e0981fa679 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -92,10 +92,169 @@ fn genesis(keyring: &BenchKeyring) -> node_runtime::GenesisConfig { // //endowed-user//01 // ... // //endowed-user//N +#[derive(Clone)] struct BenchKeyring { accounts: BTreeMap, } +// This is prepared database with genesis and keyring +// that can be cloned and then used for any benchmarking. +struct BenchDb { + random_space: usize, + keyring: BenchKeyring, + directory_guard: Guard, +} + +impl Clone for BenchDb { + fn clone(&self) -> Self { + let random_space = self.random_space; + let keyring = self.keyring.clone(); + let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); + + let seed_dir = self.directory_guard.0.path(); + + log::trace!( + target: "bench-logistics", + "Copying seed db from {} to {}", + seed_dir.to_string_lossy(), + dir.path().to_string_lossy(), + ); + let seed_db_files = std::fs::read_dir(seed_dir) + .expect("failed to list file in seed dir") + .map(|f_result| + f_result.expect("failed to read file in seed db") + .path() + .clone() + ).collect(); + fs_extra::copy_items( + &seed_db_files, + dir.path(), + &fs_extra::dir::CopyOptions::new(), + ).expect("Copy of seed database is ok"); + + BenchDb { keyring, directory_guard: Guard(dir), random_space } + } +} + +impl BenchDb { + + fn new(random_space: usize) -> Self { + let keyring = BenchKeyring::new(random_space); + + let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); + log::trace!( + target: "bench-logistics", + "Created seed db at {}", + dir.path().to_string_lossy(), + ); + let (_client, _backend) = bench_client(dir.path(), Profile::Native, &keyring); + let directory_guard = Guard(dir); + + BenchDb { keyring, random_space, directory_guard } + } + + fn generate_block(&mut self) -> Block { + let (client, _backend) = bench_client( + self.directory_guard.path(), + Profile::Wasm, + &self.keyring + ); + + let version = client.runtime_version_at(&BlockId::number(0)) + .expect("There should be runtime version at 0") + .spec_version; + + let genesis_hash = client.block_hash(Zero::zero()) + .expect("Database error?") + .expect("Genesis block always exists; qed") + .into(); + + let mut block = client + .new_block(Default::default()) + .expect("Block creation failed"); + + let timestamp = 1 * MinimumPeriod::get(); + + let mut inherent_data = InherentData::new(); + inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp) + .expect("Put timestamb failed"); + inherent_data.put_data(sp_finality_tracker::INHERENT_IDENTIFIER, &0) + .expect("Put finality tracker failed"); + + for extrinsic in client.runtime_api() + .inherent_extrinsics_with_context( + &BlockId::number(0), + ExecutionContext::BlockConstruction, + inherent_data, + ).expect("Get inherents failed") + { + block.push(extrinsic).expect("Push inherent failed"); + } + + let mut iteration = 0; + let start = std::time::Instant::now(); + for _ in 0..100 { + + let sender = self.keyring.at(iteration); + let receiver = get_account_id_from_seed::( + &format!("random-user//{}", iteration) + ); + + let signed = self.keyring.sign( + CheckedExtrinsic { + signed: Some((sender, signed_extra(0, 1*DOLLARS))), + function: Call::Balances( + BalancesCall::transfer( + pallet_indices::address::Address::Id(receiver), + 1*DOLLARS + ) + ), + }, + version, + genesis_hash, + ); + + let encoded = Encode::encode(&signed); + + let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]) + .expect("Failed to decode opaque"); + + match block.push(opaque) { + Err(sp_blockchain::Error::ApplyExtrinsicFailed( + sp_blockchain::ApplyExtrinsicFailed::Validity(e) + )) if e.exhausted_resources() => { + break; + }, + Err(err) => panic!("Error pushing transaction: {:?}", err), + Ok(_) => {}, + } + iteration += 1; + } + let block = block.build().expect("Block build failed").block; + + log::info!( + target: "bench-logistics", + "Block construction: {:#?} ({} tx)", + start.elapsed(), block.extrinsics.len() + ); + + block + } + + fn path(&self) -> &Path { + self.directory_guard.path() + } + + fn create_context(&self, profile: Profile) -> BenchContext { + let BenchDb { directory_guard, keyring, .. } = self.clone(); + let (client, backend) = bench_client(directory_guard.path(), profile, &keyring); + + BenchContext { + client, backend, db_guard: directory_guard, + } + } +} + impl BenchKeyring { fn new(num: usize) -> Self { let mut accounts = BTreeMap::new(); @@ -200,63 +359,16 @@ fn bench_client(dir: &std::path::Path, profile: Profile, keyring: &BenchKeyring) struct Guard(tempdir::TempDir); +impl Guard { + fn path(&self) -> &Path { + self.0.path() + } +} + struct BenchContext { client: Client, backend: Arc, db_guard: Guard, - keyring: BenchKeyring, -} - -impl BenchContext { - fn new(profile: Profile) -> BenchContext { - let keyring = BenchKeyring::new(128); - - let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); - log::trace!( - target: "bench-logistics", - "Created seed db at {}", - dir.path().to_string_lossy(), - ); - let (client, backend) = bench_client(dir.path(), profile, &keyring); - let db_guard = Guard(dir); - - - BenchContext { client, backend, db_guard, keyring } - } - - fn new_from_seed(profile: Profile, seed_dir: &Path) -> BenchContext { - let keyring = BenchKeyring::new(128); - - let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); - - log::trace!( - target: "bench-logistics", - "Copying seed db from {} to {}", - seed_dir.to_string_lossy(), - dir.path().to_string_lossy(), - ); - let seed_db_files = std::fs::read_dir(seed_dir) - .expect("failed to list file in seed dir") - .map(|f_result| - f_result.expect("failed to read file in seed db") - .path() - .clone() - ).collect(); - fs_extra::copy_items( - &seed_db_files, - dir.path(), - &fs_extra::dir::CopyOptions::new(), - ).expect("Copy of seed database is ok"); - - let (client, backend) = bench_client(dir.path(), profile, &keyring); - let db_guard = Guard(dir); - - BenchContext { client, backend, db_guard, keyring } - } - - fn keep_db(self) -> Guard { - self.db_guard - } } type AccountPublic = ::Signer; @@ -274,88 +386,6 @@ where AccountPublic::from(get_from_seed::(seed)).into_account() } -// Block generation. -fn generate_block_import(client: &Client, keyring: &BenchKeyring) -> Block { - let version = client.runtime_version_at(&BlockId::number(0)) - .expect("There should be runtime version at 0") - .spec_version; - let genesis_hash = client.block_hash(Zero::zero()) - .expect("Database error?") - .expect("Genesis block always exists; qed") - .into(); - - let mut block = client - .new_block(Default::default()) - .expect("Block creation failed"); - - let timestamp = 1 * MinimumPeriod::get(); - - let mut inherent_data = InherentData::new(); - inherent_data.put_data(sp_timestamp::INHERENT_IDENTIFIER, ×tamp) - .expect("Put timestamb failed"); - inherent_data.put_data(sp_finality_tracker::INHERENT_IDENTIFIER, &0) - .expect("Put finality tracker failed"); - - for extrinsic in client.runtime_api() - .inherent_extrinsics_with_context( - &BlockId::number(0), - ExecutionContext::BlockConstruction, - inherent_data, - ).expect("Get inherents failed") - { - block.push(extrinsic).expect("Push inherent failed"); - } - - let mut iteration = 0; - let start = std::time::Instant::now(); - for _ in 0..100 { - - let sender = keyring.at(iteration); - let receiver = get_account_id_from_seed::( - &format!("random-user//{}", iteration) - ); - - let signed = keyring.sign( - CheckedExtrinsic { - signed: Some((sender, signed_extra(0, 1*DOLLARS))), - function: Call::Balances( - BalancesCall::transfer( - pallet_indices::address::Address::Id(receiver), - 1*DOLLARS - ) - ), - }, - version, - genesis_hash, - ); - - let encoded = Encode::encode(&signed); - - let opaque = OpaqueExtrinsic::decode(&mut &encoded[..]) - .expect("Failed to decode opaque"); - - match block.push(opaque) { - Err(sp_blockchain::Error::ApplyExtrinsicFailed( - sp_blockchain::ApplyExtrinsicFailed::Validity(e) - )) if e.exhausted_resources() => { - break; - }, - Err(err) => panic!("Error pushing transaction: {:?}", err), - Ok(_) => {}, - } - iteration += 1; - } - let block = block.build().expect("Block build failed").block; - - log::info!( - target: "bench-logistics", - "Block construction: {:#?} ({} tx)", - start.elapsed(), block.extrinsics.len() - ); - - block -} - // Import generated block. fn import_block(client: &mut Client, block: Block) { let import_params = BlockImportParams { @@ -398,26 +428,20 @@ fn bench_block_import(c: &mut Criterion) { // for future uses, uncomment if something wrong. // sc_cli::init_logger("sc_client=debug"); - let (block, guard) = { - let context = BenchContext::new(Profile::Wasm); - let block = generate_block_import(&context.client, &context.keyring); - (block, context.keep_db()) - }; + let mut bench_db = BenchDb::new(128); + let block = bench_db.generate_block(); log::trace!( target: "bench-logistics", "Seed database directory: {}", - guard.0.path().to_string_lossy(), + bench_db.path().to_string_lossy(), ); c.bench_function_over_inputs("import block", move |bencher, profile| { bencher.iter_batched( || { - let context = BenchContext::new_from_seed( - *profile, - guard.0.path(), - ); + let context = bench_db.create_context(*profile); // mostly to just launch compiler before benching! let version = context.client.runtime_version_at(&BlockId::Number(0)) @@ -465,21 +489,14 @@ fn bench_block_import(c: &mut Criterion) { fn profile_block_import(c: &mut Criterion) { sc_cli::init_logger(""); - let (block, guard) = { - let context = BenchContext::new(Profile::Wasm); - let block = generate_block_import(&context.client, &context.keyring); - (block, context.keep_db()) - }; + let mut bench_db = BenchDb::new(128); + let block = bench_db.generate_block(); c.bench_function("profile block", move |bencher| { bencher.iter_batched( || { - let context = BenchContext::new_from_seed( - Profile::Native, - guard.0.path(), - ); - context + bench_db.create_context(Profile::Native) }, |mut context| { // until better osx signpost/callgrind signal is possible to use From ef9db561d2f68b34b4d2bff815c963ea834005ea Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 17 Feb 2020 12:46:45 +0300 Subject: [PATCH 2/6] Update bin/node/testing/benches/import.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bastian Köcher --- bin/node/testing/benches/import.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index 929e0981fa679..ee209ee398faa 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -434,7 +434,7 @@ fn bench_block_import(c: &mut Criterion) { log::trace!( target: "bench-logistics", "Seed database directory: {}", - bench_db.path().to_string_lossy(), + bench_db.path().display(), ); c.bench_function_over_inputs("import block", @@ -517,4 +517,4 @@ fn profile_block_import(c: &mut Criterion) { ); }, ); -} \ No newline at end of file +} From 4908ee6ee8be6e06c0a8aa258c51ede60125b0b9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 17 Feb 2020 12:46:53 +0300 Subject: [PATCH 3/6] Update bin/node/testing/benches/import.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bastian Köcher --- bin/node/testing/benches/import.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index ee209ee398faa..0d5162985e340 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -157,7 +157,7 @@ impl BenchDb { let (client, _backend) = bench_client( self.directory_guard.path(), Profile::Wasm, - &self.keyring + &self.keyring, ); let version = client.runtime_version_at(&BlockId::number(0)) From 286e52f73f0e94cfb87800bd88b9a274deaf5bea Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 17 Feb 2020 12:47:08 +0300 Subject: [PATCH 4/6] Update bin/node/testing/benches/import.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bastian Köcher --- bin/node/testing/benches/import.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index 0d5162985e340..890e34ac7efb2 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -137,7 +137,6 @@ impl Clone for BenchDb { } impl BenchDb { - fn new(random_space: usize) -> Self { let keyring = BenchKeyring::new(random_space); From 4c555cf619c756754832afe4c1b5915ca544596f Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 17 Feb 2020 12:50:11 +0300 Subject: [PATCH 5/6] review suggestions --- bin/node/testing/benches/import.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index 929e0981fa679..c820496154d24 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -100,14 +100,12 @@ struct BenchKeyring { // This is prepared database with genesis and keyring // that can be cloned and then used for any benchmarking. struct BenchDb { - random_space: usize, keyring: BenchKeyring, directory_guard: Guard, } impl Clone for BenchDb { fn clone(&self) -> Self { - let random_space = self.random_space; let keyring = self.keyring.clone(); let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); @@ -132,14 +130,14 @@ impl Clone for BenchDb { &fs_extra::dir::CopyOptions::new(), ).expect("Copy of seed database is ok"); - BenchDb { keyring, directory_guard: Guard(dir), random_space } + BenchDb { keyring, directory_guard: Guard(dir) } } } impl BenchDb { - fn new(random_space: usize) -> Self { - let keyring = BenchKeyring::new(random_space); + fn new(keyring_length: usize) -> Self { + let keyring = BenchKeyring::new(keyring_length); let dir = tempdir::TempDir::new("sub-bench").expect("temp dir creation failed"); log::trace!( @@ -150,7 +148,7 @@ impl BenchDb { let (_client, _backend) = bench_client(dir.path(), Profile::Native, &keyring); let directory_guard = Guard(dir); - BenchDb { keyring, random_space, directory_guard } + BenchDb { keyring, directory_guard } } fn generate_block(&mut self) -> Block { @@ -246,7 +244,7 @@ impl BenchDb { } fn create_context(&self, profile: Profile) -> BenchContext { - let BenchDb { directory_guard, keyring, .. } = self.clone(); + let BenchDb { directory_guard, keyring } = self.clone(); let (client, backend) = bench_client(directory_guard.path(), profile, &keyring); BenchContext { @@ -256,7 +254,8 @@ impl BenchDb { } impl BenchKeyring { - fn new(num: usize) -> Self { + // `length` is the number of random accounts generated. + fn new(length: usize) -> Self { let mut accounts = BTreeMap::new(); for n in 0..num { From 46d1d191b119a9e557633008c2ac7be13adffe18 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 17 Feb 2020 13:37:00 +0300 Subject: [PATCH 6/6] fix build --- bin/node/testing/benches/import.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/testing/benches/import.rs b/bin/node/testing/benches/import.rs index 3b656455f69a9..9f20387cd58fa 100644 --- a/bin/node/testing/benches/import.rs +++ b/bin/node/testing/benches/import.rs @@ -257,7 +257,7 @@ impl BenchKeyring { fn new(length: usize) -> Self { let mut accounts = BTreeMap::new(); - for n in 0..num { + for n in 0..length { let seed = format!("//endowed-user/{}", n); let pair = sr25519::Pair::from_string(&seed, None).expect("failed to generate pair"); let account_id = AccountPublic::from(pair.public()).into_account();