SimpleKernel 1.17.0
Loading...
Searching...
No Matches
cfs_scheduler_test.cpp
Go to the documentation of this file.
1
5#include "cfs_scheduler.hpp"
6
7#include <cstdint>
8
9#include "system_test.h"
11#include "task_messages.hpp"
12
13namespace {
14
15auto test_cfs_basic_functionality() -> bool {
16 klog::Info("Running test_cfs_basic_functionality...");
17
18 CfsScheduler scheduler;
19
20 // 创建测试任务
21 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
22 task1.fsm.Receive(MsgSchedule{});
23 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
24 task1.sched_data.cfs.vruntime = 0;
25
26 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
27 task2.fsm.Receive(MsgSchedule{});
28 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
29 task2.sched_data.cfs.vruntime = 0;
30
31 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
32 task3.fsm.Receive(MsgSchedule{});
33 task3.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
34 task3.sched_data.cfs.vruntime = 0;
35
36 // 测试空队列
37 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty initially");
38 EXPECT_EQ(scheduler.GetQueueSize(), 0,
39 "Queue size should be 0 for empty queue");
40 EXPECT_EQ(scheduler.PickNext(), nullptr,
41 "PickNext should return nullptr for empty queue");
42
43 // 加入任务
44 scheduler.Enqueue(&task1);
45 EXPECT_EQ(scheduler.GetQueueSize(), 1,
46 "Queue size should be 1 after enqueue");
47
48 scheduler.Enqueue(&task2);
49 scheduler.Enqueue(&task3);
50 EXPECT_EQ(scheduler.GetQueueSize(), 3,
51 "Queue size should be 3 after 3 enqueues");
52
53 // 选择任务
54 auto* picked1 = scheduler.PickNext();
55 EXPECT_NE(picked1, nullptr, "Picked task should not be nullptr");
56
57 auto* picked2 = scheduler.PickNext();
58 EXPECT_NE(picked2, nullptr, "Picked task should not be nullptr");
59
60 auto* picked3 = scheduler.PickNext();
61 EXPECT_NE(picked3, nullptr, "Picked task should not be nullptr");
62
63 EXPECT_EQ(scheduler.PickNext(), nullptr,
64 "PickNext should return nullptr after all tasks picked");
65 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
66
67 klog::Info("test_cfs_basic_functionality passed");
68 return true;
69}
70
71auto test_cfs_vruntime_ordering() -> bool {
72 klog::Info("Running test_cfs_vruntime_ordering...");
73
74 CfsScheduler scheduler;
75
76 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
77 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
78 task1.sched_data.cfs.vruntime = 1000; // 最大 vruntime
79
80 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
81 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
82 task2.sched_data.cfs.vruntime = 500; // 最小 vruntime
83
84 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
85 task3.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
86 task3.sched_data.cfs.vruntime = 750; // 中间 vruntime
87
88 // 按任意顺序加入任务
89 scheduler.Enqueue(&task1);
90 scheduler.Enqueue(&task2);
91 scheduler.Enqueue(&task3);
92
93 EXPECT_EQ(scheduler.GetQueueSize(), 3, "Queue size should be 3");
94
95 // 应该按 vruntime 从小到大选择
96 auto* picked1 = scheduler.PickNext();
97 EXPECT_EQ(picked1, &task2, "First pick should be task2 (vruntime=500)");
98
99 auto* picked2 = scheduler.PickNext();
100 EXPECT_EQ(picked2, &task3, "Second pick should be task3 (vruntime=750)");
101
102 auto* picked3 = scheduler.PickNext();
103 EXPECT_EQ(picked3, &task1, "Third pick should be task1 (vruntime=1000)");
104
105 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
106
107 klog::Info("test_cfs_vruntime_ordering passed");
108 return true;
109}
110
111auto test_cfs_new_task_vruntime() -> bool {
112 klog::Info("Running test_cfs_new_task_vruntime...");
113
114 CfsScheduler scheduler;
115
116 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
117 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
118 task1.sched_data.cfs.vruntime = 1000;
119
120 // 加入第一个任务并选择它
121 scheduler.Enqueue(&task1);
122 auto* picked = scheduler.PickNext();
123 EXPECT_EQ(picked, &task1, "First pick should be task1");
124
125 // 第二个新任务 (vruntime = 0)
126 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
127 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
128 task2.sched_data.cfs.vruntime = 0;
129
130 // 记录入队前的 vruntime
131 uint64_t before_vruntime = task2.sched_data.cfs.vruntime;
132 EXPECT_EQ(before_vruntime, 0, "New task vruntime should be 0 initially");
133
134 scheduler.Enqueue(&task2);
135
136 // 新任务的 vruntime 应该被设置为 min_vruntime
137 EXPECT_NE(task2.sched_data.cfs.vruntime, 0,
138 "New task vruntime should be initialized to min_vruntime");
139 EXPECT_GE(task2.sched_data.cfs.vruntime, 1000,
140 "New task vruntime should be >= min_vruntime");
141
142 klog::Info("test_cfs_new_task_vruntime passed");
143 return true;
144}
145
146auto test_cfs_weight_impact() -> bool {
147 klog::Info("Running test_cfs_weight_impact...");
148
149 CfsScheduler scheduler;
150
151 TaskControlBlock high_priority("HighPriority", 1, nullptr, nullptr);
152 high_priority.sched_data.cfs.weight =
153 CfsScheduler::kDefaultWeight * 2; // 2倍权重
154 high_priority.sched_data.cfs.vruntime = 0;
155
156 TaskControlBlock low_priority("LowPriority", 2, nullptr, nullptr);
157 low_priority.sched_data.cfs.weight = CfsScheduler::kDefaultWeight; // 1倍权重
158 low_priority.sched_data.cfs.vruntime = 0;
159
160 // 模拟相同次数的 tick
161 constexpr int kTickCount = 10;
162
163 for (int i = 0; i < kTickCount; ++i) {
164 (void)scheduler.OnTick(&high_priority);
165 (void)scheduler.OnTick(&low_priority);
166 }
167
168 // 高优先级任务的 vruntime 增长应该慢于低优先级
169 EXPECT_LT(high_priority.sched_data.cfs.vruntime,
170 low_priority.sched_data.cfs.vruntime,
171 "High priority task should have lower vruntime growth");
172
173 uint64_t expected = high_priority.sched_data.cfs.vruntime * 2;
174 uint64_t tolerance = expected / 10;
175 EXPECT_GE(low_priority.sched_data.cfs.vruntime, expected - tolerance,
176 "vruntime ratio lower bound (should be ~2x)");
177 EXPECT_LE(low_priority.sched_data.cfs.vruntime, expected + tolerance,
178 "vruntime ratio upper bound (should be ~2x)");
179
180 klog::Info("test_cfs_weight_impact passed");
181 return true;
182}
183
184auto test_cfs_preemption() -> bool {
185 klog::Info("Running test_cfs_preemption...");
186
187 CfsScheduler scheduler;
188
189 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
190 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
191 task1.sched_data.cfs.vruntime = 1000;
192
193 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
194 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
195 task2.sched_data.cfs.vruntime = 0; // 更小的 vruntime
196
197 scheduler.Enqueue(&task2);
198
199 // task1 运行时,应该被抢占
200 bool should_preempt = scheduler.OnTick(&task1);
201 EXPECT_TRUE(should_preempt, "Task with higher vruntime should be preempted");
202
203 klog::Info("test_cfs_preemption passed");
204 return true;
205}
206
207auto test_cfs_no_preemption() -> bool {
208 klog::Info("Running test_cfs_no_preemption...");
209
210 CfsScheduler scheduler;
211
212 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
213 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
214 task1.sched_data.cfs.vruntime = 1000;
215
216 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
217 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
218 // OnTick 会让 task1 的 vruntime 增加 delta = (kDefaultWeight * 1000) / weight
219 // task1 初始 vruntime=1000,OnTick 后 = 1000 + delta = 2000
220 // 设置 task2 的 vruntime 使差距小于 kMinGranularity
221 uint64_t delta =
222 (CfsScheduler::kDefaultWeight * 1000) / task1.sched_data.cfs.weight;
223 uint64_t task1_after_tick = task1.sched_data.cfs.vruntime + delta;
224 task2.sched_data.cfs.vruntime =
225 task1_after_tick - (CfsScheduler::kMinGranularity / 2);
226
227 scheduler.Enqueue(&task2);
228
229 // OnTick 后差距为 5,小于 kMinGranularity (10),不应该抢占
230 bool should_preempt = scheduler.OnTick(&task1);
232 should_preempt,
233 "Task should not be preempted when vruntime difference is small");
234
235 klog::Info("test_cfs_no_preemption passed");
236 return true;
237}
238
239auto test_cfs_dequeue() -> bool {
240 klog::Info("Running test_cfs_dequeue...");
241
242 CfsScheduler scheduler;
243
244 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
245 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
246 task1.sched_data.cfs.vruntime = 100;
247
248 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
249 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
250 task2.sched_data.cfs.vruntime = 200;
251
252 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
253 task3.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
254 task3.sched_data.cfs.vruntime = 300;
255
256 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
257 task4.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
258 task4.sched_data.cfs.vruntime = 400;
259
260 scheduler.Enqueue(&task1);
261 scheduler.Enqueue(&task2);
262 scheduler.Enqueue(&task3);
263 scheduler.Enqueue(&task4);
264
265 EXPECT_EQ(scheduler.GetQueueSize(), 4, "Queue size should be 4");
266
267 // 移除中间任务
268 scheduler.Dequeue(&task2);
269 EXPECT_EQ(scheduler.GetQueueSize(), 3,
270 "Queue size should be 3 after dequeue");
271
272 // 移除队首任务(vruntime 最小)
273 scheduler.Dequeue(&task1);
274 EXPECT_EQ(scheduler.GetQueueSize(), 2,
275 "Queue size should be 2 after dequeue");
276
277 // 验证剩余任务按 vruntime 顺序
278 auto* picked1 = scheduler.PickNext();
279 EXPECT_EQ(picked1, &task3, "First remaining task should be task3");
280
281 auto* picked2 = scheduler.PickNext();
282 EXPECT_EQ(picked2, &task4, "Second remaining task should be task4");
283
284 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
285
286 klog::Info("test_cfs_dequeue passed");
287 return true;
288}
289
290auto test_cfs_statistics() -> bool {
291 klog::Info("Running test_cfs_statistics...");
292
293 CfsScheduler scheduler;
294
295 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
296 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
297 task1.sched_data.cfs.vruntime = 0;
298
299 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
300 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
301 task2.sched_data.cfs.vruntime = 0;
302
303 // 初始统计
304 auto stats = scheduler.GetStats();
305 EXPECT_EQ(stats.total_enqueues, 0, "Initial enqueues should be 0");
306 EXPECT_EQ(stats.total_dequeues, 0, "Initial dequeues should be 0");
307 EXPECT_EQ(stats.total_picks, 0, "Initial picks should be 0");
308 EXPECT_EQ(stats.total_preemptions, 0, "Initial preemptions should be 0");
309
310 // 测试入队统计
311 scheduler.Enqueue(&task1);
312 scheduler.Enqueue(&task2);
313 stats = scheduler.GetStats();
314 EXPECT_EQ(stats.total_enqueues, 2, "Enqueues should be 2");
315
316 // 测试选择统计
317 (void)scheduler.PickNext();
318 (void)scheduler.PickNext();
319 stats = scheduler.GetStats();
320 EXPECT_EQ(stats.total_picks, 2, "Picks should be 2");
321
322 // 测试出队统计
323 scheduler.Enqueue(&task1);
324 scheduler.Dequeue(&task1);
325 stats = scheduler.GetStats();
326 EXPECT_EQ(stats.total_dequeues, 1, "Dequeues should be 1");
327
328 // 重置统计
329 scheduler.ResetStats();
330 stats = scheduler.GetStats();
331 EXPECT_EQ(stats.total_enqueues, 0, "Enqueues should be 0 after reset");
332 EXPECT_EQ(stats.total_dequeues, 0, "Dequeues should be 0 after reset");
333 EXPECT_EQ(stats.total_picks, 0, "Picks should be 0 after reset");
334 EXPECT_EQ(stats.total_preemptions, 0, "Preemptions should be 0 after reset");
335
336 klog::Info("test_cfs_statistics passed");
337 return true;
338}
339
340auto test_cfs_min_vruntime_update() -> bool {
341 klog::Info("Running test_cfs_min_vruntime_update...");
342
343 CfsScheduler scheduler;
344
345 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
346 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
347 task1.sched_data.cfs.vruntime = 1000;
348
349 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
350 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
351 task2.sched_data.cfs.vruntime = 500;
352
353 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
354 task3.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
355 task3.sched_data.cfs.vruntime = 750;
356
357 // 初始 min_vruntime 应该是 0
358 EXPECT_EQ(scheduler.GetMinVruntime(), 0, "Initial min_vruntime should be 0");
359
360 scheduler.Enqueue(&task1);
361 scheduler.Enqueue(&task2);
362 scheduler.Enqueue(&task3);
363
364 // 选择 task2 (vruntime = 500)
365 (void)scheduler.PickNext();
366
367 // min_vruntime 应该更新为队列中最小的 (750)
368 uint64_t min_vruntime = scheduler.GetMinVruntime();
369 EXPECT_GE(min_vruntime, 500, "min_vruntime should be updated");
370
371 klog::Info("test_cfs_min_vruntime_update passed");
372 return true;
373}
374
375auto test_cfs_multiple_ticks() -> bool {
376 klog::Info("Running test_cfs_multiple_ticks...");
377
378 CfsScheduler scheduler;
379
380 TaskControlBlock task("Task", 1, nullptr, nullptr);
381 task.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
382 task.sched_data.cfs.vruntime = 0;
383
384 uint64_t initial_vruntime = task.sched_data.cfs.vruntime;
385
386 // 模拟多次 tick
387 constexpr int kTickCount = 10;
388 for (int i = 0; i < kTickCount; ++i) {
389 (void)scheduler.OnTick(&task);
390 }
391
392 // vruntime 应该累积增长
393 EXPECT_GT(task.sched_data.cfs.vruntime, initial_vruntime,
394 "vruntime should accumulate over ticks");
395
396 // 计算预期的增长
397 uint64_t expected_delta =
398 (CfsScheduler::kDefaultWeight * 1000) / task.sched_data.cfs.weight;
399 uint64_t expected_vruntime = initial_vruntime + expected_delta * kTickCount;
400 EXPECT_EQ(task.sched_data.cfs.vruntime, expected_vruntime,
401 "vruntime should grow by expected amount");
402
403 klog::Info("test_cfs_multiple_ticks passed");
404 return true;
405}
406
407auto test_cfs_fairness() -> bool {
408 klog::Info("Running test_cfs_fairness...");
409
410 CfsScheduler scheduler;
411
412 // 创建三个相同权重的任务
413 constexpr size_t kTaskCount = 3;
414 TaskControlBlock* tasks[kTaskCount];
415
416 for (size_t i = 0; i < kTaskCount; ++i) {
417 tasks[i] = new TaskControlBlock("Task", 10, nullptr, nullptr);
419 tasks[i]->sched_data.cfs.vruntime = 0;
420 scheduler.Enqueue(tasks[i]);
421 }
422
423 // 模拟多轮调度
424 constexpr int kRounds = 5;
425 for (int round = 0; round < kRounds; ++round) {
426 // 每轮选择所有任务
427 for (size_t i = 0; i < kTaskCount; ++i) {
428 auto* task = scheduler.PickNext();
429 EXPECT_NE(task, nullptr, "Should pick a task");
430
431 // 模拟任务运行一段时间
432 for (int tick = 0; tick < 5; ++tick) {
433 (void)scheduler.OnTick(task);
434 }
435
436 // 将任务重新入队
437 scheduler.Enqueue(task);
438 }
439 }
440
441 // 检查所有任务的 vruntime 应该相近(公平性)
442 uint64_t max_vruntime = 0;
443 uint64_t min_vruntime = UINT64_MAX;
444
445 for (size_t i = 0; i < kTaskCount; ++i) {
446 if (tasks[i]->sched_data.cfs.vruntime > max_vruntime) {
447 max_vruntime = tasks[i]->sched_data.cfs.vruntime;
448 }
449 if (tasks[i]->sched_data.cfs.vruntime < min_vruntime) {
450 min_vruntime = tasks[i]->sched_data.cfs.vruntime;
451 }
452 }
453
454 // vruntime 差异应该较小(表示公平性)
455 uint64_t difference = max_vruntime - min_vruntime;
456 EXPECT_LT(difference, 10000,
457 "vruntime difference should be small (fairness)");
458
459 // 清理内存
460 for (size_t i = 0; i < kTaskCount; ++i) {
461 delete tasks[i];
462 }
463
464 klog::Info("test_cfs_fairness passed");
465 return true;
466}
467
468auto test_cfs_mixed_operations() -> bool {
469 klog::Info("Running test_cfs_mixed_operations...");
470
471 CfsScheduler scheduler;
472
473 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
474 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
475 task1.sched_data.cfs.vruntime = 100;
476
477 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
478 task2.sched_data.cfs.weight = CfsScheduler::kDefaultWeight * 2;
479 task2.sched_data.cfs.vruntime = 200;
480
481 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
482 task3.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
483 task3.sched_data.cfs.vruntime = 300;
484
485 TaskControlBlock task4("Task4", 4, nullptr, nullptr);
486 task4.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
487 task4.sched_data.cfs.vruntime = 0;
488
489 TaskControlBlock task5("Task5", 5, nullptr, nullptr);
490 task5.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
491 task5.sched_data.cfs.vruntime = 0;
492
493 // 复杂的混合操作序列
494 scheduler.Enqueue(&task1);
495 scheduler.Enqueue(&task2);
496 scheduler.Enqueue(&task3);
497
498 auto* picked1 = scheduler.PickNext(); // 应该是 task1 (vruntime=100)
499 EXPECT_EQ(picked1, &task1, "First pick should be task1");
500
501 scheduler.Enqueue(&task4); // 新任务
502 scheduler.Dequeue(&task3);
503 scheduler.Enqueue(&task5); // 新任务
504
505 EXPECT_EQ(scheduler.GetQueueSize(), 3,
506 "Queue size should be 3 after operations");
507
508 // 继续选择
509 auto* picked2 = scheduler.PickNext();
510 EXPECT_NE(picked2, nullptr, "Second pick should not be nullptr");
511
512 klog::Info("test_cfs_mixed_operations passed");
513 return true;
514}
515
516auto test_cfs_robustness() -> bool {
517 klog::Info("Running test_cfs_robustness...");
518
519 CfsScheduler scheduler;
520
521 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
522 task1.sched_data.cfs.weight = CfsScheduler::kDefaultWeight;
523 task1.sched_data.cfs.vruntime = 0;
524
525 // 空队列操作
526 EXPECT_EQ(scheduler.PickNext(), nullptr,
527 "PickNext on empty queue should return nullptr");
528 scheduler.Dequeue(&task1); // 不应崩溃
529
530 // nullptr 操作
531 scheduler.Enqueue(nullptr);
532 scheduler.Dequeue(nullptr);
533 scheduler.OnPreempted(nullptr);
534 scheduler.OnScheduled(nullptr);
535
536 // 权重为 0 的任务
537 task1.sched_data.cfs.weight = 0;
538 scheduler.Enqueue(&task1);
539 EXPECT_NE(task1.sched_data.cfs.weight, 0,
540 "Weight should be set to default if 0");
541
542 // 重复移除
543 scheduler.Dequeue(&task1);
544 scheduler.Dequeue(&task1); // 不应崩溃
545
546 EXPECT_TRUE(scheduler.IsEmpty(), "Scheduler should be empty");
547
548 klog::Info("test_cfs_robustness passed");
549 return true;
550}
551
552} // namespace
553
554auto cfs_scheduler_test() -> bool {
555 klog::Info("\n=== CFS Scheduler System Tests ===\n");
556
557 if (!test_cfs_basic_functionality()) {
558 return false;
559 }
560
561 if (!test_cfs_vruntime_ordering()) {
562 return false;
563 }
564
565 if (!test_cfs_new_task_vruntime()) {
566 return false;
567 }
568
569 if (!test_cfs_weight_impact()) {
570 return false;
571 }
572
573 if (!test_cfs_preemption()) {
574 return false;
575 }
576
577 if (!test_cfs_no_preemption()) {
578 return false;
579 }
580
581 if (!test_cfs_dequeue()) {
582 return false;
583 }
584
585 if (!test_cfs_statistics()) {
586 return false;
587 }
588
589 if (!test_cfs_min_vruntime_update()) {
590 return false;
591 }
592
593 if (!test_cfs_multiple_ticks()) {
594 return false;
595 }
596
597 if (!test_cfs_fairness()) {
598 return false;
599 }
600
601 if (!test_cfs_mixed_operations()) {
602 return false;
603 }
604
605 if (!test_cfs_robustness()) {
606 return false;
607 }
608
609 klog::Info("=== All CFS Scheduler Tests Passed ===\n");
610 return true;
611}
CFS (Completely Fair Scheduler) 调度器
static constexpr uint64_t kMinGranularity
vruntime 粒度 (用于计算抢占阈值)
auto Dequeue(TaskControlBlock *task) -> void override
从就绪队列中移除指定任务
auto OnTick(TaskControlBlock *current) -> bool override
每个 tick 更新任务的 vruntime
auto PickNext() -> TaskControlBlock *override
选择下一个要运行的任务
auto Enqueue(TaskControlBlock *task) -> void override
将任务加入就绪队列
auto OnPreempted(TaskControlBlock *task) -> void override
任务被抢占时调用
auto IsEmpty() const -> bool override
判断队列是否为空
static constexpr uint32_t kDefaultWeight
默认权重 (对应 nice 值为 0)
auto GetQueueSize() const -> size_t override
获取就绪队列大小
auto GetMinVruntime() const -> uint64_t
获取当前 min_vruntime
virtual auto GetStats() const -> const Stats &
获取调度器统计信息
virtual auto OnScheduled(TaskControlBlock *task) -> void
任务开始运行时调用 (从 Ready 变为 Running)
virtual auto ResetStats() -> void
重置统计信息
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
CpuSchedData * sched_data
调度数据 (RunQueue) 指针
Definition per_cpu.hpp:8
调度消息(无负载,用作事件)
任务控制块,管理进程/线程的核心数据结构
union TaskControlBlock::SchedData sched_data
auto cfs_scheduler_test() -> bool
#define EXPECT_TRUE(cond, msg)
#define EXPECT_LE(val1, val2, msg)
#define EXPECT_NE(val1, val2, msg)
#define EXPECT_LT(val1, val2, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_GT(val1, val2, msg)
#define EXPECT_GE(val1, val2, msg)
#define EXPECT_EQ(val1, val2, msg)
uint32_t weight
任务权重 (1024 为默认)
struct TaskControlBlock::SchedData::@3 cfs
CFS 调度器数据
uint64_t vruntime
虚拟运行时间