资源

  1. ucore在线实验指导书
  2. 我的ucore实验代码

练习1: 使用 Round Robin 调度算法(不需要编码)

题目

完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件) 个人完成的lab5和练习0完成后的刚修改的lab6之间的区别,分析了解lab6采用RR调度算法后的执行过程。执行make grade,大部分测试用例应该通过。但执行priority.c应该过不去。

请在实验报告中完成:

请理解并分析sched_class中各个函数指针的用法,并结合Round Robin 调度算法描述ucore的调度执行过程。

请在实验报告中简要说明如何设计实现”多级反馈队列调度算法“,给出概要设计,鼓励给出详细设计。

解答

分析sched_class中各个函数指针的用法

  1. 首先,kern_init在调用vmm_init初始化完虚拟内存后,调用sched_init来初始化调度器。在sched_init函数中将sched赋值为default_sched_class。
    sched_class = &default_sched_class;
  1. 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,
};
  1. RR_init初始化RUNNABLE进程链表run_list,并将RUNNABLE进程的数目proc_num设置为0
    list_init(&(rq->run_list));
rq->proc_num = 0;
  1. 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 ++;
  1. RR_dequeue从RUNNABLE进程链表run_list中删除指定进程,并将RUNNABLE进程数目proc_num减1.
    list_del_init(&(proc->run_link));
rq->proc_num --;
  1. 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;
  1. 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系统的进程调度执行过程。

  1. 上文已经提到,ucore内核初始化总入口kern_init调用sched_init来初始化调度器sched_class,接下来调用proc_init来初始化进程。

  2. proc_init首先为当前正在运行的ucore程序分配一个进程控制块,并将其命名为idle,因此第一个内核线程idleproc应运而生。

  3. idleproc调用kernel_thread来创建一个新的内核线程initproc,kernel_thread进一步调用do_fork来完成具体的进程初始化操作,完成后调用wakeup_proc来唤醒新进程,并将内核线程initproc放在RUNNABLE队列rq的末尾。这时rq队列有了第一个进程在等待调度。

  4. proc_init结束后,继续一路运行到cpu_idle,在cpu_idle中,不断判断当前进程是否需要调度,如果需要则调用schedule进行调度。由于当前进程是idleproc,其need_resched设置为1,因此进入schedule进行调度。

  5. schedule首先判断当前进程是否RUNNABLE,以及是不是idleproc,如果当前进程不是idleproc而且RUNNABLE,则将其加入到rq队列的末尾。由于当前进程是idleproc,因此不会将其加入rq队列。

  6. 接下来从RUNNABLE队列中取出队首的进程(此时是initproc),通过调用proc_run来运行initproc进程。这时rq队列已空。

  7. initproc进程运行init_main,init_main调用kernel_thread来创建第三个进程userproc。同理,在完成userproc的初始化后,会调用wakeup_proc将其唤醒,并将其加入到rq队列的末尾。这时rq队列有一个进程userproc在等待调度。

  8. initproc进程接下来调用do_wait来等待子进程结束运行,其中搜索到其子进程userproc的state不为ZOMBIE,因此调用schedule来试图调度子进程来运行。由于rq队列只有一个进程initproc在排队,因此会调用idleproc来运行。这时rq队列又空了。另外注意,由于initproc进程在调用schedule之前将自己的state设置为SLEEPING,因此在进入schedule后,不会再次将其加入到rq队列,也就是说initproc需要睡眠了。什么时候睡醒呢?等子进程userproc运行结束后再将其唤醒。

  9. userproc进程运行user_main,加载ELF文件并运行之。运行完毕,则调用do_exit,在do_exit中,将自己的state设置为Zombie,然后调用wakeup_proc来唤醒initproc,这时会将initproc加入到rq队列,因此rq队列又有一个进程在等待了。接着调用schedule,选择刚加入的initproc来运行,rq队列再次变空。

  10. 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 ) 。

请在实验报告中简要说明你的设计实现过程。

解答

我的设计实现过程

  1. 为了保留Round Robin和Stride两种调度算法,我并没有用default_sched_stride_c覆盖default_sched.c,而是保留两个文件,只是修改sched_init中绑定调度器的地方,将调度器绑定为stride_sched_class。

  2. stride_init:初始化RUNNABLE链表run_list(其实Stride Scheduling如果使用优先级队列时,不需要用到run_list,但这里还是一并初始化),初始化运行队列的运行池lab6_run_pool为空,初始化RUNNABLE进程数目为0.

  3. stride_enqueue:该函数将一个进程添加到运行队列。调用skew_heap_insert,将运行队列rq的运行进程池与新进程proc合并;将新进程的时间片初始化为最大值,关联proc->rq到rq,最后将rq的进程数目加1.

  4. stride_dequeue:该函数从运行队列中删除一个进程。只需调用skew_heap_remove,将进程proc从运行队列rq中删除,并取消proc->rq到rq的关联,最后将rq的进程数目减1.

  5. stride_pick_next:选择下一个要调度的进程,其实就保存在运行队列的头部。因此只需要调用le2proc根据rq->lab6_run_pool找到对应进程的地址,然后要更新对应进程的stride。

  6. 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》实验报告的更多相关文章

  1. [操作系统实验lab3]实验报告

    [感受] 这次操作系统实验感觉还是比较难的,除了因为助教老师笔误引发的2个错误外,还有一些关键性的理解的地方感觉还没有很到位,这些天一直在不断地消化.理解Lab3里的内容,到现在感觉比Lab2里面所蕴 ...

  2. Ucore lab1实验报告

    练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...

  3. ucore操作系统学习(三) ucore lab3虚拟内存管理分析

    1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...

  4. 《ucore lab3》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1:给未被映射的地址映射上物理页 题目 完成do_pgfault(mm/vmm.c)函数,给未被映射的地址映射上物理页.设置访问权限的时候需 ...

  5. 《ucore lab1 exercise5》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...

  6. 《ucore lab8》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1: 完成读文件操作的实现(需要编码) 题目 首先了解打开文件的处理流程,然后参考本实验后续的文件读写操作的过程分析,编写在sfs_inod ...

  7. 《ucore lab7》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1: 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题(不需要编码) 题目 完成练习0后,建议大家比较一下(可用meld等文件dif ...

  8. 《ucore lab5》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1: 加载应用程序并执行(需要编码) 题目 do_execv函数调用load_icode(位于kern/process/proc.c中) 来 ...

  9. 《ucore lab4》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1:分配并初始化一个进程控制块 题目 alloc_proc函数(位于kern/process/proc.c中) 负责分配并返回一个新的str ...

随机推荐

  1. P1108 低价购买——最长下降子序列+方案数

    P1108 低价购买 最长下降子序列不用多讲:关键是方案数: 在求出f[i]时,我们可以比较前面的f[j]; 如果f[i]==f[j]&&a[i]==a[j] 要将t[j]=0,去重: ...

  2. LOJ#2983. 「WC2019」数树 排列组合,生成函数,多项式,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/LOJ2983.html 前言 我怎么什么都不会?贺忙指导博客才会做. 题解 我们分三个子问题考虑. 子问题0 将红蓝共有的边连接 ...

  3. python 装饰器demo

    本质就是一个函数,这个函数符合闭包语法结构,可以在函数不需要改变任何代码情况下增加额外功装饰器的返回值是一个函数的引用 功能:1.引入日志:2.函数执行时间统计:3.执行函数前预备处理:4.执行函数后 ...

  4. FCS省选模拟赛 Day7

    Description  Solution T1 island 考虑把问题成两部分计算 纵坐标的距离和很好计算,在输入的同时一次计算了就完事 横坐标又分成两部分 分别在\(y\)轴不同侧的矩形的距离和 ...

  5. OpenCV reshape The Matrix is not continuous, thus its number of rows can not be changed

    When using OpenCV  reshape and gets this error: OpenCV Error: Image step is wrong (The matrix is not ...

  6. ubuntu之路——day11.2 快速搭建系统并进行迭代、在不同的划分上进行训练和测试

    快速搭建系统并进行迭代 1.建立dev/test set,并确定你的目标 2.快速建立初始化的系统 3.使用前面提到的bias/variance分析和错误分析来进行模型优化和迭代 针对以上的过程,An ...

  7. 百度编辑器contentChange监听不到图片上传

    将ueditor组件化到java项目中,当调用组件后,绑定函数,监听contentchange如下图: um.addListener("contentChange",functio ...

  8. Flink 之 写入数据到 ElasticSearch

    前面 FLink 的文章中我们已经介绍了说 Flink 已经有很多自带的 Connector. 1.<从0到1学习Flink>—— Data Source 介绍 2.<从0到1学习F ...

  9. oracle tablespace pctfree pctused

    二.oracle pctfree和pctused详解 一.建立表时候,注意PCTFREE参数的作用 PCTFREE:为一个块保留的空间百分比,表示数据块在什么情况下可以被insert,默认是10,表示 ...

  10. 浏览器并发数 network.http.max-connections

    network.http.max-connections https://bugs.chromium.org/p/chromium/issues/detail?id=12066 https://chr ...