time: optimize math by reducing fractions at compile time.

For example, `as_micros`, `from_micros` now are noops if tick rate is 1MHz.
This commit is contained in:
Dario Nieuwenhuis 2022-02-12 03:19:46 +01:00
parent eb922c4655
commit 640ddc9481
3 changed files with 21 additions and 10 deletions

View File

@ -1,7 +1,7 @@
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use super::TICKS_PER_SECOND; use super::{GCD_1K, GCD_1M, TICKS_PER_SECOND};
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -28,12 +28,12 @@ impl Duration {
/// Convert the `Duration` to milliseconds, rounding down. /// Convert the `Duration` to milliseconds, rounding down.
pub const fn as_millis(&self) -> u64 { pub const fn as_millis(&self) -> u64 {
self.ticks * 1000 / TICKS_PER_SECOND self.ticks * (1000 / GCD_1K) / (TICKS_PER_SECOND / GCD_1K)
} }
/// Convert the `Duration` to microseconds, rounding down. /// Convert the `Duration` to microseconds, rounding down.
pub const fn as_micros(&self) -> u64 { pub const fn as_micros(&self) -> u64 {
self.ticks * 1_000_000 / TICKS_PER_SECOND self.ticks * (1_000_000 / GCD_1M) / (TICKS_PER_SECOND / GCD_1M)
} }
/// Creates a duration from the specified number of clock ticks /// Creates a duration from the specified number of clock ticks
@ -51,7 +51,7 @@ impl Duration {
/// Creates a duration from the specified number of milliseconds /// Creates a duration from the specified number of milliseconds
pub const fn from_millis(millis: u64) -> Duration { pub const fn from_millis(millis: u64) -> Duration {
Duration { Duration {
ticks: millis * TICKS_PER_SECOND / 1000, ticks: millis * (TICKS_PER_SECOND / GCD_1K) / (1000 / GCD_1K),
} }
} }
@ -59,7 +59,7 @@ impl Duration {
/// NOTE: Delays this small may be inaccurate. /// NOTE: Delays this small may be inaccurate.
pub const fn from_micros(micros: u64) -> Duration { pub const fn from_micros(micros: u64) -> Duration {
Duration { Duration {
ticks: micros * TICKS_PER_SECOND / 1_000_000, ticks: micros * (TICKS_PER_SECOND / GCD_1M) / (1_000_000 / GCD_1M),
} }
} }

View File

@ -1,7 +1,7 @@
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::ops::{Add, AddAssign, Sub, SubAssign};
use super::{driver, Duration, TICKS_PER_SECOND}; use super::{driver, Duration, GCD_1K, GCD_1M, TICKS_PER_SECOND};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -31,14 +31,14 @@ impl Instant {
/// Create an Instant from a microsecond count since system boot. /// Create an Instant from a microsecond count since system boot.
pub const fn from_micros(micros: u64) -> Self { pub const fn from_micros(micros: u64) -> Self {
Self { Self {
ticks: micros * TICKS_PER_SECOND / 1_000_000, ticks: micros * (TICKS_PER_SECOND / GCD_1M) / (1_000_000 / GCD_1M),
} }
} }
/// Create an Instant from a millisecond count since system boot. /// Create an Instant from a millisecond count since system boot.
pub const fn from_millis(millis: u64) -> Self { pub const fn from_millis(millis: u64) -> Self {
Self { Self {
ticks: millis * TICKS_PER_SECOND / 1000, ticks: millis * (TICKS_PER_SECOND / GCD_1K) / (1000 / GCD_1K),
} }
} }
@ -61,12 +61,12 @@ impl Instant {
/// Milliseconds since system boot. /// Milliseconds since system boot.
pub const fn as_millis(&self) -> u64 { pub const fn as_millis(&self) -> u64 {
self.ticks * 1000 / TICKS_PER_SECOND self.ticks * (1000 / GCD_1K) / (TICKS_PER_SECOND / GCD_1K)
} }
/// Microseconds since system boot. /// Microseconds since system boot.
pub const fn as_micros(&self) -> u64 { pub const fn as_micros(&self) -> u64 {
self.ticks * 1_000_000 / TICKS_PER_SECOND self.ticks * (1_000_000 / GCD_1M) / (TICKS_PER_SECOND / GCD_1M)
} }
/// Duration between this Instant and another Instant /// Duration between this Instant and another Instant

View File

@ -75,3 +75,14 @@ const TPS: u64 = 1_000_000;
/// allow you to choose a tick rate with Cargo features of their own. You should not /// allow you to choose a tick rate with Cargo features of their own. You should not
/// set the `time-tick-*` features for embassy yourself as an end user. /// set the `time-tick-*` features for embassy yourself as an end user.
pub const TICKS_PER_SECOND: u64 = TPS; pub const TICKS_PER_SECOND: u64 = TPS;
const fn gcd(a: u64, b: u64) -> u64 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
pub(crate) const GCD_1K: u64 = gcd(TICKS_PER_SECOND, 1_000);
pub(crate) const GCD_1M: u64 = gcd(TICKS_PER_SECOND, 1_000_000);