From 3ab577aa606d3aed25da5fb3e4ea3baf7a7a220c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 9 Apr 2024 08:29:58 -0700 Subject: [PATCH] perf(d1): optimize interrupt vectoring by indexing Currently, the interrupt vector dispatch code uses a linear search over the interrupt vector array by checking each vector's ID against the interrupt number being dispatched. This is inefficient; because we already generate the vector array in order, we can simply index into it, which is _O_(1) instead of _O_(_ninterrupts_). This commit changes the existing code to do that. We can rely on the ordering being correct as it's generated by a `const fn` that should always output the same order. However, I've also added debug assertions that the index and ID match, just in case the table somehow gets corrupted or something. I don't think this is really that necessary, but it seemed nice to have. --- platforms/allwinner-d1/d1-core/src/plic.rs | 42 +++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/platforms/allwinner-d1/d1-core/src/plic.rs b/platforms/allwinner-d1/d1-core/src/plic.rs index 6e885e5e..4abaee79 100644 --- a/platforms/allwinner-d1/d1-core/src/plic.rs +++ b/platforms/allwinner-d1/d1-core/src/plic.rs @@ -98,8 +98,14 @@ impl Plic { let claim_u16 = claim as u16; // Is this a known interrupt? - let handler = INTERRUPT_ARRAY.iter().find(|i| i.id == claim_u16); - if let Some(Vectored { id: _id, handler }) = handler { + let handler = INTERRUPT_ARRAY.get(claim_u16 as usize); + if let Some(Vectored { id, handler }) = handler { + debug_assert_eq!( + *id, claim_u16, + "FLAGRANT ERROR: interrupt ID ({id}) does not match index \ + ({claim_u16}); perhaps the interrupt dispatch table has \ + somehow been corrupted?" + ); let ptr = handler.load(Ordering::SeqCst); // todo: ordering if !ptr.is_null() { let hdlr = ptr as *mut fn() as fn(); @@ -118,10 +124,17 @@ impl Plic { } pub unsafe fn register(&self, interrupt: Interrupt, new_hdl: fn()) { - let v = INTERRUPT_ARRAY.iter().find(|v| v.id == interrupt as u16); - if let Some(Vectored { id: _id, handler }) = v { - handler.store(new_hdl as *mut fn() as *mut (), Ordering::Release); - } + let idx = interrupt as u16; + let Some(Vectored { id, handler }) = INTERRUPT_ARRAY.get(idx as usize) else { + panic!("interrupt not found in dispatch table: {interrupt:?} (index {idx})") + }; + debug_assert_eq!( + *id, idx, + "FLAGRANT ERROR: interrupt ID for {interrupt:?} (id) does not \ + match index ({idx}); perhaps the interrupt dispatch table has \ + somehow been corrupted?" + ); + handler.store(new_hdl as *mut fn() as *mut (), Ordering::Release); } pub unsafe fn activate(&self, interrupt: Interrupt, prio: Priority) -> Result<(), MaskError> { @@ -138,16 +151,19 @@ impl Plic { } fn can_mask(&self, interrupt: Interrupt) -> Result<(), MaskError> { - let v = INTERRUPT_ARRAY - .iter() - .find(|v| v.id == interrupt as u16) + let &Vectored { id, ref handler } = INTERRUPT_ARRAY + .get(interrupt as usize) .ok_or(MaskError::NotFound(interrupt))?; - if v.handler.load(Ordering::SeqCst).is_null() { - Err(MaskError::NoHandler(interrupt)) - } else { - Ok(()) + if id != interrupt as u16 { + return Err(MaskError::NotFound(interrupt)); + } + + if handler.load(Ordering::SeqCst).is_null() { + return Err(MaskError::NoHandler(interrupt)); } + + Ok(()) } #[inline(always)]