Skip to content

Commit

Permalink
feat(mm): add slab usage calculation (#768)
Browse files Browse the repository at this point in the history
* Add slab free space calculation and add it to freeram of sysinfo
  • Loading branch information
laokengwt authored Apr 29, 2024
1 parent bde4a33 commit 7401bec
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 12 deletions.
76 changes: 70 additions & 6 deletions kernel/crates/rust-slabmalloc/src/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! The ZoneAllocator achieves this by having many `SCAllocator`
use crate::*;
use core::sync::atomic::Ordering;

/// Creates an instance of a zone, we do this in a macro because we
/// re-use the code in const and non-const functions
Expand All @@ -24,6 +25,7 @@ macro_rules! new_zone {
SCAllocator::new(1 << 10), // 1024
SCAllocator::new(1 << 11), // 2048 ],
],
total: 0,
}
};
}
Expand All @@ -38,6 +40,7 @@ macro_rules! new_zone {
/// to provide the underlying `SCAllocator` with more memory in case it runs out.
pub struct ZoneAllocator<'a> {
small_slabs: [SCAllocator<'a, ObjectPage<'a>>; ZoneAllocator::MAX_BASE_SIZE_CLASSES],
total: u64,
}

impl<'a> Default for ZoneAllocator<'a> {
Expand All @@ -52,17 +55,13 @@ enum Slab {
}

impl<'a> ZoneAllocator<'a> {
/// Maximum size that allocated within LargeObjectPages (2 MiB).
/// This is also the maximum object size that this allocator can handle.
pub const MAX_ALLOC_SIZE: usize = 1 << 11;

/// Maximum size which is allocated with ObjectPages (4 KiB pages).
///
/// e.g. this is 4 KiB - 80 bytes of meta-data.
pub const MAX_BASE_ALLOC_SIZE: usize = 256;
pub const MAX_BASE_ALLOC_SIZE: usize = 1 << 11;

/// How many allocators of type SCAllocator<ObjectPage> we have.
const MAX_BASE_SIZE_CLASSES: usize = 9;
pub const MAX_BASE_SIZE_CLASSES: usize = 9;

#[cfg(feature = "unstable")]
pub const fn new() -> ZoneAllocator<'a> {
Expand Down Expand Up @@ -119,13 +118,49 @@ impl<'a> ZoneAllocator<'a> {
{
for i in 0..ZoneAllocator::MAX_BASE_SIZE_CLASSES {
let slab = &mut self.small_slabs[i];
// reclaim的page数
let just_reclaimed = slab.try_reclaim_pages(to_reclaim, &mut dealloc);
self.total -= (just_reclaimed * OBJECT_PAGE_SIZE) as u64;
to_reclaim = to_reclaim.saturating_sub(just_reclaimed);
if to_reclaim == 0 {
break;
}
}
}

/// 获取scallocator中的还未被分配的空间
pub fn free_space(&mut self) -> u64 {
// 记录空闲空间
let mut free = 0;
// 遍历所有scallocator
for count in 0..ZoneAllocator::MAX_BASE_SIZE_CLASSES {
// 获取scallocator
let scallocator = &mut self.small_slabs[count];

// 遍历scallocator中的部分分配的page(partial_page)
for slab_page in scallocator.slabs.iter_mut() {
// 统计page中还可以分配多少个object
let mut free_obj_count = 0;
// 遍历page中的bitfield(用来统计内存分配情况的u64数组)
for b in slab_page.bitfield().iter() {
let bitval = b.load(Ordering::Relaxed);
let free_count = bitval.count_zeros() as usize;
free_obj_count += free_count;
}
// 剩余可分配object数乘上page中规定的每个object的大小,即空闲空间
free += free_obj_count * scallocator.size();
}
// 遍历scallocator中的empty_page,把空页空间也加上去
free +=
scallocator.empty_slabs.elements * (scallocator.obj_per_page * scallocator.size());
}
free as u64
}

pub fn usage(&mut self) -> SlabUsage {
let free_num = self.free_space();
SlabUsage::new(self.total, free_num)
}
}

unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
Expand Down Expand Up @@ -162,9 +197,38 @@ unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> {
match ZoneAllocator::get_slab(layout.size()) {
Slab::Base(idx) => {
self.small_slabs[idx].refill(new_page);
// 每refill一个page就为slab的总空间统计加上4KB
self.total += OBJECT_PAGE_SIZE as u64;
Ok(())
}
Slab::Unsupported => Err(AllocationError::InvalidLayout),
}
}
}

/// Slab内存空间使用情况
pub struct SlabUsage {
// slab总共使用的内存空间
total: u64,
// slab的空闲空间
free: u64,
}

impl SlabUsage {
/// 初始化SlabUsage
pub fn new(total: u64, free: u64) -> Self {
Self { total, free }
}

pub fn total(&self) -> u64 {
self.total
}

pub fn used(&self) -> u64 {
self.total - self.free
}

pub fn free(&self) -> u64 {
self.free
}
}
11 changes: 8 additions & 3 deletions kernel/src/mm/allocator/slab.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//! 当前slab分配器暂时不使用,等待后续完善后合并主线
#![allow(dead_code)]

use core::{alloc::Layout, ptr::NonNull, sync::atomic::AtomicBool};

use alloc::boxed::Box;
Expand Down Expand Up @@ -74,3 +71,11 @@ pub unsafe fn slab_init() {
pub fn slab_init_state() -> bool {
unsafe { *SLABINITSTATE.get_mut() }
}

pub unsafe fn slab_usage() -> SlabUsage {
if let Some(ref mut slab) = SLABALLOCATOR {
slab.zone.usage()
} else {
SlabUsage::new(0, 0)
}
}
5 changes: 3 additions & 2 deletions kernel/src/syscall/misc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
arch::{mm::LockedFrameAllocator, rand::rand},
libs::rand::GRandFlags,
mm::allocator::page_frame::FrameAllocator,
mm::allocator::{page_frame::FrameAllocator, slab::slab_usage},
};
use alloc::vec::Vec;
use core::cmp;
Expand Down Expand Up @@ -38,10 +38,11 @@ impl Syscall {
let mut sysinfo = SysInfo::default();

let mem = unsafe { LockedFrameAllocator.usage() };
let slab_usage = unsafe { slab_usage() };
sysinfo.uptime = 0;
sysinfo.loads = [0; 3];
sysinfo.totalram = mem.total().bytes() as u64;
sysinfo.freeram = mem.free().bytes() as u64;
sysinfo.freeram = mem.free().bytes() as u64 + slab_usage.free();
sysinfo.sharedram = 0;
sysinfo.bufferram = 0;
sysinfo.totalswap = 0;
Expand Down
2 changes: 1 addition & 1 deletion user/apps/test-backlog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ test-release:

.PHONY: install
install:
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force
RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --target $(RUST_TARGET) --path . --no-track --root $(INSTALL_DIR) --force

0 comments on commit 7401bec

Please sign in to comment.