1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-06-16 04:58:45 +00:00

perf(core): encode Timer using a single u32

[no changelog]
This commit is contained in:
Roman Zeyde 2025-04-22 18:55:34 +03:00 committed by Roman Zeyde
parent 9037c398eb
commit f20c2d551d
2 changed files with 53 additions and 37 deletions

View File

@ -1,6 +1,7 @@
use heapless::Vec; use heapless::Vec;
use crate::{ use crate::{
error::Error,
strutil::{ShortString, TString}, strutil::{ShortString, TString},
time::Duration, time::Duration,
ui::{ ui::{
@ -359,53 +360,68 @@ pub enum EventPropagation {
pub struct TimerToken(u32); pub struct TimerToken(u32);
impl TimerToken { impl TimerToken {
/// Value of an invalid (or missing) token. pub const fn from_raw(raw: u32) -> Result<Self, Error> {
pub const INVALID: TimerToken = TimerToken(0); if raw == Timer::INVALID_TOKEN_VALUE || raw > Timer::TOKEN_BITMASK {
/// Reserved value of the animation frame timer. return Err(Error::ValueError(c"Invalid token"));
pub const ANIM_FRAME: TimerToken = TimerToken(1); }
Ok(Self(raw))
/// Starting token value
const STARTING_TOKEN: u32 = 2;
pub const fn from_raw(raw: u32) -> Self {
Self(raw)
} }
pub const fn into_raw(self) -> u32 { pub const fn into_raw(self) -> u32 {
self.0 self.0
} }
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
pub struct Timer(u32);
pub fn next_token() -> Self { impl Timer {
static mut NEXT_TOKEN: TimerToken = Self(TimerToken::STARTING_TOKEN); /// Value of an invalid (or missing) token.
const INVALID_TOKEN_VALUE: u32 = 0;
/// Reserved value of the animation frame timer.
const ANIM_FRAME: TimerToken = TimerToken(1);
/// Starting token value
const STARTING_TOKEN: u32 = 2;
const IS_RUNNING_BITMASK: u32 = 1 << 31;
const TOKEN_BITMASK: u32 = Timer::IS_RUNNING_BITMASK - 1;
fn next_token() -> u32 {
static mut NEXT_TOKEN: u32 = Timer::STARTING_TOKEN;
// SAFETY: we are in single-threaded environment // SAFETY: we are in single-threaded environment
let token = unsafe { NEXT_TOKEN }; let token = unsafe { NEXT_TOKEN };
debug_assert!(token >= Timer::STARTING_TOKEN);
debug_assert!(token <= Timer::TOKEN_BITMASK);
let next = { let next = {
if token.0 == u32::MAX { if token == Timer::TOKEN_BITMASK {
TimerToken(Self::STARTING_TOKEN) Self::STARTING_TOKEN
} else { } else {
TimerToken(token.0 + 1) token + 1
} }
}; };
// SAFETY: we are in single-threaded environment // SAFETY: we are in single-threaded environment
unsafe { NEXT_TOKEN = next }; unsafe { NEXT_TOKEN = next };
token token
} }
}
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] /// Create a new stopped timer.
pub struct Timer {
token: TimerToken,
running: bool,
}
impl Timer {
/// Create a new timer.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self(Timer::INVALID_TOKEN_VALUE)
token: TimerToken::INVALID,
running: false,
} }
const fn token(&self) -> TimerToken {
TimerToken(self.0 & Timer::TOKEN_BITMASK)
}
const fn is_invalid(&self) -> bool {
self.token().0 == Timer::INVALID_TOKEN_VALUE
}
const fn is_running(&self) -> bool {
self.0 & Timer::IS_RUNNING_BITMASK != 0
} }
/// Start this timer for a given duration. /// Start this timer for a given duration.
@ -413,11 +429,11 @@ impl Timer {
/// Requests the internal timer token to be scheduled to `duration` from /// Requests the internal timer token to be scheduled to `duration` from
/// now. If the timer was already running, its token is rescheduled. /// now. If the timer was already running, its token is rescheduled.
pub fn start(&mut self, ctx: &mut EventCtx, duration: Duration) { pub fn start(&mut self, ctx: &mut EventCtx, duration: Duration) {
if self.token == TimerToken::INVALID { if self.is_invalid() {
self.token = TimerToken::next_token(); self.0 = Timer::next_token(); // new stopped timer
} }
self.running = true; self.0 |= Timer::IS_RUNNING_BITMASK;
ctx.register_timer(self.token, duration); ctx.register_timer(self.token(), duration);
} }
/// Stop the timer. /// Stop the timer.
@ -426,7 +442,7 @@ impl Timer {
/// means that _some_ scheduled task might keep running, but this timer /// means that _some_ scheduled task might keep running, but this timer
/// will not trigger when that task expires. /// will not trigger when that task expires.
pub fn stop(&mut self) { pub fn stop(&mut self) {
self.running = false; self.0 &= Timer::TOKEN_BITMASK;
} }
/// Check if the timer has expired. /// Check if the timer has expired.
@ -434,8 +450,8 @@ impl Timer {
/// Returns `true` if the given event is a timer event and the token matches /// Returns `true` if the given event is a timer event and the token matches
/// the internal token of this timer. /// the internal token of this timer.
pub fn expire(&mut self, event: Event) -> bool { pub fn expire(&mut self, event: Event) -> bool {
if self.running && event == Event::Timer(self.token) { if self.is_running() && event == Event::Timer(self.token()) {
self.running = false; self.stop();
true true
} else { } else {
false false
@ -458,7 +474,7 @@ pub struct EventCtx {
impl EventCtx { impl EventCtx {
/// Timer token dedicated for animation frames. /// Timer token dedicated for animation frames.
pub const ANIM_FRAME_TIMER: TimerToken = TimerToken(1); pub const ANIM_FRAME_TIMER: TimerToken = Timer::ANIM_FRAME;
/// How long into the future we should schedule the animation frame timer. /// How long into the future we should schedule the animation frame timer.
const ANIM_FRAME_DURATION: Duration = Duration::from_millis(1); const ANIM_FRAME_DURATION: Duration = Duration::from_millis(1);

View File

@ -444,7 +444,7 @@ impl TryFrom<Obj> for TimerToken {
fn try_from(value: Obj) -> Result<Self, Self::Error> { fn try_from(value: Obj) -> Result<Self, Self::Error> {
let raw: u32 = value.try_into()?; let raw: u32 = value.try_into()?;
let this = Self::from_raw(raw); let this = Self::from_raw(raw)?;
Ok(this) Ok(this)
} }
} }