内存分配及调度算法

RuxOS 底层组件实现了多种内存分配和任务调度算法,提供给用户灵活的选择,针对不同类型的应用进行特殊优化。

内存分配算法

RuxOS 支持三种内存分配算法,提供给应用使用。在内存分配组件中,定义了如下特征:

#![allow(unused)]
fn main() {
/// The base allocator inherited by other allocators.
pub trait BaseAllocator {
    /// Initialize the allocator with a free memory region.
    fn init(&mut self, start: usize, size: usize);

    /// Add a free memory region to the allocator.
    fn add_memory(&mut self, start: usize, size: usize) -> AllocResult;
}
}

BaseAllocator 定义了作为分配器的基本方法,即初始化可用内存范围,以及扩大可用内存范围。

#![allow(unused)]
fn main() {
/// Byte-granularity allocator.
pub trait ByteAllocator: BaseAllocator {
    /// Allocate memory with the given size (in bytes) and alignment.
    fn alloc(&mut self, layout: Layout) -> AllocResult<NonNull<u8>>;

    /// Deallocate memory at the given position, size, and alignment.
    fn dealloc(&mut self, pos: NonNull<u8>, layout: Layout);

    /// Returns total memory size in bytes.
    fn total_bytes(&self) -> usize;

    /// Returns allocated memory size in bytes.
    fn used_bytes(&self) -> usize;

    /// Returns available memory size in bytes.
    fn available_bytes(&self) -> usize;
}
}

ByteAllocator 定义了以字节为粒度的分配器所具备的基本方法,包括:

  • 分配/释放指定大小的内存,以 rust 的 layout 进行描述。

  • 目前管理的内存信息,包括总字节数、已用字节数、可用字节数。

#![allow(unused)]
fn main() {
/// Page-granularity allocator.
pub trait PageAllocator: BaseAllocator {
    /// The size of a memory page.
    const PAGE_SIZE: usize;

    /// Allocate contiguous memory pages with given count and alignment.
    fn alloc_pages(&mut self, num_pages: usize, align_pow2: usize) -> AllocResult<usize>;

    /// Deallocate contiguous memory pages with given position and count.
    fn dealloc_pages(&mut self, pos: usize, num_pages: usize);

    /// Returns the total number of memory pages.
    fn total_pages(&self) -> usize;

    /// Returns the number of allocated memory pages.
    fn used_pages(&self) -> usize;

    /// Returns the number of available memory pages.
    fn available_pages(&self) -> usize;
}
}

PageAllocator 定义了以页为粒度的分配器的基本方法,与字节为粒度的分配器方法类似。

buddy 算法

Buddy 算法将内存分为多个固定大小的块,分配的时候仅分配出去最接近需求大小的内存块。

RuxOS 借助第三方库 buddy_system_allocator 来进行实现,提供了 BuddyByteAllocator 结构体,为其实现了 BaseAllocatorByteAllocator 两个 trait,基于 buddy feature 进行条件编译。

slab 算法

Slab 分配器以从64到4096的2的幂次方大小的对象为粒度自主进行内存分配,对大于4096字节的内存块借助 buddy_system 分配器进行分配。

RuxOS 自己实现了相关的 slab 算法分配语义,提供了 SlabByteAllocator 结构体,为其实现了 BaseAllocatorByteAllocator 两个 trait,基于 slab feature 进行条件编译。

tlsf 算法

tlsf 动态内存分配算法常用于实时系统中,借助第三方库 rlsf 来进行实现,提供了 TlsfByteAllocator 结构体,为其实现了 BaseAllocatorByteAllocator 两个 trait,基于 tlsf feature 进行条件编译。

任务调度算法

RuxOS 支持三种任务调度算法,定义了调度器的基本特征:

#![allow(unused)]
fn main() {
/// The base scheduler trait that all schedulers should implement.
///
/// All tasks in the scheduler are considered runnable. If a task is go to
/// sleep, it should be removed from the scheduler.
pub trait BaseScheduler {
    /// Type of scheduled entities. Often a task struct.
    type SchedItem;

    /// Initializes the scheduler.
    fn init(&mut self);

    /// Adds a task to the scheduler.
    fn add_task(&mut self, task: Self::SchedItem);

    /// Removes a task by its reference from the scheduler. Returns the owned
    /// removed task with ownership if it exists.
    ///
    /// # Safety
    ///
    /// The caller should ensure that the task is in the scheduler, otherwise
    /// the behavior is undefined.
    fn remove_task(&mut self, task: &Self::SchedItem) -> Option<Self::SchedItem>;

    /// Picks the next task to run, it will be removed from the scheduler.
    /// Returns [`None`] if there is not runnable task.
    fn pick_next_task(&mut self) -> Option<Self::SchedItem>;

    /// Puts the previous task back to the scheduler. The previous task is
    /// usually placed at the end of the ready queue, making it less likely
    /// to be re-scheduled.
    ///
    /// `preempt` indicates whether the previous task is preempted by the next
    /// task. In this case, the previous task may be placed at the front of the
    /// ready queue.
    fn put_prev_task(&mut self, prev: Self::SchedItem, preempt: bool);

    /// Advances the scheduler state at each timer tick. Returns `true` if
    /// re-scheduling is required.
    ///
    /// `current` is the current running task.
    fn task_tick(&mut self, current: &Self::SchedItem) -> bool;

    /// set priority for a task
    fn set_priority(&mut self, task: &Self::SchedItem, prio: isize) -> bool;
}
}

BaseScheduler 中定义了调度器的关联对象类型和基本方法:

  • SchedItem:定义了调度器的调度对象,包含其属性等,与具体的调度算法有关。

  • init:调度器初始化。

  • add_task/remove_task:放入就绪的任务或移除任务。

  • pick_next_task:获取下一个可运行的任务。

  • put_prev_task:将上一个任务重新放回调度器中,如果该任务是被抢占的任务,则放入就绪队列的头部,否则放入末尾。

  • task_tick:递增相关的时钟属性。

  • set_priority:设置任务的优先级。

FIFO 算法

FIFO 先入先出算法按序执行当前就绪队列中的所有任务,以先到达的任务先占据CPU为原则,直到该任务运行完成主动退出,或主动让出处理器,才会调度下一个就绪任务。由于该算法在当前的多种编程语言和主流应用中不适用,RuxOS 正在考虑移除该算法实现。

RuxOS 提供了 FifoScheduler 对象,为其实现了 BaseScheduler

RR 算法

Round Robin 时间片轮转算法以时间片为单位进行任务调度,当时钟中断来临时,对当前正在执行的任务进行换出,调度下一个等待的就绪任务。

RuxOS 提供了 RRScheduler 对象,为其实现了 BaseScheduler

CFS 算法

Completely Fair Scheduler 完全公平调度算法基于 nice 值来对任务进行调度,期望任务根据优先级来按比例获取处理器时间。

RuxOS 提供了 CFScheduler 对象,为其实现了 BaseScheduler