SimpleKernel 1.17.0
Loading...
Searching...
No Matches
rr_scheduler_test.cpp
Go to the documentation of this file.
1
5#include "rr_scheduler.hpp"
6
7#include <gtest/gtest.h>
8
9#include "kstd_vector"
11
12// 测试 Round-Robin 调度器的基本功能
13TEST(RoundRobinSchedulerTest, BasicEnqueueDequeue) {
14 RoundRobinScheduler scheduler;
15
16 // 创建测试任务
17 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
18 task1.status = TaskStatus::kReady;
19
20 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
21 task2.status = TaskStatus::kReady;
22
23 // 测试空队列
24 EXPECT_EQ(scheduler.PickNext(), nullptr);
25
26 // 加入任务
27 scheduler.Enqueue(&task1);
28 scheduler.Enqueue(&task2);
29
30 // 测试 FIFO 顺序
31 EXPECT_EQ(scheduler.PickNext(), &task1);
32 EXPECT_EQ(scheduler.PickNext(), &task2);
33 EXPECT_EQ(scheduler.PickNext(), nullptr);
34}
35
36// 测试 Round-Robin 的轮转特性
37TEST(RoundRobinSchedulerTest, RoundRobinRotation) {
38 RoundRobinScheduler scheduler;
39
40 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
41 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
42 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
43
44 // 加入三个任务
45 scheduler.Enqueue(&task1);
46 scheduler.Enqueue(&task2);
47 scheduler.Enqueue(&task3);
48
49 // 第一轮
50 EXPECT_EQ(scheduler.PickNext(), &task1);
51 EXPECT_EQ(scheduler.PickNext(), &task2);
52 EXPECT_EQ(scheduler.PickNext(), &task3);
53
54 // 模拟时间片用完,任务重新入队
55 scheduler.Enqueue(&task1);
56 scheduler.Enqueue(&task2);
57 scheduler.Enqueue(&task3);
58
59 // 第二轮 - 应该保持相同的顺序
60 EXPECT_EQ(scheduler.PickNext(), &task1);
61 EXPECT_EQ(scheduler.PickNext(), &task2);
62 EXPECT_EQ(scheduler.PickNext(), &task3);
63}
64
65// 测试 Dequeue 功能
66TEST(RoundRobinSchedulerTest, DequeueSpecificTask) {
67 RoundRobinScheduler scheduler;
68
69 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
70 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
71 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
72
73 scheduler.Enqueue(&task1);
74 scheduler.Enqueue(&task2);
75 scheduler.Enqueue(&task3);
76
77 // 移除中间的任务
78 scheduler.Dequeue(&task2);
79
80 // 验证只剩下 task1 和 task3
81 EXPECT_EQ(scheduler.PickNext(), &task1);
82 EXPECT_EQ(scheduler.PickNext(), &task3);
83 EXPECT_EQ(scheduler.PickNext(), nullptr);
84}
85
86// 测试空指针处理
87TEST(RoundRobinSchedulerTest, NullPointerHandling) {
88 RoundRobinScheduler scheduler;
89
90 // Enqueue 空指针应该不崩溃
91 scheduler.Enqueue(nullptr);
92 EXPECT_EQ(scheduler.PickNext(), nullptr);
93
94 // Dequeue 空指针应该不崩溃
95 scheduler.Dequeue(nullptr);
96}
97
98// 测试重复入队和出队
99TEST(RoundRobinSchedulerTest, RepeatedEnqueueDequeue) {
100 RoundRobinScheduler scheduler;
101
102 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
103
104 // 重复入队和出队
105 for (int i = 0; i < 10; ++i) {
106 scheduler.Enqueue(&task1);
107 EXPECT_EQ(scheduler.PickNext(), &task1);
108 }
109
110 EXPECT_EQ(scheduler.PickNext(), nullptr);
111}
112
113// 测试多任务交替入队
114TEST(RoundRobinSchedulerTest, InterleavedEnqueueDequeue) {
115 RoundRobinScheduler scheduler;
116
117 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
118 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
119
120 scheduler.Enqueue(&task1);
121 EXPECT_EQ(scheduler.PickNext(), &task1);
122
123 scheduler.Enqueue(&task2);
124 EXPECT_EQ(scheduler.PickNext(), &task2);
125
126 scheduler.Enqueue(&task1);
127 scheduler.Enqueue(&task2);
128 EXPECT_EQ(scheduler.PickNext(), &task1);
129 EXPECT_EQ(scheduler.PickNext(), &task2);
130}
131
132// 测试队列大小和空状态检查
133TEST(RoundRobinSchedulerTest, QueueSizeAndEmpty) {
134 RoundRobinScheduler scheduler;
135
136 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
137 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
138 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
139
140 // 初始状态
141 EXPECT_TRUE(scheduler.IsEmpty());
142 EXPECT_EQ(scheduler.GetQueueSize(), 0);
143
144 // 加入任务
145 scheduler.Enqueue(&task1);
146 EXPECT_FALSE(scheduler.IsEmpty());
147 EXPECT_EQ(scheduler.GetQueueSize(), 1);
148
149 scheduler.Enqueue(&task2);
150 scheduler.Enqueue(&task3);
151 EXPECT_EQ(scheduler.GetQueueSize(), 3);
152
153 // 取出任务
154 scheduler.PickNext();
155 EXPECT_EQ(scheduler.GetQueueSize(), 2);
156
157 scheduler.PickNext();
158 scheduler.PickNext();
159 EXPECT_TRUE(scheduler.IsEmpty());
160 EXPECT_EQ(scheduler.GetQueueSize(), 0);
161}
162
163// 测试时间片重置
164TEST(RoundRobinSchedulerTest, TimeSliceReset) {
165 RoundRobinScheduler scheduler;
166
167 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
169 task1.sched_info.time_slice_remaining = 5; // 时间片快用完了
170
171 // 入队应该重置时间片
172 scheduler.Enqueue(&task1);
174
175 // 模拟时间片耗尽
177 bool should_reenqueue = scheduler.OnTimeSliceExpired(&task1);
178 EXPECT_TRUE(should_reenqueue);
180}
181
182// 测试统计信息
183TEST(RoundRobinSchedulerTest, Statistics) {
184 RoundRobinScheduler scheduler;
185
186 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
187 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
188
189 // 初始统计
190 auto stats = scheduler.GetStats();
191 EXPECT_EQ(stats.total_enqueues, 0);
192 EXPECT_EQ(stats.total_dequeues, 0);
193 EXPECT_EQ(stats.total_picks, 0);
194 EXPECT_EQ(stats.total_preemptions, 0);
195
196 // 测试入队统计
197 scheduler.Enqueue(&task1);
198 scheduler.Enqueue(&task2);
199 stats = scheduler.GetStats();
200 EXPECT_EQ(stats.total_enqueues, 2);
201
202 // 测试选择统计
203 scheduler.PickNext();
204 scheduler.PickNext();
205 stats = scheduler.GetStats();
206 EXPECT_EQ(stats.total_picks, 2);
207
208 // 测试出队统计
209 scheduler.Enqueue(&task1);
210 scheduler.Dequeue(&task1);
211 stats = scheduler.GetStats();
212 EXPECT_EQ(stats.total_dequeues, 1);
213
214 // 测试抢占统计
215 scheduler.OnPreempted(&task1);
216 scheduler.OnPreempted(&task2);
217 stats = scheduler.GetStats();
218 EXPECT_EQ(stats.total_preemptions, 2);
219
220 // 重置统计
221 scheduler.ResetStats();
222 stats = scheduler.GetStats();
223 EXPECT_EQ(stats.total_enqueues, 0);
224 EXPECT_EQ(stats.total_dequeues, 0);
225 EXPECT_EQ(stats.total_picks, 0);
226 EXPECT_EQ(stats.total_preemptions, 0);
227}
228
229// 测试大量任务的公平性
230TEST(RoundRobinSchedulerTest, FairnessWithManyTasks) {
231 RoundRobinScheduler scheduler;
232 constexpr size_t kTaskCount = 100;
233
234 // 创建任务数组(使用动态分配)
235 kstd::vector<TaskControlBlock*> tasks;
236 for (size_t i = 0; i < kTaskCount; ++i) {
237 auto* task = new TaskControlBlock("Task", 10, nullptr, nullptr);
238 task->status = TaskStatus::kReady;
239 tasks.push_back(task);
240 scheduler.Enqueue(task);
241 }
242
243 EXPECT_EQ(scheduler.GetQueueSize(), kTaskCount);
244
245 // 验证所有任务按顺序被选中
246 for (size_t i = 0; i < kTaskCount; ++i) {
247 auto* picked = scheduler.PickNext();
248 ASSERT_NE(picked, nullptr);
249 EXPECT_EQ(picked, tasks[i]);
250 }
251
252 EXPECT_TRUE(scheduler.IsEmpty());
253
254 // 清理内存
255 for (auto* task : tasks) {
256 delete task;
257 }
258}
259
260// 测试多轮轮转
261TEST(RoundRobinSchedulerTest, MultipleRounds) {
262 RoundRobinScheduler scheduler;
263
264 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
265 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
266 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
267
268 // 进行 5 轮轮转
269 for (int round = 0; round < 5; ++round) {
270 scheduler.Enqueue(&task1);
271 scheduler.Enqueue(&task2);
272 scheduler.Enqueue(&task3);
273
274 EXPECT_EQ(scheduler.PickNext(), &task1);
275 EXPECT_EQ(scheduler.PickNext(), &task2);
276 EXPECT_EQ(scheduler.PickNext(), &task3);
277 EXPECT_TRUE(scheduler.IsEmpty());
278 }
279}
280
281// 测试边界条件:单个任务
282TEST(RoundRobinSchedulerTest, SingleTask) {
283 RoundRobinScheduler scheduler;
284
285 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
286
287 scheduler.Enqueue(&task1);
288 EXPECT_EQ(scheduler.GetQueueSize(), 1);
289
290 auto* picked = scheduler.PickNext();
291 EXPECT_EQ(picked, &task1);
292 EXPECT_TRUE(scheduler.IsEmpty());
293}
294
295// 测试出队不存在的任务
296TEST(RoundRobinSchedulerTest, DequeueNonExistentTask) {
297 RoundRobinScheduler scheduler;
298
299 TaskControlBlock task1("Task1", 1, nullptr, nullptr);
300 TaskControlBlock task2("Task2", 2, nullptr, nullptr);
301 TaskControlBlock task3("Task3", 3, nullptr, nullptr);
302
303 scheduler.Enqueue(&task1);
304 scheduler.Enqueue(&task2);
305
306 // 尝试移除不在队列中的任务
307 scheduler.Dequeue(&task3);
308 EXPECT_EQ(scheduler.GetQueueSize(), 2);
309
310 // 验证原有任务仍在队列中
311 EXPECT_EQ(scheduler.PickNext(), &task1);
312 EXPECT_EQ(scheduler.PickNext(), &task2);
313 EXPECT_TRUE(scheduler.IsEmpty());
314}
Round-Robin 调度器
auto OnPreempted(TaskControlBlock *task) -> void override
任务被抢占时调用
auto Dequeue(TaskControlBlock *task) -> void override
从就绪队列中移除指定任务
auto OnTimeSliceExpired(TaskControlBlock *task) -> bool override
时间片耗尽处理
auto PickNext() -> TaskControlBlock *override
选择下一个要运行的任务
auto Enqueue(TaskControlBlock *task) -> void override
将任务加入就绪队列尾部
auto GetQueueSize() const -> size_t override
获取就绪队列大小
auto IsEmpty() const -> bool override
判断队列是否为空
virtual auto GetStats() const -> const Stats &
获取调度器统计信息
virtual auto ResetStats() -> void
重置统计信息
constexpr etl::fsm_state_id_t kReady
Definition task_fsm.hpp:15
uint64_t time_slice_default
默认时间片
uint64_t time_slice_remaining
剩余时间片
任务控制块,管理进程/线程的核心数据结构
struct TaskControlBlock::SchedInfo sched_info
#define EXPECT_TRUE(cond, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_EQ(val1, val2, msg)
TEST(RoundRobinSchedulerTest, BasicEnqueueDequeue)