From 640ddc948190fe9a24d6db616cb103d6a94f81f9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 12 Feb 2022 03:19:46 +0100 Subject: [PATCH] time: optimize math by reducing fractions at compile time. For example, `as_micros`, `from_micros` now are noops if tick rate is 1MHz. --- embassy/src/time/duration.rs | 10 +++++----- embassy/src/time/instant.rs | 10 +++++----- embassy/src/time/mod.rs | 11 +++++++++++ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/embassy/src/time/duration.rs b/embassy/src/time/duration.rs index e196a00c..47b413f4 100644 --- a/embassy/src/time/duration.rs +++ b/embassy/src/time/duration.rs @@ -1,7 +1,7 @@ use core::fmt; 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)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -28,12 +28,12 @@ impl Duration { /// Convert the `Duration` to milliseconds, rounding down. 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. 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 @@ -51,7 +51,7 @@ impl Duration { /// Creates a duration from the specified number of milliseconds pub const fn from_millis(millis: u64) -> 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. pub const fn from_micros(micros: u64) -> Duration { Duration { - ticks: micros * TICKS_PER_SECOND / 1_000_000, + ticks: micros * (TICKS_PER_SECOND / GCD_1M) / (1_000_000 / GCD_1M), } } diff --git a/embassy/src/time/instant.rs b/embassy/src/time/instant.rs index aff83be2..71adbeb3 100644 --- a/embassy/src/time/instant.rs +++ b/embassy/src/time/instant.rs @@ -1,7 +1,7 @@ use core::fmt; 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)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -31,14 +31,14 @@ impl Instant { /// Create an Instant from a microsecond count since system boot. pub const fn from_micros(micros: u64) -> 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. pub const fn from_millis(millis: u64) -> 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. 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. 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 diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs index c8971bd1..ac84b8f8 100644 --- a/embassy/src/time/mod.rs +++ b/embassy/src/time/mod.rs @@ -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 /// set the `time-tick-*` features for embassy yourself as an end user. 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);