memory region merge algorithm
parent
b0e757769a
commit
ed0f9119f4
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "memregion_merge"
|
||||
version = "0.1.0"
|
||||
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "memregion_merge"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@ -0,0 +1,282 @@
|
||||
// Notes:
|
||||
// - Once we've got a list of usable memory, we can use some of it to store the original e820 list
|
||||
// for future use. We therefore don't have to worry about storing the unavailable regions for
|
||||
// now, we can do that later.
|
||||
|
||||
use std::array;
|
||||
|
||||
struct MemRegions<const N: usize> {
|
||||
buf: [MemRegion; N],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<const N: usize> MemRegions<N> {
|
||||
fn new() -> Self {
|
||||
Self { buf: array::from_fn(|_| Default::default()), len: 0 }
|
||||
}
|
||||
|
||||
fn regions(&self) -> &[MemRegion] {
|
||||
&self.buf[..self.len]
|
||||
}
|
||||
|
||||
fn push_usable(&mut self, new: MemRegion) -> bool {
|
||||
let mut merged = false;
|
||||
for old in &mut self.buf[..self.len] {
|
||||
if old.overlaps(&new) {
|
||||
old.merge(&new);
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we merged the new region with an existing one, we may have filled in a gap that allows
|
||||
// other regions to be merged, so check if any adjacent regions can be merged.
|
||||
if merged {
|
||||
let mut i = 1;
|
||||
while i < self.len {
|
||||
if self.buf[i - 1].overlaps(&self.buf[i]) {
|
||||
let (left, right) = self.buf.split_at_mut(i);
|
||||
left[i - 1].merge(&right[0]);
|
||||
right.rotate_left(1);
|
||||
self.len -= 1;
|
||||
}
|
||||
else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we couldn't merge the new region with any others, then place it into its sorted position
|
||||
// in the regions buffer.
|
||||
else {
|
||||
self.push_without_merge_at(new, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn push_without_merge_at(&mut self, new: MemRegion, start_idx: usize) -> bool {
|
||||
// Fail if we don't have space for the new region.
|
||||
if self.len >= N {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut i = start_idx;
|
||||
while i < self.len {
|
||||
if new.start < self.buf[i].start {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self.buf[self.len] = new;
|
||||
self.len += 1;
|
||||
self.buf[i..self.len].rotate_right(1);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// n.b. expects to be run only after all `push_usable`s are done
|
||||
fn push_unusable(&mut self, unusable: MemRegion) {
|
||||
let mut i = 0;
|
||||
while i < self.len {
|
||||
if !unusable.overlaps(&self.buf[i]) {
|
||||
i += 1;
|
||||
}
|
||||
else {
|
||||
let left_region = MemRegion::new(self.buf[i].start, unusable.start);
|
||||
let right_region = MemRegion::new(unusable.end, self.buf[i].end);
|
||||
|
||||
// If the unusable region completely contains the usable region, remove the usable region
|
||||
// entirely.
|
||||
if left_region.empty() && right_region.empty() {
|
||||
self.buf[i..self.len].rotate_left(1);
|
||||
self.len -= 1;
|
||||
}
|
||||
// If the unusable region is completely contained within the usable region, then split the
|
||||
// usable region in two.
|
||||
else if !left_region.empty() && !right_region.empty() {
|
||||
self.buf[i] = left_region;
|
||||
self.push_without_merge_at(right_region, i + 1);
|
||||
i += 1;
|
||||
}
|
||||
// Otherwise, trim the usable region.
|
||||
else {
|
||||
self.buf[i] = if !left_region.empty() { left_region } else { right_region };
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Eq, Debug)]
|
||||
struct MemRegion {
|
||||
start: u64,
|
||||
end: u64,
|
||||
}
|
||||
|
||||
impl MemRegion {
|
||||
fn new(start: u64, end: u64) -> Self {
|
||||
Self { start, end }
|
||||
}
|
||||
|
||||
fn len(&self) -> u64 {
|
||||
if self.end < self.start {
|
||||
0
|
||||
}
|
||||
else {
|
||||
self.end - self.start
|
||||
}
|
||||
}
|
||||
|
||||
fn empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
fn overlaps(&self, other: &MemRegion) -> bool {
|
||||
self.start <= other.end && other.start <= self.end
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: &MemRegion) {
|
||||
debug_assert!(self.overlaps(other));
|
||||
|
||||
self.start = self.start.min(other.start);
|
||||
self.end = self.end.max(other.end);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_push_usable() {
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 200),
|
||||
MemRegion::new(250, 400),
|
||||
MemRegion::new(500, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_usable(MemRegion::new(150, 300));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 400),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_usable(MemRegion::new(150, 300));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 400),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(150, 300));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 400),
|
||||
MemRegion::new(500, 600),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_unusable() {
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_unusable(MemRegion::new(250, 400));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 200),
|
||||
MemRegion::new(500, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_unusable(MemRegion::new(300, 400));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 200),
|
||||
MemRegion::new(250, 300),
|
||||
MemRegion::new(500, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_unusable(MemRegion::new(250, 300));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 200),
|
||||
MemRegion::new(300, 400),
|
||||
MemRegion::new(500, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<5>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_unusable(MemRegion::new(300, 350));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 200),
|
||||
MemRegion::new(250, 300),
|
||||
MemRegion::new(350, 400),
|
||||
MemRegion::new(500, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
let mut rs = MemRegions::<4>::new();
|
||||
rs.push_usable(MemRegion::new(800, 900));
|
||||
rs.push_usable(MemRegion::new(500, 600));
|
||||
rs.push_usable(MemRegion::new(250, 400));
|
||||
rs.push_usable(MemRegion::new(100, 200));
|
||||
rs.push_unusable(MemRegion::new(150, 550));
|
||||
assert_eq!(rs.regions(), &[
|
||||
MemRegion::new(100, 150),
|
||||
MemRegion::new(550, 600),
|
||||
MemRegion::new(800, 900),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue