《ucore lab6》实验报告
资源
练习1: 使用 Round Robin 调度算法(不需要编码)
题目
完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件) 个人完成的lab5和练习0完成后的刚修改的lab6之间的区别,分析了解lab6采用RR调度算法后的执行过程。执行make grade,大部分测试用例应该通过。但执行priority.c应该过不去。
请在实验报告中完成:
请理解并分析sched_class中各个函数指针的用法,并结合Round Robin 调度算法描述ucore的调度执行过程。
请在实验报告中简要说明如何设计实现”多级反馈队列调度算法“,给出概要设计,鼓励给出详细设计。
解答
分析sched_class中各个函数指针的用法
- 首先,kern_init在调用vmm_init初始化完虚拟内存后,调用sched_init来初始化调度器。在sched_init函数中将sched赋值为default_sched_class。
sched_class = &default_sched_class;
- default_sched_class的成员如下所示,接下来分析其中各个函数指针。
struct sched_class default_sched_class = {
.name = "RR_scheduler",
.init = RR_init,
.enqueue = RR_enqueue,
.dequeue = RR_dequeue,
.pick_next = RR_pick_next,
.proc_tick = RR_proc_tick,
};
- RR_init初始化RUNNABLE进程链表run_list,并将RUNNABLE进程的数目proc_num设置为0
list_init(&(rq->run_list));
rq->proc_num = 0;
- RR_enqueue将一个新进程添加到RUNNABLE进程链表run_list的末尾,并将RUNNABLE进程数目proc_num加1。并且检查该进程的时间片,如果为0,重新为它分配时间片max_time_slice。此外还要保证进程的时间片不超过max_time_slice,如果超过了,将其修正为max_time_slice。
list_add_before(&(rq->run_list), &(proc->run_link));
if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) {
proc->time_slice = rq->max_time_slice;
}
proc->rq = rq;
rq->proc_num ++;
- RR_dequeue从RUNNABLE进程链表run_list中删除指定进程,并将RUNNABLE进程数目proc_num减1.
list_del_init(&(proc->run_link));
rq->proc_num --;
- RR_pick_next从RUNNABLE进程链表run_list中取出首元素,然后返回。
list_entry_t *le = list_next(&(rq->run_list));
if (le != &(rq->run_list)) {
return le2proc(le, run_link);
}
return NULL;
- RR_proc_tick将指定进程的时间片减1,如果减1后时间片数值为0,说明该进程的时间片用完了,需要被调度出去,因此将其need_resched标志设置为1.
if (proc->time_slice > 0) {
proc->time_slice --;
}
if (proc->time_slice == 0) {
proc->need_resched = 1;
}
结合Round Robin调度算法描述ucore的调度执行过程
下面结合Round Robin调度算法来分析ucore系统的进程调度执行过程。
上文已经提到,ucore内核初始化总入口kern_init调用sched_init来初始化调度器sched_class,接下来调用proc_init来初始化进程。
proc_init首先为当前正在运行的ucore程序分配一个进程控制块,并将其命名为idle,因此第一个内核线程idleproc应运而生。
idleproc调用kernel_thread来创建一个新的内核线程initproc,kernel_thread进一步调用do_fork来完成具体的进程初始化操作,完成后调用wakeup_proc来唤醒新进程,并将内核线程initproc放在RUNNABLE队列rq的末尾。这时rq队列有了第一个进程在等待调度。
proc_init结束后,继续一路运行到cpu_idle,在cpu_idle中,不断判断当前进程是否需要调度,如果需要则调用schedule进行调度。由于当前进程是idleproc,其need_resched设置为1,因此进入schedule进行调度。
schedule首先判断当前进程是否RUNNABLE,以及是不是idleproc,如果当前进程不是idleproc而且RUNNABLE,则将其加入到rq队列的末尾。由于当前进程是idleproc,因此不会将其加入rq队列。
接下来从RUNNABLE队列中取出队首的进程(此时是initproc),通过调用proc_run来运行initproc进程。这时rq队列已空。
initproc进程运行init_main,init_main调用kernel_thread来创建第三个进程userproc。同理,在完成userproc的初始化后,会调用wakeup_proc将其唤醒,并将其加入到rq队列的末尾。这时rq队列有一个进程userproc在等待调度。
initproc进程接下来调用do_wait来等待子进程结束运行,其中搜索到其子进程userproc的state不为ZOMBIE,因此调用schedule来试图调度子进程来运行。由于rq队列只有一个进程initproc在排队,因此会调用idleproc来运行。这时rq队列又空了。另外注意,由于initproc进程在调用schedule之前将自己的state设置为SLEEPING,因此在进入schedule后,不会再次将其加入到rq队列,也就是说initproc需要睡眠了。什么时候睡醒呢?等子进程userproc运行结束后再将其唤醒。
userproc进程运行user_main,加载ELF文件并运行之。运行完毕,则调用do_exit,在do_exit中,将自己的state设置为Zombie,然后调用wakeup_proc来唤醒initproc,这时会将initproc加入到rq队列,因此rq队列又有一个进程在等待了。接着调用schedule,选择刚加入的initproc来运行,rq队列再次变空。
initproc回收子进程userproc的资源后,打印一些字符串信息,然后退出init_main,接下来进入do_exit,do_exit调用panic,panic停留在kmonitor界面一直等待用户输入。
设计实现“多级反馈队列调度算法”
暂时不会做。。
练习2: 实现 Stride Scheduling 调度算法(需要编码)
题目
首先需要换掉RR调度器的实现,即用default_sched_stride_c覆盖default_sched.c。然后根据此文件和后续文档对Stride调度器的相关描述,完成Stride调度算法的实现。后面的实验文档部分给出了Stride调度算法的大体描述。这里给出Stride调度算法的一些相关的资料(目前网上中文的资料比较欠缺)。你也可GOOGLE “Stride Scheduling” 来查找相关资料。
strid-shed paper location1
strid-shed paper location2
执行:make grade。如果所显示的应用程序检测都输出ok,则基本正确。如果只是priority.c过不去,可执行 make run-priority 命令来单独调试它。大致执行结果可看附录。(使用的是qemu-1.0.1 ) 。
请在实验报告中简要说明你的设计实现过程。
解答
我的设计实现过程
为了保留Round Robin和Stride两种调度算法,我并没有用default_sched_stride_c覆盖default_sched.c,而是保留两个文件,只是修改sched_init中绑定调度器的地方,将调度器绑定为stride_sched_class。
stride_init:初始化RUNNABLE链表run_list(其实Stride Scheduling如果使用优先级队列时,不需要用到run_list,但这里还是一并初始化),初始化运行队列的运行池lab6_run_pool为空,初始化RUNNABLE进程数目为0.
stride_enqueue:该函数将一个进程添加到运行队列。调用skew_heap_insert,将运行队列rq的运行进程池与新进程proc合并;将新进程的时间片初始化为最大值,关联proc->rq到rq,最后将rq的进程数目加1.
stride_dequeue:该函数从运行队列中删除一个进程。只需调用skew_heap_remove,将进程proc从运行队列rq中删除,并取消proc->rq到rq的关联,最后将rq的进程数目减1.
stride_pick_next:选择下一个要调度的进程,其实就保存在运行队列的头部。因此只需要调用le2proc根据rq->lab6_run_pool找到对应进程的地址,然后要更新对应进程的stride。
stride_proc_tick:如果进程的时间片大于0,则将其减1。减1后如果等于0,则设置need_resched为1,表示该进程需要被调度出去。
代码优化
答案的代码中用调试宏开关来同时提供优先级队列和链表两种实现方式,可以参考。
扩展练习 Challenge 1 :实现 Linux 的 CFS 调度算法(待完成)
在ucore的调度器框架下实现下Linux的CFS调度算法。可阅读相关Linux内核书籍或查询网上资料,可了解CFS的细节,然后大致实现在ucore中。
扩展练习 Challenge 2 :实现更多基本调度算法(待完成)
在ucore上实现尽可能多的各种基本调度算法(FIFO, SJF,...),并设计各种测试用例,能够定量地分析出各种调度算法在各种指标上的差异,说明调度算法的适用范围。
《ucore lab6》实验报告的更多相关文章
- [操作系统实验lab3]实验报告
[感受] 这次操作系统实验感觉还是比较难的,除了因为助教老师笔误引发的2个错误外,还有一些关键性的理解的地方感觉还没有很到位,这些天一直在不断地消化.理解Lab3里的内容,到现在感觉比Lab2里面所蕴 ...
- Ucore lab1实验报告
练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...
- ucore操作系统学习(三) ucore lab3虚拟内存管理分析
1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...
- 《ucore lab3》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:给未被映射的地址映射上物理页 题目 完成do_pgfault(mm/vmm.c)函数,给未被映射的地址映射上物理页.设置访问权限的时候需 ...
- 《ucore lab1 exercise5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...
- 《ucore lab8》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 完成读文件操作的实现(需要编码) 题目 首先了解打开文件的处理流程,然后参考本实验后续的文件读写操作的过程分析,编写在sfs_inod ...
- 《ucore lab7》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题(不需要编码) 题目 完成练习0后,建议大家比较一下(可用meld等文件dif ...
- 《ucore lab5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 加载应用程序并执行(需要编码) 题目 do_execv函数调用load_icode(位于kern/process/proc.c中) 来 ...
- 《ucore lab4》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:分配并初始化一个进程控制块 题目 alloc_proc函数(位于kern/process/proc.c中) 负责分配并返回一个新的str ...
随机推荐
- LOJ2434. 「ZJOI2018」历史 [LCT]
LOJ 思路 第一眼看似乎没有什么思路,试着套个DP上去:设\(dp_x\)表示只考虑\(x\)子树,能得到的最大答案. 合并的时候发现只有\(x\)这个点有可能做出新的贡献,而做出新贡献的时候必然是 ...
- 记录一个奇怪的异常,无法还原此异常。 普通的Maven Java Web 项目
项目 : 普通的Maven Java Web 项目 操作记录: 使用 Maven 构建项目,指令 tomcat7:run 无异常 但使用 eclipse 的 tomcat 运行项目,报此异常. 后面从 ...
- Python中pass语句的作用是什么?
pass语句什么也不做,一般作为占位符或者创建占位程序,pass语句不会执行任何操作.
- Thingsboard HTTP连接至服务器
当布署了Thingsboard服务器后,可以通过在服务器地址后,加入swagger-ui.html来打开API文档
- HearthBuddy修改系统时间
将以下代码保存在.bat文件,然后用管理员权限运行 pushd "%~dp0" #下面修改时间,根据操作系统的语言不同,会有不同的格式,比如2019-10-26date 10/26 ...
- 第1课_Java基础知识【学习笔记】
摘要:韦东山android视频学习笔记 一.android系统的基本框架如图一所示,应用程序是用java编写的,底层驱动是用C代码写的,java与C怎么连接在一起主要是通过本地服务.android系统 ...
- flutter PopupMenuButton弹出式菜单列表
import 'package:flutter/material.dart'; class PopupMenuButtonDemo extends StatefulWidget { @override ...
- Dart抽象类和多态
/* Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口. 1.抽象类通过abstract 关键字来定义 2.Dart中的抽象方法不能用abstract声明, ...
- evo:评测slam参数设置
zn@buaa:~$ evo_ape euroc m1/state_groundtruth_estimate0/data.csv pl-svo-master2/trajout.txt -angle_d ...
- 使用idea创建webservice客户端
new project: Generate Java Code From Wsdl: 导入junit.jar,编写测试类: