mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 09:21:05 +00:00
Some benchmarks for phragmen (#2650)
* Add some benchmarks for phragmen * Fix dep. import. * Clean up with some macros. * more details. * Fix dual import. * Remove wrong assertions. * Add a few more.
This commit is contained in:
Generated
+1
@@ -3692,6 +3692,7 @@ name = "srml-staking"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-io 2.0.0",
|
||||
|
||||
@@ -21,8 +21,10 @@ session = { package = "srml-session", path = "../session", default-features = fa
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
timestamp = { package = "srml-timestamp", path = "../timestamp" }
|
||||
balances = { package = "srml-balances", path = "../balances" }
|
||||
rand = "0.6.5"
|
||||
|
||||
[features]
|
||||
bench = []
|
||||
default = ["std"]
|
||||
std = [
|
||||
"serde",
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright 2019 Parity Technologies
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Benchmarks of the phragmen election algorithm.
|
||||
//! Note that execution times will not be accurate in an absolute scale, since
|
||||
//! - Everything is executed in the context of `TestExternalities`
|
||||
//! - Everything is executed in native environment.
|
||||
//!
|
||||
//! Run using:
|
||||
//!
|
||||
//! ```zsh
|
||||
//! cargo bench --features bench --color always
|
||||
//! ```
|
||||
|
||||
use test::Bencher;
|
||||
use runtime_io::with_externalities;
|
||||
use mock::*;
|
||||
use super::*;
|
||||
use rand::{self, Rng};
|
||||
|
||||
const VALIDATORS: u64 = 1000;
|
||||
const NOMINATORS: u64 = 10_000;
|
||||
const EDGES: u64 = 2;
|
||||
const TO_ELECT: usize = 100;
|
||||
const STAKE: u64 = 1000;
|
||||
|
||||
fn do_phragmen(b: &mut Bencher, num_vals: u64, num_noms: u64, count: usize, votes_per: u64) {
|
||||
with_externalities(&mut ExtBuilder::default().nominate(false).build(), || {
|
||||
assert!(num_vals > votes_per);
|
||||
let rr = |a, b| rand::thread_rng().gen_range(a as usize, b as usize) as u64;
|
||||
|
||||
// prefix to distinguish the validator and nominator account ranges.
|
||||
let np = 10_000;
|
||||
|
||||
(1 ..= 2*num_vals)
|
||||
.step_by(2)
|
||||
.for_each(|acc| bond_validator(acc, STAKE + rr(10, 50)));
|
||||
|
||||
(np ..= (np + 2*num_noms))
|
||||
.step_by(2)
|
||||
.for_each(|acc| {
|
||||
let mut stashes_to_vote = (1 ..= 2*num_vals)
|
||||
.step_by(2)
|
||||
.map(|ctrl| ctrl + 1)
|
||||
.collect::<Vec<AccountIdType>>();
|
||||
let votes = (0 .. votes_per)
|
||||
.map(|_| {
|
||||
stashes_to_vote.remove(rr(0, stashes_to_vote.len()) as usize)
|
||||
})
|
||||
.collect::<Vec<AccountIdType>>();
|
||||
bond_nominator(acc, STAKE + rr(10, 50), votes);
|
||||
});
|
||||
|
||||
b.iter(|| {
|
||||
let _ = phragmen::elect::<Test, _, _, _>(
|
||||
count,
|
||||
1_usize,
|
||||
<Validators<Test>>::enumerate(),
|
||||
<Nominators<Test>>::enumerate(),
|
||||
Staking::slashable_balance_of
|
||||
);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! phragmen_benches {
|
||||
($($name:ident: $tup:expr,)*) => {
|
||||
$(
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let (v, n, t, e) = $tup;
|
||||
println!("");
|
||||
println!(
|
||||
"++ Benchmark: {} Validators // {} Nominators // {} Edges-per-nominator // {} total edges // electing {}",
|
||||
v, n, e, e * n, t
|
||||
);
|
||||
do_phragmen(b, v, n, t, e);
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
phragmen_benches! {
|
||||
bench_1_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_1_2: (VALIDATORS*2, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_1_3: (VALIDATORS*4, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_1_4: (VALIDATORS*8, NOMINATORS, TO_ELECT, EDGES),
|
||||
|
||||
bench_0_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_0_2: (VALIDATORS, NOMINATORS, TO_ELECT * 4, EDGES),
|
||||
bench_0_3: (VALIDATORS, NOMINATORS, TO_ELECT * 8, EDGES),
|
||||
bench_0_4: (VALIDATORS, NOMINATORS, TO_ELECT * 16, EDGES),
|
||||
|
||||
bench_2_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_2_2: (VALIDATORS, NOMINATORS*2, TO_ELECT, EDGES),
|
||||
bench_2_3: (VALIDATORS, NOMINATORS*4, TO_ELECT, EDGES),
|
||||
bench_2_4: (VALIDATORS, NOMINATORS*8, TO_ELECT, EDGES),
|
||||
|
||||
bench_3_1: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES),
|
||||
bench_3_2: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*2),
|
||||
bench_3_3: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*4),
|
||||
bench_3_4: (VALIDATORS, NOMINATORS, TO_ELECT, EDGES*8),
|
||||
}
|
||||
@@ -240,16 +240,31 @@
|
||||
//! stored in the Session module's `Validators` at the end of each era.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(all(feature = "bench", test), feature(test))]
|
||||
|
||||
#[cfg(all(feature = "bench", test))]
|
||||
extern crate test;
|
||||
|
||||
#[cfg(any(feature = "bench", test))]
|
||||
mod mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
mod phragmen;
|
||||
|
||||
#[cfg(all(feature = "bench", test))]
|
||||
mod benches;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use runtime_io::with_storage;
|
||||
use rstd::{prelude::*, result, collections::btree_map::BTreeMap};
|
||||
use parity_codec::{HasCompact, Encode, Decode};
|
||||
use srml_support::{StorageValue, StorageMap, EnumerableStorageMap, dispatch::Result};
|
||||
use srml_support::{decl_module, decl_event, decl_storage, ensure};
|
||||
use srml_support::traits::{
|
||||
Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, WithdrawReasons,
|
||||
OnUnbalanced, Imbalance,
|
||||
use srml_support::{ StorageValue, StorageMap, EnumerableStorageMap, dispatch::Result,
|
||||
decl_module, decl_event, decl_storage, ensure,
|
||||
traits::{Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency,
|
||||
WithdrawReasons, OnUnbalanced, Imbalance
|
||||
}
|
||||
};
|
||||
use session::OnSessionChange;
|
||||
use primitives::Perbill;
|
||||
@@ -261,10 +276,6 @@ use primitives::traits::{
|
||||
use primitives::{Serialize, Deserialize};
|
||||
use system::ensure_signed;
|
||||
|
||||
mod mock;
|
||||
mod tests;
|
||||
mod phragmen;
|
||||
|
||||
use phragmen::{elect, ACCURACY, ExtendedBalance};
|
||||
|
||||
const RECENT_OFFLINE_COUNT: usize = 32;
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
//! Test utilities
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use primitives::{traits::{IdentityLookup, Convert}, BuildStorage, Perbill};
|
||||
use primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, ConvertUintAuthorityId};
|
||||
use substrate_primitives::{H256, Blake2Hasher};
|
||||
use runtime_io;
|
||||
use srml_support::impl_outer_origin;
|
||||
use crate::{GenesisConfig, Module, Trait, StakerStatus};
|
||||
use srml_support::{impl_outer_origin, assert_ok, traits::Currency};
|
||||
use crate::{GenesisConfig, Module, Trait, StakerStatus, ValidatorPrefs, RewardDestination};
|
||||
|
||||
/// The AccountId alias in this test module.
|
||||
pub type AccountIdType = u64;
|
||||
@@ -241,3 +239,33 @@ pub type Balances = balances::Module<Test>;
|
||||
pub type Session = session::Module<Test>;
|
||||
pub type Timestamp = timestamp::Module<Test>;
|
||||
pub type Staking = Module<Test>;
|
||||
|
||||
pub fn check_exposure(acc: u64) {
|
||||
let expo = Staking::stakers(&acc);
|
||||
assert_eq!(expo.total as u128, expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::<u128>());
|
||||
}
|
||||
|
||||
pub fn check_exposure_all() {
|
||||
Staking::current_elected().into_iter().for_each(|acc| check_exposure(acc));
|
||||
}
|
||||
|
||||
pub fn assert_total_expo(acc: u64, val: u64) {
|
||||
let expo = Staking::stakers(&acc);
|
||||
assert_eq!(expo.total, val);
|
||||
}
|
||||
|
||||
pub fn bond_validator(acc: u64, val: u64) {
|
||||
// a = controller
|
||||
// a + 1 = stash
|
||||
let _ = Balances::make_free_balance_be(&(acc+1), val);
|
||||
assert_ok!(Staking::bond(Origin::signed(acc+1), acc, val, RewardDestination::Controller));
|
||||
assert_ok!(Staking::validate(Origin::signed(acc), ValidatorPrefs::default()));
|
||||
}
|
||||
|
||||
pub fn bond_nominator(acc: u64, val: u64, target: Vec<u64>) {
|
||||
// a = controller
|
||||
// a + 1 = stash
|
||||
let _ = Balances::make_free_balance_be(&(acc+1), val);
|
||||
assert_ok!(Staking::bond(Origin::signed(acc+1), acc, val, RewardDestination::Controller));
|
||||
assert_ok!(Staking::nominate(Origin::signed(acc), target));
|
||||
}
|
||||
@@ -107,29 +107,29 @@ pub fn elect<T: Trait + 'static, FV, FN, FS>(
|
||||
// Candidates who have 0 stake => have no votes or all null-votes. Kick them out not.
|
||||
let mut nominators: Vec<Nominator<T::AccountId>> = Vec::with_capacity(validator_iter.size_hint().0 + nominator_iter.size_hint().0);
|
||||
let mut candidates = validator_iter.map(|(who, _)| {
|
||||
let stash_balance = stash_of(&who);
|
||||
(Candidate { who, ..Default::default() }, stash_balance)
|
||||
})
|
||||
.filter_map(|(mut c, s)| {
|
||||
c.approval_stake += to_votes(s);
|
||||
if c.approval_stake.is_zero() {
|
||||
None
|
||||
} else {
|
||||
Some((c, s))
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(idx, (c, s))| {
|
||||
nominators.push(Nominator {
|
||||
who: c.who.clone(),
|
||||
edges: vec![ Edge { who: c.who.clone(), candidate_index: idx, ..Default::default() }],
|
||||
budget: to_votes(s),
|
||||
load: Fraction::zero(),
|
||||
});
|
||||
c_idx_cache.insert(c.who.clone(), idx);
|
||||
c
|
||||
})
|
||||
.collect::<Vec<Candidate<T::AccountId>>>();
|
||||
let stash_balance = stash_of(&who);
|
||||
(Candidate { who, ..Default::default() }, stash_balance)
|
||||
})
|
||||
.filter_map(|(mut c, s)| {
|
||||
c.approval_stake += to_votes(s);
|
||||
if c.approval_stake.is_zero() {
|
||||
None
|
||||
} else {
|
||||
Some((c, s))
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(idx, (c, s))| {
|
||||
nominators.push(Nominator {
|
||||
who: c.who.clone(),
|
||||
edges: vec![ Edge { who: c.who.clone(), candidate_index: idx, ..Default::default() }],
|
||||
budget: to_votes(s),
|
||||
load: Fraction::zero(),
|
||||
});
|
||||
c_idx_cache.insert(c.who.clone(), idx);
|
||||
c
|
||||
})
|
||||
.collect::<Vec<Candidate<T::AccountId>>>();
|
||||
|
||||
// 2- Collect the nominators with the associated votes.
|
||||
// Also collect approval stake along the way.
|
||||
|
||||
@@ -16,50 +16,13 @@
|
||||
|
||||
//! Tests for the module.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use super::*;
|
||||
use runtime_io::with_externalities;
|
||||
use phragmen;
|
||||
use srml_support::{assert_ok, assert_noop, assert_eq_uvec, EnumerableStorageMap};
|
||||
use mock::{Balances, Session, Staking, System, Timestamp, Test, ExtBuilder, Origin};
|
||||
use mock::*;
|
||||
use srml_support::traits::{Currency, ReservableCurrency};
|
||||
|
||||
#[inline]
|
||||
fn check_exposure(acc: u64) {
|
||||
let expo = Staking::stakers(&acc);
|
||||
assert_eq!(expo.total as u128, expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::<u128>());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_exposure_all() {
|
||||
Staking::current_elected().into_iter().for_each(|acc| check_exposure(acc));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn assert_total_expo(acc: u64, val: u64) {
|
||||
let expo = Staking::stakers(&acc);
|
||||
assert_eq!(expo.total, val);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bond_validator(acc: u64, val: u64) {
|
||||
// a = controller
|
||||
// a + 1 = stash
|
||||
let _ = Balances::make_free_balance_be(&(acc+1), val);
|
||||
assert_ok!(Staking::bond(Origin::signed(acc+1), acc, val, RewardDestination::Controller));
|
||||
assert_ok!(Staking::validate(Origin::signed(acc), ValidatorPrefs::default()));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bond_nominator(acc: u64, val: u64, target: Vec<u64>) {
|
||||
// a = controller
|
||||
// a + 1 = stash
|
||||
let _ = Balances::make_free_balance_be(&(acc+1), val);
|
||||
assert_ok!(Staking::bond(Origin::signed(acc+1), acc, val, RewardDestination::Controller));
|
||||
assert_ok!(Staking::nominate(Origin::signed(acc), target));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_setup_works() {
|
||||
// Verifies initial conditions of mock
|
||||
|
||||
Reference in New Issue
Block a user