perf(kernel): linked cap tree, translate-based page lookup, next-fit frames/heap, targeted dequeue; host benches

This commit is contained in:
2026-10-27 01:33:26 +01:00
parent 19aeabd86d
commit 2a8a5b0c27
24 changed files with 923 additions and 200 deletions

View File

@@ -50,6 +50,8 @@ pub struct FrameTable<const N: usize = MAX_FRAMES> {
total: usize,
frames: [Option<FrameUse>; N],
free: usize,
/// Where the next allocation starts looking: just past the last one.
cursor: usize,
}
impl<const N: usize> FrameTable<N> {
@@ -60,6 +62,7 @@ impl<const N: usize> FrameTable<N> {
total,
frames: [None; N],
free: total,
cursor: 0,
}
}
@@ -101,14 +104,21 @@ impl<const N: usize> FrameTable<N> {
self.frames.get(self.index_of(pa)?)?.as_ref()
}
/// Next-fit: searches from just past the previous allocation and wraps
/// once, so a run of allocations costs O(1) each instead of rescanning
/// the allocated prefix every time.
pub fn alloc(&mut self, usage: FrameUse) -> Option<PhysicalAddress> {
let (idx, slot) = self
.live_mut()
.iter_mut()
.enumerate()
.find(|(_, f)| f.is_none())?;
*slot = Some(usage);
if self.free == 0 {
return None;
}
let total = self.total;
let start = self.cursor.min(total);
let idx = (start..total)
.chain(0..start)
.find(|&i| self.frames.get(i).is_some_and(Option::is_none))?;
*self.frames.get_mut(idx)? = Some(usage);
self.free -= 1;
self.cursor = idx + 1;
Some(self.address_of(idx))
}
@@ -168,6 +178,29 @@ impl<const N: usize> FrameTable<N> {
}
/// The frame mapped at `va` in `owner`, if `owner` holds it as a user page.
/// The perms of the frame at `pa` if it is `owner`'s user page at
/// `va`; `None` for any other frame. O(1): the caller supplies the
/// frame, this only confirms it.
pub fn user_at(
&self,
pa: PhysicalAddress,
owner: ProcessId,
va: VirtualAddress,
) -> Option<PagePerms> {
let page = u32::try_from(va.raw() / PAGE_SIZE).ok()?;
if !va.raw().is_multiple_of(PAGE_SIZE) {
return None;
}
match self.get(pa)? {
FrameUse::User {
owner: o,
page: p,
perms,
} if *o == owner && *p == page => Some(*perms),
_ => None,
}
}
pub fn find_user(
&self,
owner: ProcessId,