SimpleKernel 1.17.0
Loading...
Searching...
No Matches
cfs_scheduler.hpp
Go to the documentation of this file.
1
5#pragma once
6
7#include <etl/multiset.h>
8
9#include <cassert>
10#include <cstdint>
11
12#include "kernel_config.hpp"
13#include "kernel_log.hpp"
14#include "scheduler_base.hpp"
16
30 public:
32 static constexpr uint32_t kDefaultWeight = 1024;
33
35 static constexpr uint64_t kMinGranularity = 10; // 10 ticks
36
43 auto operator()(const TaskControlBlock* a, const TaskControlBlock* b) const
44 -> bool {
45 if (a->sched_data.cfs.vruntime != b->sched_data.cfs.vruntime) {
46 return a->sched_data.cfs.vruntime < b->sched_data.cfs.vruntime;
47 }
48 return a < b;
49 }
50 };
51
58 auto Enqueue(TaskControlBlock* task) -> void override {
59 if (!task) {
60 return;
61 }
62
63 // 如果是新任务 (vruntime == 0),设置为当前 min_vruntime
64 if (task->sched_data.cfs.vruntime == 0) {
65 task->sched_data.cfs.vruntime = min_vruntime_;
66 }
67
68 // 确保任务有合理的权重
69 if (task->sched_data.cfs.weight == 0) {
70 task->sched_data.cfs.weight = kDefaultWeight;
71 }
72
73 if (ready_queue_.size() >= ready_queue_.max_size()) {
74 klog::Err("CfsScheduler::Enqueue: ready_queue_ full, dropping task");
75 return;
76 }
77 ready_queue_.insert(task);
79 }
80
85 auto Dequeue(TaskControlBlock* task) -> void override {
86 if (!task) {
87 return;
88 }
89
90 auto it = ready_queue_.find(task);
91 if (it != ready_queue_.end()) {
92 ready_queue_.erase(it);
94 }
95 }
96
103 [[nodiscard]] auto PickNext() -> TaskControlBlock* override {
104 if (ready_queue_.empty()) {
105 return nullptr;
106 }
107
108 auto it = ready_queue_.begin();
109 auto* next = *it;
110 ready_queue_.erase(it);
112
113 if (!ready_queue_.empty()) {
114 min_vruntime_ = (*ready_queue_.begin())->sched_data.cfs.vruntime;
115 } else {
116 min_vruntime_ = next->sched_data.cfs.vruntime;
117 }
118
119 return next;
120 }
121
126 [[nodiscard]] auto GetQueueSize() const -> size_t override {
127 return ready_queue_.size();
128 }
129
134 [[nodiscard]] auto IsEmpty() const -> bool override {
135 return ready_queue_.empty();
136 }
137
147 [[nodiscard]] auto OnTick(TaskControlBlock* current) -> bool override {
148 assert(current != nullptr &&
149 "CfsScheduler::OnTick: current task must not be null");
150
151 // 更新 vruntime:delta = tick * (kDefaultWeight / weight)
152 // 权重越大,vruntime 增长越慢,获得更多 CPU 时间
153 uint64_t delta = (kDefaultWeight * 1000) / current->sched_data.cfs.weight;
154 current->sched_data.cfs.vruntime += delta;
155
156 // 检查是否需要抢占:队列中有 vruntime 更小的任务
157 if (!ready_queue_.empty()) {
158 auto* next = *ready_queue_.begin();
159 // 如果队列顶部任务的 vruntime 比当前任务小超过阈值,则需要抢占
160 if (next->sched_data.cfs.vruntime + kMinGranularity <
161 current->sched_data.cfs.vruntime) {
163 return true; // 需要抢占
164 }
165 }
166
167 return false; // 不需要抢占
168 }
169
176 auto OnPreempted(TaskControlBlock* task) -> void override {
177 if (task) {
179 // CFS 不需要额外处理,Schedule() 会将任务重新入队
180 }
181 }
182
187 [[nodiscard]] auto GetMinVruntime() const -> uint64_t {
188 return min_vruntime_;
189 }
190
193 CfsScheduler() = default;
194 CfsScheduler(const CfsScheduler&) = delete;
196 auto operator=(const CfsScheduler&) -> CfsScheduler& = delete;
197 auto operator=(CfsScheduler&&) -> CfsScheduler& = delete;
198 ~CfsScheduler() override = default;
200
201 private:
206
208 uint64_t min_vruntime_{0};
209};
CFS (Completely Fair Scheduler) 调度器
CfsScheduler(CfsScheduler &&)=delete
uint64_t min_vruntime_
当前最小 vruntime (用于新任务初始化)
~CfsScheduler() override=default
static constexpr uint64_t kMinGranularity
vruntime 粒度 (用于计算抢占阈值)
auto Dequeue(TaskControlBlock *task) -> void override
从就绪队列中移除指定任务
auto operator=(CfsScheduler &&) -> CfsScheduler &=delete
CfsScheduler(const CfsScheduler &)=delete
auto OnTick(TaskControlBlock *current) -> bool override
每个 tick 更新任务的 vruntime
auto PickNext() -> TaskControlBlock *override
选择下一个要运行的任务
auto Enqueue(TaskControlBlock *task) -> void override
将任务加入就绪队列
CfsScheduler()=default
auto OnPreempted(TaskControlBlock *task) -> void override
任务被抢占时调用
auto IsEmpty() const -> bool override
判断队列是否为空
etl::multiset< TaskControlBlock *, kernel::config::kMaxReadyTasks, VruntimeCompare > ready_queue_
就绪队列 (红黑树,按 vruntime 升序排序,begin() = 最小 vruntime)
static constexpr uint32_t kDefaultWeight
默认权重 (对应 nice 值为 0)
auto GetQueueSize() const -> size_t override
获取就绪队列大小
auto operator=(const CfsScheduler &) -> CfsScheduler &=delete
auto GetMinVruntime() const -> uint64_t
获取当前 min_vruntime
调度器基类接口
constexpr size_t kMaxReadyTasks
调度器就绪队列容量(FIFO / RR / CFS)
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
CpuSchedData * sched_data
调度数据 (RunQueue) 指针
Definition per_cpu.hpp:8
vruntime 比较器 (用于 multiset 红黑树)
auto operator()(const TaskControlBlock *a, const TaskControlBlock *b) const -> bool
size_t total_dequeues
总出队次数
size_t total_preemptions
总抢占次数
size_t total_picks
总选择次数
size_t total_enqueues
总入队次数
任务控制块,管理进程/线程的核心数据结构