perf: vectored interrupt improvements
Instead of building a table of _all_ configured interrupts, we now only check the currently _pending_ interrupts configuration status. This means in the best case scenario we only ever do _one_ lookup instead of the 60~ we did before. Tested on esp32c3, gpio_interrupt: Before: 850cycles from `handler_interrupts` to the actual handler After: 125cycles
This commit is contained in:
parent
1d02bf87c3
commit
de379897a9
@ -246,7 +246,7 @@ mod vectored {
|
|||||||
|
|
||||||
/// Get the interrupts configured for the core
|
/// Get the interrupts configured for the core
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_configured_interrupts(_core: Cpu) -> [u128; 15] {
|
fn get_configured_interrupts(_core: Cpu, mut status: u128) -> [u128; 15] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||||
let intr_map_base = intr.mac_intr_map.as_ptr();
|
let intr_map_base = intr.mac_intr_map.as_ptr();
|
||||||
@ -254,8 +254,9 @@ mod vectored {
|
|||||||
|
|
||||||
let mut prios = [0u128; 15];
|
let mut prios = [0u128; 15];
|
||||||
|
|
||||||
for i in 0..get_interrupt_count() {
|
while status != 0 {
|
||||||
let i = i as isize;
|
let interrupt_nr = status.trailing_zeros();
|
||||||
|
let i = interrupt_nr as isize;
|
||||||
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
|
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
|
||||||
// safety: cast is safe because of repr(u32)
|
// safety: cast is safe because of repr(u32)
|
||||||
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
|
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
|
||||||
@ -264,21 +265,13 @@ mod vectored {
|
|||||||
.read_volatile();
|
.read_volatile();
|
||||||
|
|
||||||
prios[prio as usize] |= 1 << i;
|
prios[prio as usize] |= 1 << i;
|
||||||
|
status &= !(1u128 << interrupt_nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
prios
|
prios
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_interrupt_count() -> usize {
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "esp32c3")] {
|
|
||||||
62
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Interrupt Error
|
/// Interrupt Error
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -309,7 +302,7 @@ mod vectored {
|
|||||||
// so we clear it anyway
|
// so we clear it anyway
|
||||||
clear(crate::get_core(), cpu_intr);
|
clear(crate::get_core(), cpu_intr);
|
||||||
|
|
||||||
let configured_interrupts = get_configured_interrupts(crate::get_core());
|
let configured_interrupts = get_configured_interrupts(crate::get_core(), status);
|
||||||
let mut interrupt_mask = status & configured_interrupts[cpu_intr as usize];
|
let mut interrupt_mask = status & configured_interrupts[cpu_intr as usize];
|
||||||
while interrupt_mask != 0 {
|
while interrupt_mask != 0 {
|
||||||
let interrupt_nr = interrupt_mask.trailing_zeros();
|
let interrupt_nr = interrupt_mask.trailing_zeros();
|
||||||
|
|||||||
@ -252,7 +252,7 @@ mod vectored {
|
|||||||
|
|
||||||
/// Get the interrupts configured for the core
|
/// Get the interrupts configured for the core
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_configured_interrupts(core: Cpu) -> [u128; 7] {
|
fn get_configured_interrupts(core: Cpu, mut status: u128) -> [u128; 7] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let intr_map_base = match core {
|
let intr_map_base = match core {
|
||||||
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
|
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
|
||||||
@ -264,32 +264,22 @@ mod vectored {
|
|||||||
|
|
||||||
let mut levels = [0u128; 7];
|
let mut levels = [0u128; 7];
|
||||||
|
|
||||||
for i in 0..get_interrupt_count() {
|
while status != 0 {
|
||||||
let i = i as isize;
|
let interrupt_nr = status.trailing_zeros();
|
||||||
|
let i = interrupt_nr as isize;
|
||||||
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
|
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
|
||||||
// safety: cast is safe because of repr(u32)
|
// safety: cast is safe because of repr(u32)
|
||||||
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
|
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
|
||||||
let level = cpu_interrupt.level() as u8 as usize;
|
let level = cpu_interrupt.level() as u8 as usize;
|
||||||
|
|
||||||
levels[level] |= 1 << i;
|
levels[level] |= 1 << i;
|
||||||
|
status &= !(1u128 << interrupt_nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
levels
|
levels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_interrupt_count() -> usize {
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "esp32")] {
|
|
||||||
68
|
|
||||||
} else if #[cfg(feature = "esp32s2")] {
|
|
||||||
94
|
|
||||||
} else if #[cfg(feature = "esp32s3")] {
|
|
||||||
98
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
|
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
|
||||||
let cpu_interrupt =
|
let cpu_interrupt =
|
||||||
interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;
|
interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;
|
||||||
@ -389,7 +379,8 @@ mod vectored {
|
|||||||
handler(level);
|
handler(level);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let interrupt_levels = get_configured_interrupts(crate::get_core());
|
let status = get_status(crate::get_core());
|
||||||
|
let interrupt_levels = get_configured_interrupts(crate::get_core(), status);
|
||||||
if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
|
if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
|
||||||
let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_EDGE;
|
let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_EDGE;
|
||||||
let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
|
let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
|
||||||
@ -412,8 +403,7 @@ mod vectored {
|
|||||||
} else {
|
} else {
|
||||||
// finally check periperal sources and fire of handlers from pac
|
// finally check periperal sources and fire of handlers from pac
|
||||||
// peripheral mapped interrupts are cleared by the peripheral
|
// peripheral mapped interrupts are cleared by the peripheral
|
||||||
let interrupt_mask =
|
let interrupt_mask = status & interrupt_levels[level as usize];
|
||||||
get_status(crate::get_core()) & interrupt_levels[level as usize];
|
|
||||||
let interrupt_nr = interrupt_mask.trailing_zeros();
|
let interrupt_nr = interrupt_mask.trailing_zeros();
|
||||||
|
|
||||||
// Interrupt::try_from can fail if interrupt already de-asserted:
|
// Interrupt::try_from can fail if interrupt already de-asserted:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user