操作系统实验-rCore-lab3

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

目录

编程题

第1题

题目要求

解答

第2题

题目要求

解答

第3题

题目要求

解答

第4题

题目要求

解答

第5题

题目要求

解答

第6题

题目要求

解答

问答题

第1题

题目要求

解答

第2题

题目要求

解答

第3题

题目要求

解答

第4题

题目要求

解答

第5题

题目要求

解答

第6题

题目要求

解答

第7题

题目要求

解答

第8题

题目要求

解答

第9题

题目要求

解答

第10题

题目要求

解答

第11题

题目要求

解答

第12题

题目要求

解答

第13题

题目要求

解答

第14题

题目要求

解答

第15题

题目要求

解答


编程题

注:以下扩展内核的编程基于 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
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值