内存分配及调度算法

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 结构体,为其实现了 BaseAllocator 和 ByteAllocator 两个 trait,基于 buddy feature 进行条件编译。

slab 算法

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

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

tlsf 算法

tlsf 动态内存分配算法常用于实时系统中,借助第三方库 rlsf 来进行实现,提供了 TlsfByteAllocator 结构体,为其实现了 BaseAllocator 和 ByteAllocator 两个 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。