#调度器 #用户空间 #运行 #框架 #调度扩展 #用户 #BPF

scx_rustland_core

用户空间运行的 sched_ext 调度器的框架

9 个版本 (4 个稳定版)

新版本 1.0.3 2024 年 8 月 21 日
1.0.2 2024 年 8 月 9 日
1.0.1 2024 年 7 月 15 日
0.5.0 2024 年 6 月 3 日
0.1.1 2024 年 4 月 4 日

419内存管理 中排名

Download history 194/week @ 2024-04-29 18/week @ 2024-05-20 10/week @ 2024-05-27 162/week @ 2024-06-03 13/week @ 2024-06-10 81/week @ 2024-07-08 182/week @ 2024-07-15 101/week @ 2024-08-05 10/week @ 2024-08-12

每月下载 111
2 crate 中使用

GPL-2.0-only

2.5MB
2.5K SLoC

用户空间运行的 sched_ext 调度器的框架

sched_ext 是一个 Linux 内核功能,它允许在 BPF 中实现内核线程调度器并动态加载它们。

此 crate 提供了一个通用层,可用于实现运行在用户空间的 sched-ext 调度器。

它提供了一个通用的 BPF 抽象层,与用户空间中实现的特定调度策略无关。

开发者可以使用此类抽象使用纯 Rust 代码实现调度器,无需处理任何内核 / BPF 内部细节。

API

主要的 BPF 接口由 BpfScheduler 结构体提供。当此对象初始化时,它将负责注册和初始化 BPF 组件。

然后调度器可以使用 BpfScheduler 实例接收任务(以 QueuedTask 对象的形式)和调度任务(以 DispatchedTask 对象的形式),分别使用 dequeue_task()dispatch_task() 方法。

示例用法(FIFO 调度器)

struct Scheduler<'a> {
    bpf: BpfScheduler<'a>,
}

impl<'a> Scheduler<'a> {
    fn init() -> Result<Self> {
        let topo = Topology::new().expect("Failed to build host topology");
        let bpf = BpfScheduler::init(5000, topo.nr_cpus() as i32, false, false, false)?;
        Ok(Self { bpf })
    }

    fn schedule(&mut self) {
        match self.bpf.dequeue_task() {
            Ok(Some(task)) => {
                // task.cpu < 0 is used to to notify an exiting task, in this
                // case we can simply ignore it.
                if task.cpu >= 0 {
                    let _ = self.bpf.dispatch_task(&DispatchedTask {
                        pid: task.pid,
                        cpu: task.cpu,
                        cpumask_cnt: task.cpumask_cnt,
                        slice_ns: 0,
                    });
                }
            }
            Ok(None) => {
                // Notify the BPF component that all tasks have been dispatched.
                self.bpf.update_tasks(Some(0), Some(0))?

                break;
            }
            Err(_) => {
                break;
            }
        }
    }

此外,可以使用方法 get_cpu_pid() 访问 CPU 拥有者映射(该映射记录了哪些 PID 在哪个 CPU 上运行)。这也可以用来跟踪空闲和忙碌的 CPU,以及与之关联的相应 PID。

可以使用方法 nr_*_mut() 访问 BPF 计数器和统计信息,特别是 nr_queued_mut()nr_scheduled_mut() 可以更新,以通知 BPF 组件用户空间调度器是否还有待完成的工作。

最后,可以使用方法 exited()shutdown_and_report() 分别来测试 BPF 组件是否已退出,以及关闭并报告退出信息。

依赖项

~20–32MB
~549K SLoC