optimize/timers: Get rid of the while loop in Timer::update.
Profiling with 'perf' I discovered that too much time was spent inside Timer::update when the prescalar was 0 (frequency of 1 cycle). This was due to the while loop I used. I optimized this loop out and there is an appearent performance increase. Former-commit-id: d228450625fad003f054e3161f6eeee888245cac
This commit is contained in:
parent
f0aa671674
commit
c4c8163b0e
|
@ -5,18 +5,19 @@ use super::sysbus::SysBus;
|
||||||
use num::FromPrimitive;
|
use num::FromPrimitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
const SHIFT_LUT: [usize; 4] = [0, 6, 8, 10];
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
// registers
|
// registers
|
||||||
pub ctl: TimerCtl,
|
pub ctl: TimerCtl,
|
||||||
pub data: u16,
|
pub data: u16,
|
||||||
|
|
||||||
irq: Interrupt,
|
|
||||||
|
|
||||||
timer_id: usize,
|
|
||||||
pub initial_data: u16,
|
pub initial_data: u16,
|
||||||
|
|
||||||
pub cycles: usize,
|
irq: Interrupt,
|
||||||
|
timer_id: usize,
|
||||||
|
cycles: usize,
|
||||||
|
prescalar_shift: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
|
@ -31,37 +32,40 @@ impl Timer {
|
||||||
ctl: TimerCtl(0),
|
ctl: TimerCtl(0),
|
||||||
initial_data: 0,
|
initial_data: 0,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
|
prescalar_shift: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frequency(&self) -> usize {
|
#[inline]
|
||||||
match self.ctl.prescalar() {
|
fn ticks_to_overflow(&self) -> u32 {
|
||||||
0 => 1,
|
0x1_0000 - (self.data as u32)
|
||||||
1 => 64,
|
|
||||||
2 => 256,
|
|
||||||
3 => 1024,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// updates the timer with 'cycles' amount of cycles, returns the number of times it overflowed
|
/// increments the timer with an amount of ticks
|
||||||
fn update(&mut self, cycles: usize, irqs: &mut IrqBitmask) -> usize {
|
/// returns the number of times it overflowed
|
||||||
self.cycles += cycles;
|
fn update(&mut self, ticks: usize, irqs: &mut IrqBitmask) -> usize {
|
||||||
|
let mut ticks = ticks as u32;
|
||||||
let mut num_overflows = 0;
|
let mut num_overflows = 0;
|
||||||
let freq = self.frequency();
|
|
||||||
while self.cycles >= freq {
|
let ticks_remaining = self.ticks_to_overflow();
|
||||||
self.cycles -= freq;
|
|
||||||
self.data = self.data.wrapping_add(1);
|
if ticks >= ticks_remaining {
|
||||||
if self.data == 0 {
|
num_overflows += 1;
|
||||||
if self.ctl.irq_enabled() {
|
ticks -= ticks_remaining;
|
||||||
irqs.add_irq(self.irq);
|
self.data = self.initial_data;
|
||||||
}
|
|
||||||
self.data = self.initial_data;
|
let ticks_remaining = self.ticks_to_overflow();
|
||||||
num_overflows += 1;
|
num_overflows += ticks / ticks_remaining;
|
||||||
|
ticks = ticks % ticks_remaining;
|
||||||
|
|
||||||
|
if self.ctl.irq_enabled() {
|
||||||
|
irqs.add_irq(self.irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
num_overflows
|
self.data += ticks as u16;
|
||||||
|
|
||||||
|
num_overflows as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +99,13 @@ impl Timers {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_timer_ctl(&mut self, id: usize, value: u16) {
|
pub fn write_timer_ctl(&mut self, id: usize, value: u16) {
|
||||||
|
let new_ctl = TimerCtl(value);
|
||||||
let old_enabled = self[id].ctl.enabled();
|
let old_enabled = self[id].ctl.enabled();
|
||||||
self[id].ctl.0 = value;
|
let new_enabled = new_ctl.enabled();
|
||||||
let new_enabled = self[id].ctl.enabled();
|
let cascade = new_ctl.cascade();
|
||||||
let cascade = self.timers[id].ctl.cascade();
|
self[id].cycles = 0;
|
||||||
|
self[id].prescalar_shift = SHIFT_LUT[new_ctl.prescalar() as usize];
|
||||||
|
self[id].ctl = new_ctl;
|
||||||
if new_enabled && !cascade {
|
if new_enabled && !cascade {
|
||||||
self.running_timers |= 1 << id;
|
self.running_timers |= 1 << id;
|
||||||
} else {
|
} else {
|
||||||
|
@ -164,7 +171,12 @@ impl Timers {
|
||||||
|
|
||||||
if !self.timers[id].ctl.cascade() {
|
if !self.timers[id].ctl.cascade() {
|
||||||
let timer = &mut self.timers[id];
|
let timer = &mut self.timers[id];
|
||||||
let num_overflows = timer.update(cycles, irqs);
|
|
||||||
|
let cycles = timer.cycles + cycles;
|
||||||
|
let inc = cycles >> timer.prescalar_shift;
|
||||||
|
let num_overflows = timer.update(inc, irqs);
|
||||||
|
timer.cycles = cycles & ((1 << timer.prescalar_shift) - 1);
|
||||||
|
|
||||||
if num_overflows > 0 {
|
if num_overflows > 0 {
|
||||||
if id != 3 {
|
if id != 3 {
|
||||||
let next_timer = &mut self.timers[id + 1];
|
let next_timer = &mut self.timers[id + 1];
|
||||||
|
|
Reference in a new issue