Correct arithmetical semantic of PerDispatchClass (#13194)

* Fix PerDispatchClass arithmetic

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Test PerDispatchClass arithmetic

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add helpers for Weight

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove stale doc

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Dont mention Polkadot in Substrate

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove saturating_ prefix

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix usage

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
This commit is contained in:
Oliver Tale-Yazdi
2023-01-26 17:13:38 +01:00
committed by GitHub
parent 702963fea4
commit 9601b479e4
6 changed files with 307 additions and 36 deletions
-7
View File
@@ -16,13 +16,6 @@
// limitations under the License.
//! # Primitives for transaction weighting.
//!
//! Latest machine specification used to benchmark are:
//! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01
//! - 2x Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz
//! - 4GB RAM
//! - Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64)
//! - rustc 1.42.0 (b8cedc004 2020-03-09)
#![cfg_attr(not(feature = "std"), no_std)]
@@ -117,6 +117,11 @@ impl Weight {
Self { ref_time, proof_size }
}
/// Construct [`Weight`] from the same weight for all parts.
pub const fn from_all(value: u64) -> Self {
Self { ref_time: value, proof_size: value }
}
/// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of
/// all fields instead of overflowing.
pub const fn saturating_add(self, rhs: Self) -> Self {
@@ -167,6 +172,11 @@ impl Weight {
*self = self.saturating_add(amount);
}
/// Reduce [`Weight`] by `amount` via saturating subtraction.
pub fn saturating_reduce(&mut self, amount: Self) {
*self = self.saturating_sub(amount);
}
/// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred.
pub const fn checked_add(&self, rhs: &Self) -> Option<Self> {
let ref_time = match self.ref_time.checked_add(rhs.ref_time) {
@@ -222,6 +232,16 @@ impl Weight {
Some(Self { ref_time, proof_size })
}
/// Try to increase `self` by `amount` via checked addition.
pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
self.checked_add(&amount).map(|new_self| *self = new_self)
}
/// Try to reduce `self` by `amount` via checked subtraction.
pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
self.checked_sub(&amount).map(|new_self| *self = new_self)
}
/// Return a [`Weight`] where all fields are zero.
pub const fn zero() -> Self {
Self { ref_time: 0, proof_size: 0 }
@@ -352,6 +372,20 @@ where
}
}
#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))]
impl From<u64> for Weight {
fn from(value: u64) -> Self {
Self::from_parts(value, value)
}
}
#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))]
impl From<(u64, u64)> for Weight {
fn from(value: (u64, u64)) -> Self {
Self::from_parts(value.0, value.1)
}
}
macro_rules! weight_mul_per_impl {
($($t:ty),* $(,)?) => {
$(
@@ -459,4 +493,79 @@ mod tests {
assert!(!Weight::from_parts(0, 1).is_zero());
assert!(!Weight::MAX.is_zero());
}
#[test]
fn from_parts_works() {
assert_eq!(Weight::from_parts(0, 0), Weight { ref_time: 0, proof_size: 0 });
assert_eq!(Weight::from_parts(5, 5), Weight { ref_time: 5, proof_size: 5 });
assert_eq!(
Weight::from_parts(u64::MAX, u64::MAX),
Weight { ref_time: u64::MAX, proof_size: u64::MAX }
);
}
#[test]
fn from_all_works() {
assert_eq!(Weight::from_all(0), Weight::from_parts(0, 0));
assert_eq!(Weight::from_all(5), Weight::from_parts(5, 5));
assert_eq!(Weight::from_all(u64::MAX), Weight::from_parts(u64::MAX, u64::MAX));
}
#[test]
fn from_u64_works() {
assert_eq!(Weight::from_all(0), 0_u64.into());
assert_eq!(Weight::from_all(123), 123_u64.into());
assert_eq!(Weight::from_all(u64::MAX), u64::MAX.into());
}
#[test]
fn from_u64_pair_works() {
assert_eq!(Weight::from_parts(0, 1), (0, 1).into());
assert_eq!(Weight::from_parts(123, 321), (123u64, 321u64).into());
assert_eq!(Weight::from_parts(u64::MAX, 0), (u64::MAX, 0).into());
}
#[test]
fn saturating_reduce_works() {
let mut weight = Weight::from_parts(10, 20);
weight.saturating_reduce(Weight::from_all(5));
assert_eq!(weight, Weight::from_parts(5, 15));
weight.saturating_reduce(Weight::from_all(5));
assert_eq!(weight, Weight::from_parts(0, 10));
weight.saturating_reduce(Weight::from_all(11));
assert!(weight.is_zero());
weight.saturating_reduce(Weight::from_all(u64::MAX));
assert!(weight.is_zero());
}
#[test]
fn checked_accrue_works() {
let mut weight = Weight::from_parts(10, 20);
assert!(weight.checked_accrue(Weight::from_all(2)).is_some());
assert_eq!(weight, Weight::from_parts(12, 22));
assert!(weight.checked_accrue(Weight::from_parts(u64::MAX, 0)).is_none());
assert!(weight.checked_accrue(Weight::from_parts(0, u64::MAX)).is_none());
assert_eq!(weight, Weight::from_parts(12, 22));
assert!(weight
.checked_accrue(Weight::from_parts(u64::MAX - 12, u64::MAX - 22))
.is_some());
assert_eq!(weight, Weight::MAX);
assert!(weight.checked_accrue(Weight::from_parts(1, 0)).is_none());
assert!(weight.checked_accrue(Weight::from_parts(0, 1)).is_none());
assert_eq!(weight, Weight::MAX);
}
#[test]
fn checked_reduce_works() {
let mut weight = Weight::from_parts(10, 20);
assert!(weight.checked_reduce(Weight::from_all(2)).is_some());
assert_eq!(weight, Weight::from_parts(8, 18));
assert!(weight.checked_reduce(Weight::from_parts(9, 0)).is_none());
assert!(weight.checked_reduce(Weight::from_parts(0, 19)).is_none());
assert_eq!(weight, Weight::from_parts(8, 18));
assert!(weight.checked_reduce(Weight::from_parts(8, 0)).is_some());
assert_eq!(weight, Weight::from_parts(0, 18));
assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some());
assert!(weight.is_zero());
}
}