diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 61bf033ee0..b27ec3429c 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -48,13 +48,16 @@ pub fn allocate_frame() -> Option {
allocate_frames(1)
}
pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, min: usize) -> Option<(Frame, usize)> {
+ let before = get_freelist_pagecount();
+ //debug_freelist();
+
// TODO: Split into sub-power of two allocations.
let min_order = min.next_power_of_two().trailing_zeros();
let _req_order = count.next_power_of_two().trailing_zeros();
let mut freelist = FREELIST.lock();
- let Some((frame_order, frame)) = freelist[min_order as usize..].iter().enumerate().find_map(|(i, f)| f.map(|f| (i, f))) else {
+ let Some((frame_order, frame)) = freelist.iter().enumerate().skip(min_order as usize).find_map(|(i, f)| f.map(|f| (i as u32, f))) else {
// TODO: For larger sizes than the max order, split into power of two allocations.
log::error!("COUNT {min}");
log::error!("FREELIST {freelist:#?}");
@@ -68,29 +71,32 @@ pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, mi
let next_free = info.next();
//log::info!("FREE {frame:?} ORDER {frame_order} NEXT_FREE {next_free:?}");
- freelist[frame_order] = next_free.frame();
+ freelist[frame_order as usize] = next_free.frame();
// TODO: Is this LIFO cache optimal?
- for order in (min..frame_order).rev() {
- let order_page_count = 1 << (order - 1);
+ //log::info!("MIN{min_order}FRAMEORD{frame_order}");
+ for order in (min_order..frame_order).rev() {
+ //log::info!("SPLIT ORDER {order}");
+ let order_page_count = 1 << order;
let hi = frame.next_by(order_page_count);
//log::info!("SPLIT INTO {frame:?}:{hi:?} ORDER {order}");
- if let Some(old_head) = freelist[order].replace(hi) {
+ if let Some(old_head) = freelist[order as usize].replace(hi) {
let hi_info = get_page_info(hi)
.expect("no page info for allocated frame")
.as_free().expect("freelist cannot contain used pages!");
- hi_info.set_next(P2Frame::new(Some(old_head), order as u32));
+ hi_info.set_next(P2Frame::new(Some(old_head), order));
get_page_info(old_head).expect("freelist head needs page info")
.as_free().expect("freelist head cannot be in use")
- .set_prev(P2Frame::new(Some(hi), order as u32));
+ .set_prev(P2Frame::new(Some(hi), order));
}
}
info.mark_used();
+ drop(freelist);
unsafe {
(RmmA::phys_to_virt(frame.start_address()).data() as *mut u8).write_bytes(0, PAGE_SIZE << min_order);
@@ -107,15 +113,33 @@ pub fn allocate_frames_complex(count: usize, flags: (), strategy: Option<()>, mi
}
assert!(found);
}*/
+ let after = get_freelist_pagecount();
+ assert_eq!(after, before - (1 << min_order));
+ /*
+ if after != before - (1 << min_order) {
+ log::info!("BAD ALLOC order {min_order} frame {frame:?} after {after} before {before} frameorder {frame_order}");
+ debug_freelist();
+ loop {}
+ } else {
+ //log::info!("GOOD ALLOC order {min_order} frame {frame:?}");
+ }*/
+
Some((frame, PAGE_SIZE << min_order))
}
/// Deallocate a range of frames
pub unsafe fn deallocate_frames(frame: Frame, count: usize) {
+ let before = get_freelist_pagecount();
+ deallocate_frames_inner(frame, count);
+ let after = get_freelist_pagecount();
+ assert_eq!(before + count, after);
+}
+unsafe fn deallocate_frames_inner(frame: Frame, count: usize) {
if count == 0 {
log::warn!("Count == 0 (frame {frame:?}");
return;
}
+ //log::info!("DEALLOCATE {frame:?}+{count}");
let max_order = core::cmp::min(MAX_ORDER, count.next_power_of_two().trailing_zeros());
@@ -129,20 +153,40 @@ pub unsafe fn deallocate_frames(frame: Frame, count: usize) {
}).expect("must succeed at least for order=0");
for i in 0..number_of_chunks {
- deallocate_p2frame(Frame::containing_address(PhysicalAddress::new(first_aligned + i * (PAGE_SIZE << chunk_order))), chunk_order);
+ let p2frame = Frame::containing_address(PhysicalAddress::new(first_aligned + i * (PAGE_SIZE << chunk_order)));
+ //log::info!("P2DEALLOCATE {frame:?}+2^{chunk_order}");
+ deallocate_p2frame(p2frame, chunk_order);
}
let first_aligned_frame = Frame::containing_address(PhysicalAddress::new(first_aligned));
let lo_subblock_page_count = first_aligned_frame.offset_from(frame);
let hi_subblock_page_count = count - (number_of_chunks << chunk_order) - lo_subblock_page_count;
if lo_subblock_page_count > 0 {
- deallocate_frames(frame, lo_subblock_page_count);
+ //log::info!("SUBDEALLOCATE LO {frame:?}+{lo_subblock_page_count}");
+ deallocate_frames_inner(frame, lo_subblock_page_count);
}
if hi_subblock_page_count > 0 {
- deallocate_frames(first_aligned_frame.next_by(number_of_chunks << chunk_order), hi_subblock_page_count);
+ let hi_frame = first_aligned_frame.next_by(number_of_chunks << chunk_order);
+ //log::info!("SUBDEALLOCATE HI {hi_frame:?}+{hi_subblock_page_count}");
+ deallocate_frames_inner(hi_frame, hi_subblock_page_count);
}
+}
+fn get_freelist_pagecount() -> usize {
+ let mut pagecount = 0;
+ let freelist = FREELIST.lock();
- //log::info!("DEALLOCED {frame:?}+{count}");
+ for order in 0..=MAX_ORDER {
+ let Some(mut p2frame) = freelist[order as usize] else {
+ continue;
+ };
+ pagecount += 1 << order;
+
+ while let Some(next) = get_page_info(p2frame).unwrap().as_free().unwrap().next().frame() {
+ pagecount += 1 << order;
+ p2frame = next;
+ }
+ }
+ pagecount
}
unsafe fn deallocate_p2frame(mut frame: Frame, order: u32) {
@@ -631,21 +675,25 @@ fn init_sections(mut allocator: BumpAllocator) {
*FREELIST.lock() = first_pages.map(|pair| pair.map(|(frame, _)| frame));
- {
- let freelist = FREELIST.lock();
+}
+fn debug_freelist() {
+ let freelist = FREELIST.lock();
- for order in 0..=MAX_ORDER {
- let Some(first_frame) = freelist[order as usize] else {
- continue;
- };
- //log::info!("ORDER {order} FIRST {first_frame:?}");
- let mut frame = first_frame;
+ for order in 0..=MAX_ORDER {
+ let Some(first_frame) = freelist[order as usize] else {
+ continue;
+ };
+ log::info!("ORDER {order} FIRST {first_frame:?}");
+ let mut frame = first_frame;
- while let Some(next) = get_page_info(frame).unwrap_or_else(|| panic!("no page info: {frame:?}")).as_free().expect("not free").next().frame() {
- //log::info!("ORDER {order} THEN {next:?}");
- frame = next;
- }
+ if order == MAX_ORDER { break }
+ let mut count = 1;
+ while let Some(next) = get_page_info(frame).unwrap_or_else(|| panic!("no page info: {frame:?}")).as_free().expect("not free").next().frame() {
+ log::info!("ORDER {order} THEN {next:?}");
+ frame = next;
+ count += 1;
}
+ log::info!("ORDER {order}: {count} p2frames");
}
}