perf(kernel): linked cap tree, translate-based page lookup, next-fit frames/heap, targeted dequeue; host benches
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -47,6 +47,8 @@ fn any_table() -> FrameTable<N> {
|
||||
total: N,
|
||||
frames,
|
||||
free,
|
||||
// Next-fit may resume anywhere, so the proofs start it anywhere.
|
||||
cursor: kani::any::<usize>() % (N + 1),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user