This repository was archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Move WeightCounter to sp-weights
#12603
Merged
Merged
Changes from 3 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
139bc7f
Move WeightCounter to sp_weights
ggwpez c6ef48f
Rename to WeightMeter and test
ggwpez 8c70979
Fix pallet-scheduler for new usage
ggwpez 15b92a6
Update primitives/weights/src/weight_meter.rs
ggwpez e8a333d
More tests for can_accrue
ggwpez 76cc7db
Clippy
ggwpez c9d3b22
Remove defensive_accrue and fixup consumed_ratio
ggwpez 56672b3
Test
ggwpez 86e07c7
Merge branch 'master' into oty-weight-meter
gavofyork File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2022 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // 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. | ||
|
|
||
| //! Contains the `WeightMeter` primitive to meter weight usage. | ||
|
|
||
| use super::Weight; | ||
|
|
||
| use sp_arithmetic::Perbill; | ||
|
|
||
| /// Meters consumed weight and a hard limit for the maximal consumable weight. | ||
| /// | ||
| /// Can be used to check if enough weight for an operation is available before committing to it. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// ```rust | ||
| /// use sp_weights::{Weight, WeightMeter}; | ||
| /// | ||
| /// // The weight is limited to (10, 0). | ||
| /// let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); | ||
| /// // There is enough weight remaining for an operation with (5, 0) weight. | ||
| /// assert!(meter.check_accrue(Weight::from_parts(5, 0))); | ||
| /// // There is not enough weight remaining for an operation with (6, 0) weight. | ||
| /// assert!(!meter.check_accrue(Weight::from_parts(6, 0))); | ||
| /// ``` | ||
| #[derive(Debug, Clone)] | ||
| pub struct WeightMeter { | ||
| /// The already consumed weight. | ||
| pub consumed: Weight, | ||
|
|
||
| /// The maximal consumable weight. | ||
| pub limit: Weight, | ||
| } | ||
|
|
||
| impl WeightMeter { | ||
| /// Creates [`Self`] from a limit for the maximal consumable weight. | ||
| pub fn from_limit(limit: Weight) -> Self { | ||
| Self { consumed: Weight::zero(), limit } | ||
| } | ||
|
|
||
| /// Creates [`Self`] with the maximal possible limit for the consumable weight. | ||
| pub fn max_limit() -> Self { | ||
| Self::from_limit(Weight::MAX) | ||
| } | ||
|
|
||
| /// The remaining weight that can be still consumed. | ||
| pub fn remaining(&self) -> Weight { | ||
| self.limit.saturating_sub(self.consumed) | ||
| } | ||
|
|
||
| /// The ratio of consumed weight to the limit. | ||
| /// | ||
| /// Calculates one ratio per component and returns the largest. | ||
| pub fn remaining_ratio(&self) -> Perbill { | ||
| let time = Perbill::from_rational(self.consumed.ref_time(), self.limit.ref_time()); | ||
| let pov = Perbill::from_rational(self.consumed.proof_size(), self.limit.proof_size()); | ||
| time.max(pov) | ||
| } | ||
|
|
||
| /// Consume some weight and defensively fail if it is over the limit or would saturate the | ||
| /// arithmetic type. | ||
| pub fn defensive_accrue(&mut self, w: Weight) { | ||
| let res = self.check_accrue(w); | ||
| debug_assert!(res, "Weight meter exhausted; {} + {} > {}", &self.consumed, &w, &self.limit); | ||
| } | ||
|
|
||
| /// Check if the given weight can be consumed. Do nothing if not. | ||
| pub fn check_accrue(&mut self, w: Weight) -> bool { | ||
| self.consumed.checked_add(&w).map_or(false, |test| { | ||
| if test.any_gt(self.limit) { | ||
| false | ||
| } else { | ||
| self.consumed = test; | ||
| true | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| /// Check if the given weight can be consumed. | ||
| pub fn can_accrue(&self, w: Weight) -> bool { | ||
| self.consumed.checked_add(&w).map_or(false, |t| t.all_lte(self.limit)) | ||
ggwpez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use crate::*; | ||
|
|
||
| #[test] | ||
| fn weight_meter_remaining_works() { | ||
| let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(5, 0)); | ||
| assert_eq!(meter.consumed, Weight::from_parts(5, 0)); | ||
| assert_eq!(meter.remaining(), Weight::from_parts(5, 20)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(2, 10)); | ||
| assert_eq!(meter.consumed, Weight::from_parts(7, 10)); | ||
| assert_eq!(meter.remaining(), Weight::from_parts(3, 10)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(3, 10)); | ||
| assert_eq!(meter.consumed, Weight::from_parts(10, 20)); | ||
| assert_eq!(meter.remaining(), Weight::from_parts(0, 0)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn weight_meter_check_and_can_accrue_works() { | ||
| let mut meter = WeightMeter::max_limit(); | ||
|
|
||
| assert!(meter.can_accrue(Weight::from_parts(u64::MAX, 0))); | ||
| assert!(meter.check_accrue(Weight::from_parts(u64::MAX, 0))); | ||
|
|
||
| assert!(meter.can_accrue(Weight::from_parts(0, u64::MAX))); | ||
| assert!(meter.check_accrue(Weight::from_parts(0, u64::MAX))); | ||
|
|
||
| assert!(!meter.can_accrue(Weight::from_parts(0, 1))); | ||
| assert!(!meter.check_accrue(Weight::from_parts(0, 1))); | ||
|
|
||
| assert!(!meter.can_accrue(Weight::from_parts(1, 0))); | ||
| assert!(!meter.check_accrue(Weight::from_parts(1, 0))); | ||
|
|
||
| assert!(meter.can_accrue(Weight::zero())); | ||
| assert!(meter.check_accrue(Weight::zero())); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected = "Weight meter exhausted")] | ||
| fn weight_meter_defensive_accrue_works() { | ||
| let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 0)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(11, 0)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn remaining_ratio_works() { | ||
| let mut meter = WeightMeter::from_limit(Weight::from_parts(10, 20)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(5, 0)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(50)); | ||
| meter.defensive_accrue(Weight::from_parts(0, 12)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(60)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(2, 0)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(70)); | ||
| meter.defensive_accrue(Weight::from_parts(0, 4)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(80)); | ||
|
|
||
| meter.defensive_accrue(Weight::from_parts(3, 0)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(100)); | ||
| meter.defensive_accrue(Weight::from_parts(0, 4)); | ||
| assert_eq!(meter.remaining_ratio(), Perbill::from_percent(100)); | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.