目录
编程题
注:以下扩展内核的编程基于 rcore/ucore tutorial v3: Branch ch3
第1题
题目要求
* 扩展内核,能够显示操作系统切换任务的过程。
解答
/// Change the status of current `Running` task into `Ready`.
fn mark_current_suspended(&self) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
println!("task {} suspended", current);
inner.tasks[current].task_status = TaskStatus::Ready;
}
/// Change the status of current `Running` task into `Exited`.
fn mark_current_exited(&self) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
println!("task {} exited", current);
inner.tasks[current].task_status = TaskStatus::Exited;
}
/// Switch current `Running` task to the task we have found,
/// or there is no `Ready` task and we can exit with all applications completed
fn run_next_task(&self) {
if let Some(next) = self.find_next_task() {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
println!("task {} start", next);
inner.tasks[next].task_status = TaskStatus::Running;
inner.current_task = next;
let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext;
let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext;
drop(inner);
// before this, we should drop local variables that must be dropped manually
unsafe {
__switch(current_task_cx_ptr, next_task_cx_ptr);
}
// go back to user mode
} else {
println!("All applications completed!");
use crate::board::QEMUExit;
crate::board::QEMU_EXIT_HANDLE.exit_success();
}
}
也就是在原来代码的基础上添加下图中四个红框内的println函数:


根据提示,还需要做如下修改:

将第12行3000改小一点,减少输出内容。我这里改成了3,输出如下:

第2题
题目要求
** 扩展内核,能够统计每个应用执行后的完成时间:用户态完成时间和内核态完成时间。
解答
根据提示,我们先将第一问的内容拍摄快照存储后,将修改的内容改回;

根据提示一步步修改对应位置的文件内容;
2.1. 如何计算时间
首先给每个 TaskControlBlock 加上用户时间和内核时间两个属性:
#[derive(Copy, Clone)]
pub struct TaskControlBlock {
pub task_status: TaskStatus,
pub task_cx: TaskContext,
pub user_time: usize,//需要添加的属性1
pub kernel_time: usize,//需要添加的属性2
}
然后在 TaskManager 中设置一个“停表”变量 stop_watch,并通过以下方法来“掐表”:
/// Inner of Task Manager
pub struct TaskManagerInner {
/// task list
tasks: [TaskControlBlock; MAX_APP_NUM],
/// id of current `Running` task
current_task: usize,
/// 停表
stop_watch: usize,//要添加的变量
}
//需要额外添加的函数:
impl TaskManagerInner {
fn refresh_stop_watch(&mut self) -> usize {
let start_time = self.stop_watch;
self.stop_watch = get_time_ms();
self.stop_watch - start_time
}
}
可以看到,这个方法每次会返回从当前到上一次“掐表”的时间间隔,然后刷新为当前时间。之后就可以利用它来统计应用执行时间了。
2.2. 统计内核态时间
切换内核态任务时,需要记录上一个任务的时间,并重新开始统计下一个任务的时间。
在 TaskManager 的三个方法中插入上面的 refresh_stop_watch()即可(注意中文注释的位置)
fn run_first_task(&self) -> ! {
let mut inner = self.inner.exclusive_access();
let task0 = &mut inner.tasks[0];
task0.task_status = TaskStatus::Running;
let next_task_cx_ptr = &task0.task_cx as *const TaskContext;
/// 开始记录时间--(添加位置1)
inner.refresh_stop_watch();
drop(inner);
let mut _unused = TaskContext::zero_init();
// before this, we should drop local variables that must be dropped manually
unsafe {
__switch(&mut _unused as *mut TaskContext, next_task_cx_ptr);
}
panic!("unreachable in run_first_task!");
}
/// Change the status of current `Running` task into `Ready`.
fn mark_current_suspended(&self) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
// 统计内核时间--(添加位置2)
inner.tasks[current].kernel_time += inner.refresh_stop_watch();
inner.tasks[current].task_status = TaskStatus::Ready;
}
/// Change the status of current `Running` task into `Exited`.
fn mark_current_exited(&self) {
let mut inner = self.inner.exclusive_access();
let current = inner.current_task;
// 统计内核时间并输出--(添加位置3)
inner.tasks[current].kernel_time += inner.refresh_stop_watch();
println!("[task {} exited. user_time: {} ms, kernle_time: {} ms.", current, inner.tasks[current].user_time, inner.tasks[current].kernel_time);
inner.tasks[current].task_status = TaskStatus::Exited;
}
2.3. 统计用户态时间
在 trap 进入退出用户态的时候,可以统计用户态的运行时间,在 trap_handler 的开头结尾添加上函数 user_time_end user_time_start:
/// handle an interrupt, exception, or system call from user space
pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {
crate::task::user_time_end();//添加位置1
let scause = scause::read(); // get trap cause
let stval = stval::read(); // get extra value
match scause.cause() {
Trap::Exception(Exception::UserEnvCall) => {
cx.sepc += 4;
cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
}
Trap::Exception(Exception::StoreFault) | Trap::Exception(Exception::StorePageFault) => {
println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", stval, cx.sepc);
exit_current_and_run_next();
}
Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] IllegalInstruction in application, kernel killed it.");
exit_current_and_run_next();
}
Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger();
suspend_current_and_run_next();
}
_ => {
panic!(
"Unsupported trap {:?}, stval = {:#x}!",
scause.cause(),
stval

文章详细介绍了如何扩展RISC-V内核以支持任务切换的优化,包括添加日志输出、统计任务执行时间、处理浮点应用以及支持内核态中断。同时,文章展示了如何统计任务切换开销,并提供了针对浮点应用程序和内核态中断响应的实现思路。
最低0.47元/天 解锁文章
1369

被折叠的 条评论
为什么被折叠?



