Weight v1.5: Opaque Struct (#12138)

* initial idea

* update frame_support

* update a bunch more

* add ord

* adjust RuntimeDbWeight

* frame_system builds

* re-export

* frame_support tests pass

* frame_executive compile

* frame_executive builds

* frame_system tests passing

* pallet-utility tests pass

* fix a bunch of pallets

* more

* phragmen

* state-trie-migration

* scheduler and referenda

* pallet-election-provider-multi-phase

* aura

* staking

* more

* babe

* balances

* bunch more

* sudo

* transaction-payment

* asset-tx-payment

* last pallets

* fix alliance merge

* fix node template runtime

* fix pallet-contracts cc @athei

* fix node runtime

* fix compile on runtime-benchmarks feature

* comment

* fix frame-support-test

* fix more tests

* weight regex

* frame system works

* fix a bunch

* more

* more

* more

* more

* more

* more fixes

* update templates

* fix contracts benchmarks

* Update lib.rs

* Update lib.rs

* fix ui

* make scalar saturating mul const

* more const functions

* scalar div

* refactor using constant functions

* move impl

* fix overhead template

* use compactas

* Update lib.rs
This commit is contained in:
Shawn Tabrizi
2022-08-31 12:26:13 +01:00
committed by GitHub
parent 299f4ba541
commit 30951822ba
187 changed files with 5932 additions and 4930 deletions
@@ -142,7 +142,8 @@ where
let weight = ConsumedWeight::decode_all(&mut raw_weight)?;
// Should be divisible, but still use floats in case we ever change that.
Ok((weight.total() as f64 / WEIGHT_PER_NANOS as f64).floor() as NanoSeconds)
Ok((weight.total().ref_time() as f64 / WEIGHT_PER_NANOS.ref_time() as f64).floor()
as NanoSeconds)
}
/// Prints the weight info of a block to the console.
@@ -1,21 +1,21 @@
# The `benchmark overhead` command
Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead".
This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead.
The exact overhead to can vary per Substrate chain and needs to be calculated per chain.
Each time an extrinsic or a block is executed, a fixed weight is charged as "execution overhead".
This is necessary since the weight that is calculated by the pallet benchmarks does not include this overhead.
The exact overhead to can vary per Substrate chain and needs to be calculated per chain.
This command calculates the exact values of these overhead weights for any Substrate chain that supports it.
## How does it work?
The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`].
The benchmark consists of two parts; the [`BlockExecutionWeight`] and the [`ExtrinsicBaseWeight`].
Both are executed sequentially when invoking the command.
## BlockExecutionWeight
The block execution weight is defined as the weight that it takes to execute an *empty block*.
It is measured by constructing an empty block and measuring its executing time.
The result are written to a `block_weights.rs` file which is created from a template.
The file will contain the concrete weight value and various statistics about the measurements. For example:
The block execution weight is defined as the weight that it takes to execute an *empty block*.
It is measured by constructing an empty block and measuring its executing time.
The result are written to a `block_weights.rs` file which is created from a template.
The file will contain the concrete weight value and various statistics about the measurements. For example:
```rust
/// Time to execute an empty block.
/// Calculated by multiplying the *Average* with `1` and adding `0`.
@@ -30,21 +30,21 @@ The file will contain the concrete weight value and various statistics about the
/// 99th: 3_631_863
/// 95th: 3_595_674
/// 75th: 3_526_435
pub const BlockExecutionWeight: Weight = 3_532_484 * WEIGHT_PER_NANOS;
pub const BlockExecutionWeight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul(3_532_484);
```
In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block.
In this example it takes 3.5 ms to execute an empty block. That means that it always takes at least 3.5 ms to execute *any* block.
This constant weight is therefore added to each block to ensure that Substrate budgets enough time to execute it.
## ExtrinsicBaseWeight
The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic.
An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above.
The extrinsic base weight is defined as the weight that it takes to execute an *empty* extrinsic.
An *empty* extrinsic is also called a *NO-OP*. It does nothing and is the equivalent to the empty block form above.
The benchmark now constructs a block which is filled with only NO-OP extrinsics.
This block is then executed many times and the weights are measured.
The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`.
This block is then executed many times and the weights are measured.
The result is divided by the number of extrinsics in that block and the results are written to `extrinsic_weights.rs`.
The relevant section in the output file looks like this:
The relevant section in the output file looks like this:
```rust
/// Time to execute a NO-OP extrinsic, for example `System::remark`.
/// Calculated by multiplying the *Average* with `1` and adding `0`.
@@ -59,10 +59,10 @@ The relevant section in the output file looks like this:
/// 99th: 68_758
/// 95th: 67_843
/// 75th: 67_749
pub const ExtrinsicBaseWeight: Weight = 67_745 * WEIGHT_PER_NANOS;
pub const ExtrinsicBaseWeight: Weight = Weight::from_ref_time(67_745 * WEIGHT_PER_NANOS);
```
In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic.
In this example it takes 67.7 µs to execute a NO-OP extrinsic. That means that it always takes at least 67.7 µs to execute *any* extrinsic.
This constant weight is therefore added to each extrinsic to ensure that Substrate budgets enough time to execute it.
## Invocation
@@ -76,48 +76,48 @@ Output:
```pre
# BlockExecutionWeight
Running 10 warmups...
Executing block 100 times
Executing block 100 times
Per-block execution overhead [ns]:
Total: 353248430
Min: 3508416, Max: 3680498
Average: 3532484, Median: 3522111, Stddev: 27070.23
Percentiles 99th, 95th, 75th: 3631863, 3595674, 3526435
Percentiles 99th, 95th, 75th: 3631863, 3595674, 3526435
Writing weights to "block_weights.rs"
# Setup
Building block, this takes some time...
Building block, this takes some time...
Extrinsics per block: 12000
# ExtrinsicBaseWeight
Running 10 warmups...
Executing block 100 times
Executing block 100 times
Per-extrinsic execution overhead [ns]:
Total: 6774590
Min: 67561, Max: 69855
Average: 67745, Median: 67701, Stddev: 264.68
Percentiles 99th, 95th, 75th: 68758, 67843, 67749
Percentiles 99th, 95th, 75th: 68758, 67843, 67749
Writing weights to "extrinsic_weights.rs"
```
The complete command for Polkadot looks like this:
The complete command for Polkadot looks like this:
```sh
cargo run --profile=production -- benchmark overhead --chain=polkadot-dev --execution=wasm --wasm-execution=compiled --weight-path=runtime/polkadot/constants/src/weights/
```
This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory.
You can try the same for *Rococo* and to see that the results slightly differ.
This will overwrite the the [block_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/block_weights.rs) and [extrinsic_weights.rs](https://github.com/paritytech/polkadot/blob/c254e5975711a6497af256f6831e9a6c752d28f5/runtime/polkadot/constants/src/weights/extrinsic_weights.rs) files in the Polkadot runtime directory.
You can try the same for *Rococo* and to see that the results slightly differ.
👉 It is paramount to use `--profile=production`, `--execution=wasm` and `--wasm-execution=compiled` as the results are otherwise useless.
## Output Interpretation
Lower is better. The less weight the execution overhead needs, the better.
Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block.
Lower is better. The less weight the execution overhead needs, the better.
Since the weights of the overhead is charged per extrinsic and per block, a larger weight results in less extrinsics per block.
Minimizing this is important to have a large transaction throughput.
## Arguments
- `--chain` / `--dev` Set the chain specification.
- `--weight-path` Set the output directory or file to write the weights to.
- `--chain` / `--dev` Set the chain specification.
- `--weight-path` Set the output directory or file to write the weights to.
- `--repeat` Set the repetitions of both benchmarks.
- `--warmup` Set the rounds of warmup before measuring.
- `--execution` Should be set to `wasm` for correct results.
@@ -52,11 +52,12 @@ parameter_types! {
/// 99th: {{underscore stats.p99}}
/// 95th: {{underscore stats.p95}}
/// 75th: {{underscore stats.p75}}
pub const {{long_name}}Weight: Weight = {{underscore weight}} * WEIGHT_PER_NANOS;
pub const {{long_name}}Weight: Weight = WEIGHT_PER_NANOS.scalar_saturating_mul({{underscore weight}});
}
#[cfg(test)]
mod test_weights {
use super::*;
use frame_support::weights::constants;
/// Checks that the weight exists and is sane.
@@ -68,14 +69,14 @@ mod test_weights {
{{#if (eq short_name "block")}}
// At least 100 µs.
assert!(w >= 100 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs.");
assert!(w >= Weight::from_ref_time(100 * constants::WEIGHT_PER_MICROS), "Weight should be at least 100 µs.");
// At most 50 ms.
assert!(w <= 50 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms.");
assert!(w <= Weight::from_ref_time(50 * constants::WEIGHT_PER_MILLIS), "Weight should be at most 50 ms.");
{{else}}
// At least 10 µs.
assert!(w >= 10 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs.");
assert!(w >= Weight::from_ref_time(10 * constants::WEIGHT_PER_MICROS), "Weight should be at least 10 µs.");
// At most 1 ms.
assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms.");
assert!(w <= Weight::from_ref_time(constants::WEIGHT_PER_MILLIS), "Weight should be at most 1 ms.");
{{/if}}
}
}
@@ -15,7 +15,7 @@
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use frame_support::{traits::Get, weights::{RefTimeWeight, Weight}};
use sp_std::marker::PhantomData;
/// Weight functions for `{{pallet}}`.
@@ -33,22 +33,22 @@ impl<T: frame_system::Config> {{pallet}}::WeightInfo for WeightInfo<T> {
{{~#each benchmark.components as |c| ~}}
{{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}}
) -> Weight {
({{underscore benchmark.base_weight}} as Weight)
Weight::from_ref_time({{underscore benchmark.base_weight}} as RefTimeWeight)
{{#each benchmark.component_weight as |cw|}}
// Standard Error: {{underscore cw.error}}
.saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))
.saturating_add(Weight::from_ref_time({{underscore cw.slope}} as RefTimeWeight).scalar_saturating_mul({{cw.name}} as RefTimeWeight))
{{/each}}
{{#if (ne benchmark.base_reads "0")}}
.saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight))
.saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as RefTimeWeight))
{{/if}}
{{#each benchmark.component_reads as |cr|}}
.saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight)))
.saturating_add(T::DbWeight::get().reads(({{cr.slope}} as RefTimeWeight).saturating_mul({{cr.name}} as RefTimeWeight)))
{{/each}}
{{#if (ne benchmark.base_writes "0")}}
.saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight))
.saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as RefTimeWeight))
{{/if}}
{{#each benchmark.component_writes as |cw|}}
.saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)))
.saturating_add(T::DbWeight::get().writes(({{cw.slope}} as RefTimeWeight).saturating_mul({{cw.name}} as RefTimeWeight)))
{{/each}}
}
{{/each}}