Skip to content
This repository was archived by the owner on May 23, 2024. It is now read-only.

Commit 6183b0b

Browse files
sam0x17ggwpezKiChjang
authored andcommitted
new proc-macro-based benchmarking syntax (paritytech#12924)
* add stub for new benchmark macro * benchmark syntax * add #[extrinsic call] separator * parse #[benchmark] item as a function * proper emission of error when #[extrinsic_call] annotation is missing * clean up * enclosing module via benchmarks! { } working * use an attribute macro on the module instead of benchmarks! { } * cargo fmt * working component implementation * WIP * working * add syntax for Linear<A, B> * parsing of param ranges (still need to build tuple though) * params parsing WIP * clean up (don't need extrinsic call name) * use proper Result syntax for BenchmarkDef parsing * proper parsing of Linear<0, 1> style args * successfully parse and make use of linear component ranges 💥 * rename support variable => home because eventually will be moved * compile-time check that param range types implement ParamRange * switch to using balances as example, failing on instance pallet * successfully set up __origin and __call with balances 💥 * clean up * use a module * don't need a variable for transfer * rename benchmark_transfer -> transfer because no longer conflicts * clean up * working with transfer_increasing_users as well 💥 * re-add BareBlock * add comments for undocumented structs+functions+traits * refactor in preparation for removing module requirements * switch to a block instead of a module * use the outer macro pattern to to enable #[benchmarks] aggregation * successfully generate SelectedBenchmark 💥 * implement components for SelectedBenchmark * implement instance for SelectedBenchmark * properly track #[extra] * working impl for fn benchmarks() * run_benchmarks WIP * finish run_benchmark! impl 💥 * import balances transfer_best_case benchmark * import transfer_keep_alive balances pallet benchmark * import set_balance_creating balances pallet benchmark * import set_balance_killing balances pallet benchmark * import force_transfer balances pallet benchmark * add #[extra] annotation and docs to transfer_increasing_users * import transfer_all balances pallet benchmark * import force_unreserve balances pallet benchmark * prepare to implement impl_benchmark_test_suite! * ensure tests cover #[extra] before and after #[benchmark] tag * refactor * clean up * fix * move to outer * switch to benchmarks/instance_benchmarks * test impl almost done, strange compiler error * benchmark test suites working 💥 * clean up * add stub and basic parsing for where_clause * working except where clause and extrinsic calls containing method chains * assume option (2) for now wrt paritytech#12924 (comment) * clean up * switch to attribute-style * properly handle where clauses * fix subtle missing where clause, now just MessageQueue issues * fix block formatting in message-queue pallet * switch to block vs non-block parsing of extrinsic call * working now but some benchmark tests failing * message-queue tests working (run order issue fixed) 🎉 * add comments and internal docs for fame_support_procedural::benchmark * fix license years * docs for lib.rs * add docs to new support procedural macros * don't allow #[benchmark] outside of benchmarking module * add docs * use benchmark(extra, skip_meta) style args * update docs accordingly * appease clippy * bump ci * add notes about `extra` and `skip_meta` * fix doc tests * re-run CI * use `ignore` instead of `no_run` on doc examples * bump CI * replace some if-lets with if-elses * more refactoring of if-let statements * fix remaining if-lets in BenchmarkDef::from() * fix if-lets in benchmarks() * fix remaining if-lets, use nested find_map for extrinsic call * switch to use #[extrinsic_call] or #[block] situationally * refactor ExtrinsicCallDef => BenchmarkCallDef * update docs with info about #[block] * add macro stub for #[extrinsic_call] * fix docs and add stub for #[block] as well * remove unused extern crate line * fix clippy nits * Use V2 bench syntax in pallet-example-basic Just testing the dev-ex... Signed-off-by: Oliver Tale-Yazdi <[email protected]> * carry over comment * use curly-brace style for impl_benchmark_test_suite! * remove unneeded parenthesis * proper handling of _() extrinsic call style * add docs for _() syntax * fix crate access * simplify keyword access Co-authored-by: Keith Yeung <[email protected]> * simplify module content destructuring Co-authored-by: Keith Yeung <[email protected]> * fix crate access "frame_benchmarking" => "frame-benchmarking", compiles * use _() extrinsic call syntax where possible in balances * simplify attr.path.segments.last() Co-authored-by: Keith Yeung <[email protected]> * fix compile error being suppressed * simplify extrinsic call keyword parsing Co-authored-by: Keith Yeung <[email protected]> * use ? operator instead of return None Co-authored-by: Keith Yeung <[email protected]> * rename generics => type_use_generics rename full_generics => type_impl_generics * simplify extrinsic call extraction with transpose * bump CI * nit * proper handling of too many + too few block/extrinsic call annotations * change to B >= A Co-authored-by: Oliver Tale-Yazdi <[email protected]> * remove unneeded ignore Co-authored-by: Oliver Tale-Yazdi <[email protected]> * remove another ignore Co-authored-by: Oliver Tale-Yazdi <[email protected]> * add ui tests * use _() style extrinsic call on accumulate_dummy Co-authored-by: Oliver Tale-Yazdi <[email protected]> * add range check to ParamRange * ui test for bad param ranges * fix failing example * add ignore back to other failing example * tweak expr_call span Co-authored-by: Keith Yeung <[email protected]> * fix typo * eliminate a match Co-authored-by: Keith Yeung <[email protected]> * change pub fn benchmarks to return Result<TokenStream> * fix origin error span * more informative error for invalid benchmark parameter name * fix spans on a few benchmark errors * remove unneeded clone * refactor inner loop of benchmark function parsing * preserve mod attributes * refactor outer loop of benchmark def parsing code, greatly simplified * simplify to use a ? operator when parsing benchmark attr path * fix another ? operator * further simplify benchmark function attr parsing with more ? ops * refactor extrinsic call handling to use if let rather than match * replace is_ok => is_err Co-authored-by: Keith Yeung <[email protected]> * re-use name during expansion of benchmark def * remove unneeded clone * fix span for origin missing error * fix missing semi Signed-off-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: Keith Yeung <[email protected]> Co-authored-by: parity-processbot <>
1 parent 946507b commit 6183b0b

38 files changed

+1763
-134
lines changed

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frame/balances/src/benchmarking.rs

Lines changed: 80 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file is part of Substrate.
22

3-
// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.
3+
// Copyright (C) 2020-2023 Parity Technologies (UK) Ltd.
44
// SPDX-License-Identifier: Apache-2.0
55

66
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,22 +20,25 @@
2020
#![cfg(feature = "runtime-benchmarks")]
2121

2222
use super::*;
23+
use crate::Pallet as Balances;
2324

24-
use frame_benchmarking::{account, benchmarks_instance_pallet, whitelisted_caller};
25+
use frame_benchmarking::{account, impl_benchmark_test_suite, whitelisted_caller};
26+
use frame_support::benchmarking::*;
2527
use frame_system::RawOrigin;
26-
use sp_runtime::traits::Bounded;
27-
28-
use crate::Pallet as Balances;
2928

3029
const SEED: u32 = 0;
3130
// existential deposit multiplier
3231
const ED_MULTIPLIER: u32 = 10;
3332

34-
benchmarks_instance_pallet! {
33+
#[instance_benchmarks]
34+
mod benchmarks {
35+
use super::*;
36+
3537
// Benchmark `transfer` extrinsic with the worst possible conditions:
3638
// * Transfer will kill the sender account.
3739
// * Transfer will create the recipient account.
38-
transfer {
40+
#[benchmark]
41+
fn transfer() {
3942
let existential_deposit = T::ExistentialDeposit::get();
4043
let caller = whitelisted_caller();
4144

@@ -47,84 +50,103 @@ benchmarks_instance_pallet! {
4750
// and reap this user.
4851
let recipient: T::AccountId = account("recipient", 0, SEED);
4952
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
50-
let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
51-
}: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount)
52-
verify {
53+
let transfer_amount =
54+
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
55+
56+
#[extrinsic_call]
57+
_(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
58+
5359
assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
5460
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
5561
}
5662

5763
// Benchmark `transfer` with the best possible condition:
5864
// * Both accounts exist and will continue to exist.
59-
#[extra]
60-
transfer_best_case {
65+
#[benchmark(extra)]
66+
fn transfer_best_case() {
6167
let caller = whitelisted_caller();
6268
let recipient: T::AccountId = account("recipient", 0, SEED);
6369
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
6470

65-
// Give the sender account max funds for transfer (their account will never reasonably be killed).
66-
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
71+
// Give the sender account max funds for transfer (their account will never reasonably be
72+
// killed).
73+
let _ =
74+
<Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
6775

6876
// Give the recipient account existential deposit (thus their account already exists).
6977
let existential_deposit = T::ExistentialDeposit::get();
70-
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&recipient, existential_deposit);
78+
let _ =
79+
<Balances<T, I> as Currency<_>>::make_free_balance_be(&recipient, existential_deposit);
7180
let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
72-
}: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount)
73-
verify {
81+
82+
#[extrinsic_call]
83+
transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
84+
7485
assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
7586
assert!(!Balances::<T, I>::free_balance(&recipient).is_zero());
7687
}
7788

7889
// Benchmark `transfer_keep_alive` with the worst possible condition:
7990
// * The recipient account is created.
80-
transfer_keep_alive {
91+
#[benchmark]
92+
fn transfer_keep_alive() {
8193
let caller = whitelisted_caller();
8294
let recipient: T::AccountId = account("recipient", 0, SEED);
8395
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
8496

8597
// Give the sender account max funds, thus a transfer will not kill account.
86-
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
98+
let _ =
99+
<Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
87100
let existential_deposit = T::ExistentialDeposit::get();
88101
let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
89-
}: _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount)
90-
verify {
102+
103+
#[extrinsic_call]
104+
_(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
105+
91106
assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
92107
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
93108
}
94109

95110
// Benchmark `set_balance` coming from ROOT account. This always creates an account.
96-
set_balance_creating {
111+
#[benchmark]
112+
fn set_balance_creating() {
97113
let user: T::AccountId = account("user", 0, SEED);
98114
let user_lookup = T::Lookup::unlookup(user.clone());
99115

100116
// Give the user some initial balance.
101117
let existential_deposit = T::ExistentialDeposit::get();
102118
let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
103119
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance_amount);
104-
}: set_balance(RawOrigin::Root, user_lookup, balance_amount, balance_amount)
105-
verify {
120+
121+
#[extrinsic_call]
122+
set_balance(RawOrigin::Root, user_lookup, balance_amount, balance_amount);
123+
106124
assert_eq!(Balances::<T, I>::free_balance(&user), balance_amount);
107125
assert_eq!(Balances::<T, I>::reserved_balance(&user), balance_amount);
108126
}
109127

110128
// Benchmark `set_balance` coming from ROOT account. This always kills an account.
111-
set_balance_killing {
129+
#[benchmark]
130+
fn set_balance_killing() {
112131
let user: T::AccountId = account("user", 0, SEED);
113132
let user_lookup = T::Lookup::unlookup(user.clone());
114133

115134
// Give the user some initial balance.
116135
let existential_deposit = T::ExistentialDeposit::get();
117136
let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
118137
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance_amount);
119-
}: set_balance(RawOrigin::Root, user_lookup, Zero::zero(), Zero::zero())
120-
verify {
138+
139+
#[extrinsic_call]
140+
set_balance(RawOrigin::Root, user_lookup, Zero::zero(), Zero::zero());
141+
121142
assert!(Balances::<T, I>::free_balance(&user).is_zero());
122143
}
123144

124145
// Benchmark `force_transfer` extrinsic with the worst possible conditions:
125146
// * Transfer will kill the sender account.
126147
// * Transfer will create the recipient account.
127-
force_transfer {
148+
#[benchmark]
149+
fn force_transfer() {
128150
let existential_deposit = T::ExistentialDeposit::get();
129151
let source: T::AccountId = account("source", 0, SEED);
130152
let source_lookup = T::Lookup::unlookup(source.clone());
@@ -133,23 +155,26 @@ benchmarks_instance_pallet! {
133155
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
134156
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&source, balance);
135157

136-
// Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, and reap this user.
158+
// Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account,
159+
// and reap this user.
137160
let recipient: T::AccountId = account("recipient", 0, SEED);
138161
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
139-
let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
140-
}: force_transfer(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount)
141-
verify {
162+
let transfer_amount =
163+
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
164+
165+
#[extrinsic_call]
166+
_(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount);
167+
142168
assert_eq!(Balances::<T, I>::free_balance(&source), Zero::zero());
143169
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
144170
}
145171

146172
// This benchmark performs the same operation as `transfer` in the worst case scenario,
147173
// but additionally introduces many new users into the storage, increasing the the merkle
148174
// trie and PoV size.
149-
#[extra]
150-
transfer_increasing_users {
175+
#[benchmark(extra)]
176+
fn transfer_increasing_users(u: Linear<0, 1_000>) {
151177
// 1_000 is not very much, but this upper bound can be controlled by the CLI.
152-
let u in 0 .. 1_000;
153178
let existential_deposit = T::ExistentialDeposit::get();
154179
let caller = whitelisted_caller();
155180

@@ -161,25 +186,29 @@ benchmarks_instance_pallet! {
161186
// and reap this user.
162187
let recipient: T::AccountId = account("recipient", 0, SEED);
163188
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
164-
let transfer_amount = existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
189+
let transfer_amount =
190+
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
165191

166192
// Create a bunch of users in storage.
167-
for i in 0 .. u {
193+
for i in 0..u {
168194
// The `account` function uses `blake2_256` to generate unique accounts, so these
169195
// should be quite random and evenly distributed in the trie.
170196
let new_user: T::AccountId = account("new_user", i, SEED);
171197
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&new_user, balance);
172198
}
173-
}: transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount)
174-
verify {
199+
200+
#[extrinsic_call]
201+
transfer(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
202+
175203
assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
176204
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
177205
}
178206

179207
// Benchmark `transfer_all` with the worst possible condition:
180208
// * The recipient account is created
181209
// * The sender is killed
182-
transfer_all {
210+
#[benchmark]
211+
fn transfer_all() {
183212
let caller = whitelisted_caller();
184213
let recipient: T::AccountId = account("recipient", 0, SEED);
185214
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
@@ -188,13 +217,16 @@ benchmarks_instance_pallet! {
188217
let existential_deposit = T::ExistentialDeposit::get();
189218
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
190219
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
191-
}: _(RawOrigin::Signed(caller.clone()), recipient_lookup, false)
192-
verify {
220+
221+
#[extrinsic_call]
222+
_(RawOrigin::Signed(caller.clone()), recipient_lookup, false);
223+
193224
assert!(Balances::<T, I>::free_balance(&caller).is_zero());
194225
assert_eq!(Balances::<T, I>::free_balance(&recipient), balance);
195226
}
196227

197-
force_unreserve {
228+
#[benchmark]
229+
fn force_unreserve() {
198230
let user: T::AccountId = account("user", 0, SEED);
199231
let user_lookup = T::Lookup::unlookup(user.clone());
200232

@@ -208,15 +240,16 @@ benchmarks_instance_pallet! {
208240
assert_eq!(Balances::<T, I>::reserved_balance(&user), balance);
209241
assert!(Balances::<T, I>::free_balance(&user).is_zero());
210242

211-
}: _(RawOrigin::Root, user_lookup, balance)
212-
verify {
243+
#[extrinsic_call]
244+
_(RawOrigin::Root, user_lookup, balance);
245+
213246
assert!(Balances::<T, I>::reserved_balance(&user).is_zero());
214247
assert_eq!(Balances::<T, I>::free_balance(&user), balance);
215248
}
216249

217-
impl_benchmark_test_suite!(
250+
impl_benchmark_test_suite! {
218251
Balances,
219252
crate::tests_composite::ExtBuilder::default().build(),
220253
crate::tests_composite::Test,
221-
)
254+
}
222255
}

0 commit comments

Comments
 (0)