Skip to content

Commit

Permalink
Frame System Benchmarking (paritytech#5834)
Browse files Browse the repository at this point in the history
* Frame System Benchmarking

* Add to substrate node, avoid divide by zero errors in analysis

* reduce features

* some fixes

* copy pasta
  • Loading branch information
shawntabrizi authored Apr 30, 2020
1 parent bb83628 commit 6d8ddd4
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 13 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ members = [
"frame/support/procedural/tools/derive",
"frame/support/test",
"frame/system",
"frame/system/benchmarking",
"frame/system/rpc/runtime-api",
"frame/timestamp",
"frame/transaction-payment",
Expand Down Expand Up @@ -181,4 +182,3 @@ members = [
[profile.release]
# Substrate runtime requires unwinding.
panic = "unwind"

2 changes: 2 additions & 0 deletions bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ frame-executive = { version = "2.0.0-dev", default-features = false, path = "../
frame-benchmarking = { version = "2.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true }
frame-support = { version = "2.0.0-dev", default-features = false, path = "../../../frame/support" }
frame-system = { version = "2.0.0-dev", default-features = false, path = "../../../frame/system" }
frame-system-benchmarking = { version = "2.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true }
frame-system-rpc-runtime-api = { version = "2.0.0-dev", default-features = false, path = "../../../frame/system/rpc/runtime-api/" }
pallet-authority-discovery = { version = "2.0.0-dev", default-features = false, path = "../../../frame/authority-discovery" }
pallet-authorship = { version = "2.0.0-dev", default-features = false, path = "../../../frame/authorship" }
Expand Down Expand Up @@ -155,4 +156,5 @@ runtime-benchmarks = [
"pallet-vesting/runtime-benchmarks",
"pallet-offences-benchmarking",
"pallet-session-benchmarking",
"frame-system-benchmarking",
]
3 changes: 3 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,9 +902,11 @@ impl_runtime_apis! {
// we need these two lines below.
use pallet_session_benchmarking::Module as SessionBench;
use pallet_offences_benchmarking::Module as OffencesBench;
use frame_system_benchmarking::Module as SystemBench;

impl pallet_session_benchmarking::Trait for Runtime {}
impl pallet_offences_benchmarking::Trait for Runtime {}
impl frame_system_benchmarking::Trait for Runtime {}

let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&pallet, &benchmark, &lowest_range_values, &highest_range_values, &steps, repeat);
Expand All @@ -917,6 +919,7 @@ impl_runtime_apis! {
add_benchmark!(params, batches, b"offences", OffencesBench::<Runtime>);
add_benchmark!(params, batches, b"session", SessionBench::<Runtime>);
add_benchmark!(params, batches, b"staking", Staking);
add_benchmark!(params, batches, b"system", SystemBench::<Runtime>);
add_benchmark!(params, batches, b"timestamp", Timestamp);
add_benchmark!(params, batches, b"treasury", Treasury);
add_benchmark!(params, batches, b"utility", Utility);
Expand Down
26 changes: 19 additions & 7 deletions frame/benchmarking/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ impl Analysis {
.collect();

let value_dists = results.iter().map(|(p, vs)| {
// Avoid divide by zero
if vs.len() == 0 { return (p.clone(), 0, 0) }
let total = vs.iter()
.fold(0u128, |acc, v| acc + *v);
let mean = total / vs.len() as u128;
Expand Down Expand Up @@ -178,13 +180,23 @@ impl std::fmt::Display for Analysis {
writeln!(f, "\nData points distribution:")?;
writeln!(f, "{} mean µs sigma µs %", self.names.iter().map(|p| format!("{:>5}", p)).collect::<Vec<_>>().join(" "))?;
for (param_values, mean, sigma) in value_dists.iter() {
writeln!(f, "{} {:>8} {:>8} {:>3}.{}%",
param_values.iter().map(|v| format!("{:>5}", v)).collect::<Vec<_>>().join(" "),
ms(*mean),
ms(*sigma),
(sigma * 100 / mean),
(sigma * 1000 / mean % 10)
)?;
if *mean == 0 {
writeln!(f, "{} {:>8} {:>8} {:>3}.{}%",
param_values.iter().map(|v| format!("{:>5}", v)).collect::<Vec<_>>().join(" "),
ms(*mean),
ms(*sigma),
"?",
"?"
)?;
} else {
writeln!(f, "{} {:>8} {:>8} {:>3}.{}%",
param_values.iter().map(|v| format!("{:>5}", v)).collect::<Vec<_>>().join(" "),
ms(*mean),
ms(*sigma),
(sigma * 100 / mean),
(sigma * 1000 / mean % 10)
)?;
}
}
}
if let Some(ref model) = self.model {
Expand Down
2 changes: 1 addition & 1 deletion frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

//! Mock file for staking fuzzing.
//! Mock file for session benchmarking.
#![cfg(test)]

Expand Down
37 changes: 37 additions & 0 deletions frame/system/benchmarking/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "frame-system-benchmarking"
version = "2.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"
description = "FRAME System benchmarking"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false }
sp-std = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/std" }
sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/runtime" }
frame-benchmarking = { version = "2.0.0-dev", default-features = false, path = "../../benchmarking" }
frame-system = { version = "2.0.0-dev", default-features = false, path = "../../system" }
frame-support = { version = "2.0.0-dev", default-features = false, path = "../../support" }
sp-core = { version = "2.0.0-dev", default-features = false, path = "../../../primitives/core" }

[dev-dependencies]
serde = { version = "1.0.101" }
sp-io ={ path = "../../../primitives/io", version = "2.0.0-dev"}

[features]
default = ["std"]
std = [
"codec/std",
"sp-runtime/std",
"sp-std/std",
"frame-benchmarking/std",
"frame-system/std",
"frame-support/std",
"sp-core/std",
]
179 changes: 179 additions & 0 deletions frame/system/benchmarking/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.

// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

// Benchmarks for Utility Pallet

#![cfg_attr(not(feature = "std"), no_std)]

use codec::Encode;
use sp_std::vec;
use sp_std::prelude::*;
use sp_core::{ChangesTrieConfiguration, storage::well_known_keys};
use sp_runtime::traits::Hash;
use frame_benchmarking::{benchmarks, account};
use frame_support::storage::{self, StorageMap};
use frame_system::{Module as System, Call, RawOrigin, DigestItemOf, AccountInfo};

mod mock;

const SEED: u32 = 0;

pub struct Module<T: Trait>(System<T>);
pub trait Trait: frame_system::Trait {}

benchmarks! {
_ { }

remark {
// # of Bytes
let b in 0 .. 16_384;
let remark_message = vec![1; b as usize];
let caller = account("caller", 0, SEED);
}: _(RawOrigin::Signed(caller), remark_message)

set_heap_pages {
// Heap page size
let i in 0 .. u32::max_value();
}: _(RawOrigin::Root, i.into())

// `set_code` was not benchmarked because it is pretty hard to come up with a real
// Wasm runtime to test the upgrade with. But this is okay because we will make
// `set_code` take a full block anyway.

set_code_without_checks {
// Version number
let b in 0 .. 16_384;
let code = vec![1; b as usize];
}: _(RawOrigin::Root, code)
verify {
let current_code = storage::unhashed::get_raw(well_known_keys::CODE).ok_or("Code not stored.")?;
assert_eq!(current_code.len(), b as usize);
}

set_changes_trie_config {
let d in 0 .. 1000;

let digest_item = DigestItemOf::<T>::Other(vec![]);

for i in 0 .. d {
System::<T>::deposit_log(digest_item.clone());
}
let changes_trie_config = ChangesTrieConfiguration {
digest_interval: d,
digest_levels: d,
};
}: _(RawOrigin::Root, Some(changes_trie_config))
verify {
assert_eq!(System::<T>::digest().logs.len(), (d + 1) as usize)
}

set_storage {
let i in 1 .. 1000;

// Set up i items to add
let mut items = Vec::new();
for j in 0 .. i {
let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec();
items.push((hash.clone(), hash.clone()));
}
}: _(RawOrigin::Root, items)
verify {
let last_hash = (i, i - 1).using_encoded(T::Hashing::hash);
let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?;
assert_eq!(value, last_hash.as_ref().to_vec());
}

kill_storage {
let i in 1 .. 1000;

// Add i items to storage
let mut items = Vec::new();
for j in 0 .. i {
let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec();
storage::unhashed::put_raw(&hash, &hash);
items.push(hash);
}

// We will verify this value is removed
let last_hash = (i, i - 1).using_encoded(T::Hashing::hash);
let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?;
assert_eq!(value, last_hash.as_ref().to_vec());

}: _(RawOrigin::Root, items)
verify {
assert_eq!(storage::unhashed::get_raw(last_hash.as_ref()), None);
}

kill_prefix {
let p in 1 .. 1000;

let prefix = p.using_encoded(T::Hashing::hash).as_ref().to_vec();
// add p items that share a prefix
for i in 0 .. p {
let hash = (p, i).using_encoded(T::Hashing::hash).as_ref().to_vec();
let key = [&prefix[..], &hash[..]].concat();
storage::unhashed::put_raw(&key, &key);
}

// We will verify this value is removed
let last_hash = (p, p - 1).using_encoded(T::Hashing::hash).as_ref().to_vec();
let last_key = [&prefix[..], &last_hash[..]].concat();
let value = storage::unhashed::get_raw(&last_key).ok_or("No value stored")?;
assert_eq!(value, last_key);

}: _(RawOrigin::Root, prefix)
verify {
assert_eq!(storage::unhashed::get_raw(&last_key), None);
}

suicide {
let n in 1 .. 1000;
let caller: T::AccountId = account("caller", 0, SEED);
let account_info = AccountInfo::<T::Index, T::AccountData> {
nonce: n.into(),
refcount: 0,
data: T::AccountData::default()
};
frame_system::Account::<T>::insert(&caller, account_info);
let new_account_info = System::<T>::account(caller.clone());
assert_eq!(new_account_info.nonce, n.into());
}: _(RawOrigin::Signed(caller.clone()))
verify {
let account_info = System::<T>::account(&caller);
assert_eq!(account_info.nonce, 0.into());
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};
use frame_support::assert_ok;

#[test]
fn test_benchmarks() {
new_test_ext().execute_with(|| {
assert_ok!(test_benchmark_remark::<Test>());
assert_ok!(test_benchmark_set_heap_pages::<Test>());
assert_ok!(test_benchmark_set_code_without_checks::<Test>());
assert_ok!(test_benchmark_set_changes_trie_config::<Test>());
assert_ok!(test_benchmark_set_storage::<Test>());
assert_ok!(test_benchmark_kill_storage::<Test>());
assert_ok!(test_benchmark_kill_prefix::<Test>());
assert_ok!(test_benchmark_suicide::<Test>());
});
}
}
Loading

0 comments on commit 6d8ddd4

Please sign in to comment.