perf(kernel): linked cap tree, translate-based page lookup, next-fit frames/heap, targeted dequeue; host benches
This commit is contained in:
120
crates/domain/src/capability/tree_tests.rs
Normal file
120
crates/domain/src/capability/tree_tests.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use super::derivation::descendants;
|
||||
use super::tree::CapTree;
|
||||
|
||||
const N: usize = 12;
|
||||
|
||||
/// The tree as a plain parent array, updated by the rules the tree must
|
||||
/// follow; `descendants` from derivation.rs answers subtree questions.
|
||||
struct Model {
|
||||
live: [bool; N],
|
||||
parents: [Option<u16>; N],
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn detach(&mut self, i: usize) {
|
||||
let grandparent = self.parents[i];
|
||||
for p in self.parents.iter_mut() {
|
||||
if *p == Some(i as u16) {
|
||||
*p = grandparent;
|
||||
}
|
||||
}
|
||||
self.live[i] = false;
|
||||
self.parents[i] = None;
|
||||
}
|
||||
|
||||
fn below(&self, root: usize) -> [bool; N] {
|
||||
let mut d = descendants(&self.parents, root);
|
||||
d[root] = false;
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
struct Rng(u64);
|
||||
impl Rng {
|
||||
fn below(&mut self, n: usize) -> usize {
|
||||
self.0 ^= self.0 << 13;
|
||||
self.0 ^= self.0 >> 7;
|
||||
self.0 ^= self.0 << 17;
|
||||
(self.0 % n as u64) as usize
|
||||
}
|
||||
}
|
||||
|
||||
fn check(t: &CapTree<N>, m: &Model) {
|
||||
for i in 0..N {
|
||||
assert_eq!(t.is_live(i), m.live[i], "liveness of {i}");
|
||||
assert_eq!(t.parent(i), m.parents[i].map(usize::from), "parent of {i}");
|
||||
if !m.live[i] {
|
||||
continue;
|
||||
}
|
||||
let mut out = [0u16; N];
|
||||
let n = t.descendants(i, &mut out);
|
||||
let mut got = [false; N];
|
||||
for d in &out[..n] {
|
||||
assert!(!got[*d as usize], "{d} listed twice under {i}");
|
||||
got[*d as usize] = true;
|
||||
}
|
||||
assert_eq!(got, m.below(i), "subtree of {i}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn matches_the_parent_array_model_under_random_operations() {
|
||||
for seed in 1..200u64 {
|
||||
let mut rng = Rng(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15));
|
||||
let mut t = CapTree::<N>::new();
|
||||
let mut m = Model {
|
||||
live: [false; N],
|
||||
parents: [None; N],
|
||||
};
|
||||
for _ in 0..300 {
|
||||
let i = rng.below(N);
|
||||
match rng.below(4) {
|
||||
0 | 1 => {
|
||||
let parent = match rng.below(3) {
|
||||
0 => None,
|
||||
_ => Some(rng.below(N)),
|
||||
};
|
||||
let ok = !m.live[i] && parent.is_none_or(|p| p != i && m.live[p]);
|
||||
assert_eq!(t.attach(i, parent), ok, "attach {i} under {parent:?}");
|
||||
if ok {
|
||||
m.live[i] = true;
|
||||
m.parents[i] = parent.map(|p| p as u16);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
t.detach(i);
|
||||
if m.live[i] {
|
||||
m.detach(i);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
t.remove_descendants(i);
|
||||
if m.live[i] {
|
||||
let below = m.below(i);
|
||||
for (j, b) in below.iter().enumerate() {
|
||||
if *b {
|
||||
m.live[j] = false;
|
||||
m.parents[j] = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
check(&t, &m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detaching_a_middle_node_hands_its_children_up() {
|
||||
let mut t = CapTree::<4>::new();
|
||||
assert!(t.attach(0, None));
|
||||
assert!(t.attach(1, Some(0)));
|
||||
assert!(t.attach(2, Some(1)));
|
||||
assert!(t.attach(3, Some(1)));
|
||||
t.detach(1);
|
||||
assert_eq!(t.parent(2), Some(0));
|
||||
assert_eq!(t.parent(3), Some(0));
|
||||
let mut out = [0u16; 4];
|
||||
assert_eq!(t.descendants(0, &mut out), 2);
|
||||
}
|
||||
Reference in New Issue
Block a user