Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions substrate/utils/frame/benchmarking-cli/src/storage/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ pub struct StorageParams {
/// This is only used when `mode` is `validate-block`.
#[arg(long, default_value_t = 20)]
pub validate_block_rounds: u32,

/// Maximum number of keys to read
/// (All keys if not define)
#[arg(long)]
pub keys_limit: Option<usize>,

/// Seed to use for benchs randomness, the same seed allow to replay
/// becnhamrks under the same conditions.
#[arg(long)]
pub random_seed: Option<u64>,
}

impl StorageParams {
Expand Down Expand Up @@ -248,8 +258,17 @@ impl StorageCmd {
BA: ClientBackend<B>,
{
let hash = client.usage_info().chain.best_hash;
let mut keys: Vec<_> = client.storage_keys(hash, None, None)?.collect();
let (mut rng, _) = new_rng(None);
let mut keys: Vec<_> = if let Some(keys_limit) = self.params.keys_limit {
use sp_core::blake2_256;
let first_key = self
.params
.random_seed
.map(|seed| sp_storage::StorageKey(blake2_256(&seed.to_be_bytes()[..]).to_vec()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are not keys_limit keys behind first_key this will "break". We should instead just load all the keys and then do sample_iter.

This can then directly replace the shuffle call below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sample_iter seems to create new values (IIUC). What if we use choose_multiple here?

		let mut keys: Vec<_> = client.storage_keys(hash, None, None)?.collect();
		let (mut rng, _) = new_rng(self.params.random_seed);
		keys = keys.choose_multiple(&mut rng, self.params.keys_limit.unwrap_or(keys.len())).cloned().collect();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you can also use choose_multiple.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bkchr, after discussing with the team loading all keys is exactly what breaks (OOM) the workflow for our huge storage chains.
But we get your first_key concern...let me try a different approach here and will ping you back.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkchr just pushed a new approach to get more keys when it is necessary.
LMK what do you think about it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arturgontijo I'm fine with the approach, but can we get this into some shared function? :D

It can probably take two lambdas to abstract the different ways to read the entries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a shared function in 6ed88c4
I tried to simplify it even more but the complexity (mostly trait bounds) was getting too high.

client.storage_keys(hash, None, first_key.as_ref())?.take(keys_limit).collect()
} else {
client.storage_keys(hash, None, None)?.collect()
};
let (mut rng, _) = new_rng(self.params.random_seed);
keys.shuffle(&mut rng);

for i in 0..self.params.warmups {
Expand Down
18 changes: 15 additions & 3 deletions substrate/utils/frame/benchmarking-cli/src/storage/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,21 @@ impl StorageCmd {
let best_hash = client.usage_info().chain.best_hash;

info!("Preparing keys from block {}", best_hash);
// Load all keys and randomly shuffle them.
let mut keys: Vec<_> = client.storage_keys(best_hash, None, None)?.collect();
let (mut rng, _) = new_rng(None);
// Load keys and randomly shuffle them.
let mut keys: Vec<_> = if let Some(keys_limit) = self.params.keys_limit {
use sp_core::blake2_256;
let first_key = self
.params
.random_seed
.map(|seed| sp_storage::StorageKey(blake2_256(&seed.to_be_bytes()[..]).to_vec()));
client
.storage_keys(best_hash, None, first_key.as_ref())?
.take(keys_limit)
.collect()
} else {
client.storage_keys(best_hash, None, None)?.collect()
};
let (mut rng, _) = new_rng(self.params.random_seed);
keys.shuffle(&mut rng);
if keys.is_empty() {
return Err("Can't process benchmarking with empty storage".into())
Expand Down
16 changes: 13 additions & 3 deletions substrate/utils/frame/benchmarking-cli/src/storage/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,19 @@ impl StorageCmd {
);

info!("Preparing keys from block {}", best_hash);
// Load all KV pairs and randomly shuffle them.
let mut kvs: Vec<_> = trie.pairs(Default::default())?.collect();
let (mut rng, _) = new_rng(None);
// Load KV pairs and randomly shuffle them.
let mut kvs: Vec<_> = if let Some(keys_limit) = self.params.keys_limit {
let start_at = self
.params
.random_seed
.map(|seed| sp_core::blake2_256(&seed.to_be_bytes()[..]).to_vec());
let mut iter_args = sp_state_machine::IterArgs::default();
iter_args.start_at = start_at.as_deref();
trie.pairs(iter_args)?.take(keys_limit).collect()
} else {
trie.pairs(Default::default())?.collect()
};
let (mut rng, _) = new_rng(self.params.random_seed);
kvs.shuffle(&mut rng);
if kvs.is_empty() {
return Err("Can't process benchmarking with empty storage".into())
Expand Down
Loading