diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index fd8817006..b1d2881b4 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -248,6 +248,7 @@ fn do_waitpid( unsafe { ProcessManager::release(pid) }; return Some(Ok(pid.into())); } + _ => {} }; return None; diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index c22c17dde..c83635b7b 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -48,10 +48,12 @@ use crate::{ VirtAddr, }, net::socket::SocketInode, - sched::completion::Completion, sched::{ - cpu_rq, fair::FairSchedEntity, prio::MAX_PRIO, DequeueFlag, EnqueueFlag, OnRq, SchedMode, - WakeupFlags, __schedule, + completion::Completion, + cpu_rq, + fair::{CompletelyFairScheduler, FairSchedEntity}, + prio::MAX_PRIO, + DequeueFlag, EnqueueFlag, OnRq, SchedMode, SchedPolicy, WakeupFlags, __schedule, }, smp::{ core::smp_get_processor_id, @@ -467,6 +469,20 @@ impl ProcessManager { .take() .expect("next_pcb is None"); + let guard = prev_pcb.sched_info.inner_lock_read_irqsave(); + if unlikely(guard.state() == ProcessState::Dead) { + match prev_pcb.sched_info().policy() { + SchedPolicy::RT => todo!(), + SchedPolicy::FIFO => todo!(), + SchedPolicy::CFS => CompletelyFairScheduler::task_dead(prev_pcb.clone()), + SchedPolicy::IDLE => todo!(), + } + + // TODO: put_task_stack + // TODO: put_task_struct_rcu_user + } + drop(guard); + // 由于进程切换前使用了SpinLockGuard::leak(),所以这里需要手动释放锁 fence(Ordering::SeqCst); @@ -530,6 +546,7 @@ pub enum ProcessState { Stopped, /// 进程已经退出,usize表示进程的退出码 Exited(usize), + Dead, } #[allow(dead_code)] @@ -977,6 +994,11 @@ impl ProcessControlBlock { pub fn alarm_timer_irqsave(&self) -> SpinLockGuard> { return self.alarm_timer.lock_irqsave(); } + + #[inline] + pub fn task_util(&self) -> usize { + self.sched_info().sched_entity.avg.util_avg + } } impl Drop for ProcessControlBlock { @@ -1481,6 +1503,13 @@ impl ProcessSignalInfo { self.tty = Some(tty); } + #[allow(dead_code)] + pub fn set_task_cpu(&self, _new_cpu: x86::cpuid::CpuId) { + // TODO + + // TODO(pelt): call migrate_task_rq + } + /// 从 pcb 的 siginfo中取出下一个要处理的信号,先处理线程信号,再处理进程信号 /// /// ## 参数 diff --git a/kernel/src/sched/fair.rs b/kernel/src/sched/fair.rs index 0428b1b93..abd8a56fc 100644 --- a/kernel/src/sched/fair.rs +++ b/kernel/src/sched/fair.rs @@ -1,6 +1,7 @@ use core::intrinsics::likely; use core::intrinsics::unlikely; use core::mem::swap; +use core::ptr; use core::sync::atomic::fence; use core::sync::atomic::{AtomicU64, Ordering}; @@ -150,7 +151,9 @@ impl FairSchedEntity { /// 判断是否是进程持有的调度实体 #[inline] pub fn is_task(&self) -> bool { - // TODO: 调度组 + #[cfg(CONFIG_FAIR_GROUP_SCHED)] + return self.my_cfs_rq.is_none(); + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] true } @@ -248,14 +251,22 @@ impl FairSchedEntity { } pub fn runnable(&self) -> u64 { - if self.is_task() { + #[cfg(CONFIG_FAIR_GROUP_SCHED)] + { + if self.is_task() { + return self.on_rq as u64; + } else { + self.runnable_weight + } + } + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + { return self.on_rq as u64; - } else { - self.runnable_weight } } /// 更新task和其cfsrq的负载均值 + #[cfg(CONFIG_FAIR_GROUP_SCHED)] pub fn propagate_entity_load_avg(&mut self) -> bool { if self.is_task() { return false; @@ -279,9 +290,17 @@ impl FairSchedEntity { cfs_rq.update_task_group_runnable(self.self_arc(), gcfs_rq); cfs_rq.update_task_group_load(self.self_arc(), gcfs_rq); + // TODO: trace_pelt_cfs_tp + // TODO: trace_pelt_se_tp + return true; } + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + pub fn propagate_entity_load_avg(&mut self) -> bool { + false + } + /// 更新runnable_weight pub fn update_runnable(&mut self) { if !self.is_task() { @@ -297,6 +316,42 @@ impl FairSchedEntity { self.avg.load_avg = LoadWeight::scale_load_down(self.load.weight) as usize; } } + + #[allow(dead_code)] + fn attach_entity_cfs_rq(se: Arc) { + let binding = se.cfs_rq(); + let cfs_rq = binding.force_mut(); + + // TODO(pelt): High sched_feat(ATTACH_AGE_LOAD) + cfs_rq.update_load_avg(&se, UpdateAvgFlags::ZERO); + cfs_rq.attach_entity_load_avg(&se); + cfs_rq.update_tg_load_avg(); + se.propagate_entity_cfs_rq(); + } + + #[allow(dead_code)] + fn detach_entity_cfs_rq(self: &Arc) { + let se = self.clone(); + let binding = se.cfs_rq(); + let cfs_rq = binding.force_mut(); + + cfs_rq.update_load_avg(&se, UpdateAvgFlags::ZERO); + cfs_rq.detach_entity_load_avg(&se); + cfs_rq.update_tg_load_avg(); + se.propagate_entity_cfs_rq(); + } + + #[allow(dead_code)] + fn propagate_entity_cfs_rq(&self) { + #[cfg(CONFIG_FAIR_GROUP_SCHED)] + { + // TODO + } + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + { + return; + } + } } /// CFS的运行队列,这个队列需确保是percpu的 @@ -842,20 +897,24 @@ impl CfsRunQueue { let now = self.cfs_rq_clock_pelt(); if se.avg.last_update_time > 0 && !flags.contains(UpdateAvgFlags::SKIP_AGE_LOAD) { - se.force_mut().update_load_avg(self, now); + se.force_mut().update_self_load_avg(self, now); } let mut decayed = self.update_self_load_avg(now); decayed |= se.force_mut().propagate_entity_load_avg() as u32; if se.avg.last_update_time > 0 && flags.contains(UpdateAvgFlags::DO_ATTACH) { - todo!() - } else if flags.contains(UpdateAvgFlags::DO_ATTACH) { + self.attach_entity_load_avg(se); + self.update_tg_load_avg(); + } else if flags.contains(UpdateAvgFlags::DO_DETACH) { self.detach_entity_load_avg(se); + self.update_tg_load_avg(); } else if decayed > 0 { - // cfs_rq_util_change + self.cfs_rq_util_change(0); - todo!() + if flags.contains(UpdateAvgFlags::UPDATE_TG) { + self.update_tg_load_avg(); + } } } @@ -880,19 +939,71 @@ impl CfsRunQueue { .runnable_sum .max((self.avg.runnable_avg * PELT_MIN_DIVIDER) as u64); - self.propagate = 1; - self.prop_runnable_sum += se.avg.load_sum as isize; + self.add_tg_cfs_propagate(-(se.avg.load_sum as isize)); + + self.cfs_rq_util_change(0); + + // TODO: trace_pelt_cfs_tp + } + + fn attach_entity_load_avg(&mut self, se: &Arc) { + let divider = self.avg.get_pelt_divider(); + + let binding = se.clone(); + let se = binding.force_mut(); + + se.avg.last_update_time = self.avg.last_update_time; + se.avg.period_contrib = self.avg.period_contrib; + + se.avg.util_sum = (se.avg.util_avg * divider) as u64; + + se.avg.runnable_sum = (se.avg.runnable_avg * divider) as u64; + + se.avg.load_sum = (se.avg.load_avg * divider) as u64; + + if LoadWeight::scale_load_down(se.load.weight) < se.avg.load_sum { + se.avg.load_sum = se + .avg + .load_sum + .checked_div(LoadWeight::scale_load_down(se.load.weight)) + .unwrap_or(0); + } else { + se.avg.load_sum = 1; + } + + self.enqueue_load_avg(binding.clone()); + self.avg.util_avg += se.avg.util_avg; + self.avg.util_sum += se.avg.util_sum; + self.avg.runnable_avg += se.avg.runnable_avg; + self.avg.runnable_sum += se.avg.runnable_sum; + + self.add_tg_cfs_propagate(se.avg.load_sum as isize); + + self.cfs_rq_util_change(0); + + // TODO: trace_pelt_cfs_tp + } + + #[inline] + pub fn load_avg(&self) -> usize { + self.avg.load_avg + } + + #[inline] + pub fn runnable_avg(&self) -> usize { + self.avg.runnable_avg } - fn update_self_load_avg(&mut self, now: u64) -> u32 { + #[inline] + pub(crate) fn update_self_load_avg(&mut self, now: u64) -> u32 { let mut removed_load = 0; let mut removed_util = 0; let mut removed_runnable = 0; let mut decayed = 0; - if self.removed.lock().nr > 0 { - let mut removed_guard = self.removed.lock(); + let mut removed_guard = self.removed.lock(); + if removed_guard.nr > 0 { let divider = self.avg.get_pelt_divider(); swap::(&mut removed_guard.util_avg, &mut removed_util); @@ -900,12 +1011,11 @@ impl CfsRunQueue { swap::(&mut removed_guard.runnable_avg, &mut removed_runnable); removed_guard.nr = 0; + drop(removed_guard); let mut r = removed_load; - sub_positive(&mut self.avg.load_avg, r); sub_positive(&mut (self.avg.load_sum as usize), r * divider); - self.avg.load_sum = self .avg .load_sum @@ -927,21 +1037,45 @@ impl CfsRunQueue { .runnable_sum .max((self.avg.runnable_avg * PELT_MIN_DIVIDER) as u64); - drop(removed_guard); self.add_task_group_propagate( -(removed_runnable as isize * divider as isize) >> SCHED_CAPACITY_SHIFT, ); decayed = 1; + } else { + drop(removed_guard); } decayed |= self.__update_load_avg(now) as u32; - - self.last_update_time_copy = self.avg.last_update_time; + // if CONFIG_64BIT: do nothing + // self.last_update_time_copy = self.avg.last_update_time; return decayed; } + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + #[inline] + fn update_tg_load_avg(&self) {} + + #[cfg(CONFIG_FAIR_GROUP_SCHED)] + #[inline] + fn add_tg_cfs_propagate(&self, runnable_sum: isize) { + self.propagate = 1; + self.prop_runnable_sum += runnable_sum; + } + + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + #[inline] + fn add_tg_cfs_propagate(&self, _runnable_sum: isize) {} + + #[inline] + fn cfs_rq_util_change(&self, flags: u32) { + let rq = self.rq(); + if ptr::eq(rq.cfs_rq().as_ref(), self) { + rq.cpufreq_update_util(flags) + } + } + fn __update_load_avg(&mut self, now: u64) -> bool { if self.avg.update_load_sum( now, @@ -956,11 +1090,17 @@ impl CfsRunQueue { return false; } + #[cfg(CONFIG_FAIR_GROUP_SCHED)] + #[inline] fn add_task_group_propagate(&mut self, runnable_sum: isize) { self.propagate = 1; self.prop_runnable_sum += runnable_sum; } + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + #[inline] + fn add_task_group_propagate(&mut self, _runnable_sum: isize) {} + /// 将实体加入队列 pub fn enqueue_entity(&mut self, se: &Arc, flags: EnqueueFlag) { let is_curr = self.is_curr(se); @@ -1050,7 +1190,9 @@ impl CfsRunQueue { } if prev.on_rq() { + // TODO: update_stats_wait_start_fair self.inner_enqueue_entity(&prev); + self.update_load_avg(&prev, UpdateAvgFlags::ZERO); } self.set_current(Weak::default()); @@ -1061,6 +1203,7 @@ impl CfsRunQueue { self.clear_buddies(se); if se.on_rq() { + // TODO: update_stats_wait_start_fair self.inner_dequeue_entity(se); self.update_load_avg(se, UpdateAvgFlags::UPDATE_TG); se.force_mut().vlag = se.deadline as i64; @@ -1364,6 +1507,12 @@ impl CfsRunQueue { return avg >= self.entity_key(se) * load; } + + #[cfg(not(CONFIG_NO_HZ_COMMON))] + #[inline] + pub(crate) fn cfs_rq_has_blocked(&self) -> bool { + false + } } pub struct CompletelyFairScheduler; @@ -1389,6 +1538,25 @@ impl CompletelyFairScheduler { *pse = pse.parent().unwrap(); } } + + pub(crate) fn task_dead(p: Arc) { + p.sched_info() + .sched_entity() + .force_mut() + .remove_entity_load_avg() + } + + #[allow(dead_code)] + fn migrate_task_rq(p: Arc, _new_cpu: x86::cpuid::CpuId) { + // TODO + + p.sched_info() + .sched_entity() + .force_mut() + .remove_entity_load_avg(); + + // TODO + } } impl Scheduler for CompletelyFairScheduler { diff --git a/kernel/src/sched/mod.rs b/kernel/src/sched/mod.rs index c50782e82..76a6ea5b7 100644 --- a/kernel/src/sched/mod.rs +++ b/kernel/src/sched/mod.rs @@ -677,6 +677,10 @@ impl CpuRunQueue { todo!() } + + #[cfg(not(CONFIG_CPU_FREQ))] + #[inline] + fn cpufreq_update_util(&self, _flags: u32) {} } bitflags! { diff --git a/kernel/src/sched/pelt.rs b/kernel/src/sched/pelt.rs index 9ead63cad..5c0d4257a 100644 --- a/kernel/src/sched/pelt.rs +++ b/kernel/src/sched/pelt.rs @@ -2,7 +2,9 @@ use core::intrinsics::unlikely; use alloc::sync::Arc; -use crate::process::ProcessControlBlock; +use crate::exception::InterruptArch; +use crate::sched::CompletelyFairScheduler; +use crate::{arch::CurrentIrqArch, process::ProcessControlBlock}; use super::{ fair::{CfsRunQueue, FairSchedEntity}, @@ -73,6 +75,7 @@ impl SchedulerAvg { self.accumulate_sum(delta, load, runnable, running) != 0 } + #[inline] pub fn accumulate_sum( &mut self, mut delta: u64, @@ -196,12 +199,15 @@ impl SchedulerAvg { } impl CpuRunQueue { + #[inline] pub fn rq_clock_pelt(&self) -> u64 { + // TODO assert_clock_updated self.clock_pelt - self.lost_idle_time } } impl CfsRunQueue { + #[cfg(CONFIG_CFS_BANDWIDTH)] pub fn cfs_rq_clock_pelt(&self) -> u64 { if unlikely(self.throttled_count > 0) { return self.throttled_clock_pelt - self.throttled_clock_pelt_time; @@ -212,10 +218,31 @@ impl CfsRunQueue { return rq.rq_clock_pelt() - self.throttled_clock_pelt_time; } + + #[cfg(not(CONFIG_CFS_BANDWIDTH))] + pub fn cfs_rq_clock_pelt(&self) -> u64 { + let rq = self.rq(); + return rq.rq_clock_pelt(); + } +} + +impl CompletelyFairScheduler { + #[cfg(not(CONFIG_FAIR_GROUP_SCHED))] + #[allow(dead_code)] + fn self_update_blocked(rq: &mut CpuRunQueue, done: &mut bool) -> bool { + let binding = rq.cfs_rq(); + let cfs = binding.force_mut(); + + let decayed = cfs.update_self_load_avg(cfs.cfs_rq_clock_pelt()) != 0; + if cfs.cfs_rq_has_blocked() { + *done = false; + } + return decayed; + } } impl FairSchedEntity { - pub fn update_load_avg(&mut self, cfs_rq: &mut CfsRunQueue, now: u64) -> bool { + pub fn update_self_load_avg(&mut self, cfs_rq: &mut CfsRunQueue, now: u64) -> bool { if self.avg.update_load_sum( now, self.on_rq as u32, @@ -224,16 +251,53 @@ impl FairSchedEntity { ) { self.avg .update_load_avg(LoadWeight::scale_load_down(self.load.weight)); + // TODO(util_est): cfs_se_util_change + // TODO: trace_pelt_se_tp + return true; + } + + return false; + } + #[allow(dead_code)] + fn self_update_load_avg_blocked_se(&mut self, now: u64) -> bool { + if self.avg.update_load_sum(now, 0, 0, 0) { + self.avg + .update_load_avg(LoadWeight::scale_load_down(self.load.weight)); + // TODO: trace_pelt_se_tp return true; } return false; } + + #[allow(dead_code)] + pub(crate) fn remove_entity_load_avg(&mut self) { + let cfs = self.cfs_rq(); + + self.sync_entity_load_avg(); + + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + let mut removed_guard = cfs.removed.lock(); + removed_guard.nr += 1; + removed_guard.util_avg += self.avg.util_avg; + removed_guard.load_avg += self.avg.load_avg; + removed_guard.runnable_avg += self.avg.runnable_avg; + drop(removed_guard); + drop(irq_guard); + } + + fn sync_entity_load_avg(&mut self) { + let cfs = self.cfs_rq(); + // config CONFIG_64BIT: do return cfs.avg.last_update_time + let last_update_time = cfs.avg.last_update_time; + self.self_update_load_avg_blocked_se(last_update_time); + } } bitflags! { pub struct UpdateAvgFlags: u8 { + const ZERO = 0x0; /// 更新任务组(task group)信息 const UPDATE_TG = 0x1; @@ -246,6 +310,7 @@ bitflags! { } } +#[allow(dead_code)] pub fn add_positive(x: &mut isize, y: isize) { let res = *x + y; *x = res.max(0);