From af097f9f4b317337fe74aaa5070c34a14b8635fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E9=93=AD=E6=B6=9B?= <114841534+1037827920@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:51:21 +0800 Subject: [PATCH] fix(time): modify update wall time (#836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更改了时间子系统的update_wall_time函数,通过读取当前周期数,计算delta值进行更新,而不是通过传入delta值进行更新 --- .../src/arch/x86_64/driver/apic/apic_timer.rs | 4 +- kernel/src/arch/x86_64/driver/hpet.rs | 8 +- kernel/src/driver/clocksource/acpi_pm.rs | 18 +- kernel/src/driver/clocksource/timer_riscv.rs | 40 +-- kernel/src/time/clocksource.rs | 133 +++++--- kernel/src/time/jiffies.rs | 24 +- kernel/src/time/mod.rs | 1 + kernel/src/time/tick_common.rs | 25 ++ kernel/src/time/timekeep.rs | 30 +- kernel/src/time/timekeeping.rs | 299 +++++++++++++----- kernel/src/time/timer.rs | 10 +- 11 files changed, 389 insertions(+), 203 deletions(-) create mode 100644 kernel/src/time/tick_common.rs diff --git a/kernel/src/arch/x86_64/driver/apic/apic_timer.rs b/kernel/src/arch/x86_64/driver/apic/apic_timer.rs index 1c8695b8..35acebf0 100644 --- a/kernel/src/arch/x86_64/driver/apic/apic_timer.rs +++ b/kernel/src/arch/x86_64/driver/apic/apic_timer.rs @@ -12,10 +12,10 @@ use crate::exception::manage::irq_manager; use crate::exception::IrqNumber; use crate::mm::percpu::PerCpu; -use crate::process::ProcessManager; use crate::smp::core::smp_get_processor_id; use crate::smp::cpu::ProcessorId; use crate::time::clocksource::HZ; +use crate::time::tick_common::tick_handle_periodic; use alloc::string::ToString; use alloc::sync::Arc; pub use drop; @@ -277,7 +277,7 @@ impl LocalApicTimer { pub(super) fn handle_irq(trap_frame: &TrapFrame) -> Result { // sched_update_jiffies(); - ProcessManager::update_process_times(trap_frame.is_from_user()); + tick_handle_periodic(trap_frame); return Ok(IrqReturn::Handled); } } diff --git a/kernel/src/arch/x86_64/driver/hpet.rs b/kernel/src/arch/x86_64/driver/hpet.rs index 98863bdc..89a7d5da 100644 --- a/kernel/src/arch/x86_64/driver/hpet.rs +++ b/kernel/src/arch/x86_64/driver/hpet.rs @@ -30,10 +30,7 @@ use crate::{ mmio_buddy::{mmio_pool, MMIOSpaceGuard}, PhysAddr, }, - time::{ - jiffies::NSEC_PER_JIFFY, - timer::{try_raise_timer_softirq, update_timer_jiffies}, - }, + time::jiffies::NSEC_PER_JIFFY, }; static mut HPET_INSTANCE: Option = None; @@ -249,9 +246,6 @@ impl Hpet { pub(super) fn handle_irq(&self, timer_num: u32) { if timer_num == 0 { assert!(!CurrentIrqArch::is_irq_enabled()); - update_timer_jiffies(1, Self::HPET0_INTERVAL_USEC as i64); - - try_raise_timer_softirq(); } } } diff --git a/kernel/src/driver/clocksource/acpi_pm.rs b/kernel/src/driver/clocksource/acpi_pm.rs index 09382a9a..e5b7d7a5 100644 --- a/kernel/src/driver/clocksource/acpi_pm.rs +++ b/kernel/src/driver/clocksource/acpi_pm.rs @@ -88,8 +88,10 @@ impl Acpipm { max_idle_ns: Default::default(), flags: ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS, watchdog_last: CycleNum::new(0), + cs_last: CycleNum::new(0), uncertainty_margin: 0, maxadj: 0, + cycle_last: CycleNum::new(0), }; let acpi_pm = Arc::new(Acpipm(SpinLock::new(InnerAcpipm { data, @@ -117,14 +119,18 @@ impl Clocksource for Acpipm { fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> { let d = &mut self.0.lock_irqsave().data; - d.set_flags(data.flags); - d.set_mask(data.mask); - d.set_max_idle_ns(data.max_idle_ns); - d.set_mult(data.mult); d.set_name(data.name); d.set_rating(data.rating); + d.set_mask(data.mask); + d.set_mult(data.mult); d.set_shift(data.shift); + d.set_max_idle_ns(data.max_idle_ns); + d.set_flags(data.flags); d.watchdog_last = data.watchdog_last; + d.cs_last = data.cs_last; + d.set_uncertainty_margin(data.uncertainty_margin); + d.set_maxadj(data.maxadj); + d.cycle_last = data.cycle_last; return Ok(()); } } @@ -281,7 +287,7 @@ pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> { } // 检查TSC时钟源的监视器是否被禁用,如果被禁用则将时钟源的标志设置为CLOCK_SOURCE_MUST_VERIFY - // 没有实现clocksource_selecet_watchdog函数,所以这里设置为false + // 是因为jiffies精度小于acpi pm,所以不需要被jiffies监视 let tsc_clocksource_watchdog_disabled = false; if tsc_clocksource_watchdog_disabled { clocksource_acpi_pm().0.lock_irqsave().data.flags |= @@ -290,7 +296,7 @@ pub fn init_acpi_pm_clocksource() -> Result<(), SystemError> { // 注册ACPI PM Timer let acpi_pmtmr = clocksource_acpi_pm() as Arc; - match acpi_pmtmr.register(100, PMTMR_TICKS_PER_SEC as u32) { + match acpi_pmtmr.register(1, PMTMR_TICKS_PER_SEC as u32) { Ok(_) => { info!("ACPI PM Timer registered as clocksource sccessfully"); return Ok(()); diff --git a/kernel/src/driver/clocksource/timer_riscv.rs b/kernel/src/driver/clocksource/timer_riscv.rs index 48cd31e4..fad652ef 100644 --- a/kernel/src/driver/clocksource/timer_riscv.rs +++ b/kernel/src/driver/clocksource/timer_riscv.rs @@ -20,12 +20,9 @@ use crate::{ }, libs::spinlock::SpinLock, mm::percpu::PerCpu, - process::ProcessManager, smp::core::smp_get_processor_id, time::{ - clocksource::HZ, - jiffies::NSEC_PER_JIFFY, - timer::{try_raise_timer_softirq, update_timer_jiffies}, + clocksource::HZ, tick_common::tick_handle_periodic, timer::try_raise_timer_softirq, TimeArch, }, }; @@ -37,13 +34,6 @@ static SBI_TIMER_INIT_BMP: SpinLock>> = SpinLock::new(LinkedList::new()); - pub static ref CLOCKSOUCE_WATCHDOG:SpinLock = SpinLock::new(ClocksouceWatchdog::new()); + pub static ref CLOCKSOURCE_WATCHDOG:SpinLock = SpinLock::new(ClocksouceWatchdog::new()); pub static ref OVERRIDE_NAME: SpinLock = SpinLock::new(String::from("")); @@ -138,8 +138,6 @@ pub struct ClocksouceWatchdog { watchdog: Option>, /// 检查器是否在工作的标志 is_running: bool, - /// 上一次检查的时刻 - last_check: CycleNum, /// 定时监视器的过期时间 timer_expires: u64, } @@ -148,7 +146,6 @@ impl ClocksouceWatchdog { Self { watchdog: None, is_running: false, - last_check: CycleNum(0), timer_expires: 0, } } @@ -168,7 +165,13 @@ impl ClocksouceWatchdog { // 生成一个定时器 let wd_timer_func: Box = Box::new(WatchdogTimerFunc {}); self.timer_expires += clock() + WATCHDOG_INTERVAL; - self.last_check = self.watchdog.as_ref().unwrap().clone().read(); + let mut wd_data = self.watchdog.as_ref().unwrap().clone().clocksource_data(); + wd_data.watchdog_last = self.watchdog.as_ref().unwrap().clone().read(); + self.watchdog + .as_ref() + .unwrap() + .update_clocksource_data(wd_data) + .expect("clocksource_start_watchdog: failed to update watchdog data"); let wd_timer = Timer::new(wd_timer_func, self.timer_expires); wd_timer.activate(); self.is_running = true; @@ -271,15 +274,14 @@ impl dyn Clocksource { let cs_data_guard = self.clocksource_data(); let mut max_cycles: u64; - // 这里我有问题,不知道要不要修改,暂时不修改它 - max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64; + max_cycles = (1 << (63 - (log2(cs_data_guard.mult + cs_data_guard.maxadj) + 1))) as u64; max_cycles = max_cycles.min(cs_data_guard.mask.bits); let max_nsecs = clocksource_cyc2ns( CycleNum(max_cycles), - cs_data_guard.mult, + cs_data_guard.mult - cs_data_guard.maxadj, cs_data_guard.shift, ); - return max_nsecs - (max_nsecs >> 5); + return max_nsecs - (max_nsecs >> 3); } /// # 计算时钟源的mult和shift,以便将一个时钟源的频率转换为另一个时钟源的频率 @@ -318,9 +320,8 @@ impl dyn Clocksource { /// # 更新时钟源频率,初始化mult/shift 和 max_idle_ns fn clocksource_update_freq_scale(&self, scale: u32, freq: u32) -> Result<(), SystemError> { - let mut cs_data = self.clocksource_data(); - if freq != 0 { + let mut cs_data = self.clocksource_data(); let mut sec: u64 = cs_data.mask.bits(); sec /= freq as u64; @@ -335,8 +336,10 @@ impl dyn Clocksource { self.clocks_calc_mult_shift(freq, NSEC_PER_SEC / scale, sec as u32 * scale); cs_data.set_mult(mult); cs_data.set_shift(shift); + self.update_clocksource_data(cs_data)?; } + let mut cs_data = self.clocksource_data(); if scale != 0 && freq != 0 && cs_data.uncertainty_margin == 0 { cs_data.set_uncertainty_margin(NSEC_PER_SEC / (scale * freq)); if cs_data.uncertainty_margin < 2 * WATCHDOG_MAX_SKEW { @@ -348,10 +351,25 @@ impl dyn Clocksource { // 确保时钟源没有太大的mult值造成溢出 cs_data.set_maxadj(self.clocksource_max_adjustment()); + self.update_clocksource_data(cs_data)?; + while freq != 0 + && (self.clocksource_data().mult + self.clocksource_data().maxadj + < self.clocksource_data().mult + || self.clocksource_data().mult - self.clocksource_data().maxadj + > self.clocksource_data().mult) + { + let mut cs_data = self.clocksource_data(); + cs_data.set_mult(cs_data.mult >> 1); + cs_data.set_shift(cs_data.shift - 1); + self.update_clocksource_data(cs_data)?; + let mut cs_data = self.clocksource_data(); + cs_data.set_maxadj(self.clocksource_max_adjustment()); + self.update_clocksource_data(cs_data)?; + } + let mut cs_data = self.clocksource_data(); let ns = self.clocksource_max_deferment(); cs_data.set_max_idle_ns(ns as u32); - self.update_clocksource_data(cs_data)?; return Ok(()); @@ -387,7 +405,7 @@ impl dyn Clocksource { // 根据rating由大到小排序 let cs_data = self.clocksource_data(); let mut list_guard = CLOCKSOURCE_LIST.lock(); - let mut spilt_pos: usize = 0; + let mut spilt_pos: usize = list_guard.len(); for (pos, ele) in list_guard.iter().enumerate() { if ele.clocksource_data().rating < cs_data.rating { spilt_pos = pos; @@ -445,7 +463,7 @@ impl dyn Clocksource { drop(list_guard); // 对比当前注册的时间源的精度和监视器的精度 - let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock_irqsave(); + let mut cs_watchdog = CLOCKSOURCE_WATCHDOG.lock_irqsave(); if cs_watchdog.watchdog.is_none() || cs_data.rating > cs_watchdog @@ -496,7 +514,7 @@ impl dyn Clocksource { /// # 将时间源从监视链表中弹出 fn clocksource_dequeue_watchdog(&self) { let data = self.clocksource_data(); - let mut locked_watchdog = CLOCKSOUCE_WATCHDOG.lock_irqsave(); + let mut locked_watchdog = CLOCKSOURCE_WATCHDOG.lock_irqsave(); let watchdog = locked_watchdog .get_watchdog() .clone() @@ -652,10 +670,14 @@ pub struct ClocksourceData { pub max_idle_ns: u32, pub flags: ClocksourceFlags, pub watchdog_last: CycleNum, + /// 用于watchdog机制中的字段,记录主时钟源上一次被读取的周期数 + pub cs_last: CycleNum, // 用于描述时钟源的不确定性边界,时钟源读取的时间可能存在的不确定性和误差范围 pub uncertainty_margin: u32, // 最大的时间调整量 pub maxadj: u32, + /// 上一次读取时钟源时的周期数 + pub cycle_last: CycleNum, } impl ClocksourceData { @@ -681,8 +703,10 @@ impl ClocksourceData { max_idle_ns, flags, watchdog_last: CycleNum(0), + cs_last: CycleNum(0), uncertainty_margin, maxadj, + cycle_last: CycleNum(0), }; return csd; } @@ -727,6 +751,9 @@ impl ClocksourceData { /// converts clocksource cycles to nanoseconds /// pub fn clocksource_cyc2ns(cycles: CycleNum, mult: u32, shift: u32) -> u64 { + // info!(""); + // info!("cycles = {:?}, mult = {:?}, shift = {:?}", cycles, mult, shift); + // info!("ret = {:?}", (cycles.data() * mult as u64) >> shift); return (cycles.data() * mult as u64) >> shift; } @@ -768,7 +795,7 @@ pub fn clocksource_suspend() { /// * `Ok()` - 检查完成 /// * `Err(SystemError)` - 错误码 pub fn clocksource_watchdog() -> Result<(), SystemError> { - let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock_irqsave(); + let cs_watchdog = CLOCKSOURCE_WATCHDOG.lock_irqsave(); // debug!("clocksource_watchdog start"); // watchdog没有在运行的话直接退出 @@ -776,17 +803,7 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> { // debug!("is_running = {:?},watchdog = {:?}", cs_watchdog.is_running, cs_watchdog.watchdog); return Ok(()); } - let cur_watchdog = cs_watchdog.watchdog.as_ref().unwrap().clone(); - let cur_wd_data = cur_watchdog.as_ref().clocksource_data(); - let cur_wd_nowclock = cur_watchdog.as_ref().read().data(); - let wd_last = cs_watchdog.last_check.data(); - let wd_dev_nsec = clocksource_cyc2ns( - CycleNum((cur_wd_nowclock - wd_last) & cur_wd_data.mask.bits), - cur_wd_data.mult, - cur_wd_data.shift, - ); - cs_watchdog.last_check = CycleNum(cur_wd_nowclock); drop(cs_watchdog); let watchdog_list = WATCHDOG_LIST.lock_irqsave(); for cs in watchdog_list.iter() { @@ -798,11 +815,27 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> { { // debug!("clocksource_watchdog unstable"); // 启动watchdog_kthread - run_watchdog_kthread(); + if FINISHED_BOOTING.load(Ordering::Relaxed) { + // TODO 在实现了工作队列后,将启动线程换成schedule work + run_watchdog_kthread(); + } continue; } + // 读取时钟源现在的时间 let cs_now_clock = cs.read(); + // 读取watchdog现在的时间 + let wd = CLOCKSOURCE_WATCHDOG.lock_irqsave(); + let wd_now = wd.watchdog.as_ref().unwrap().clone(); + let wd_now_data = wd_now.as_ref().clocksource_data(); + let wd_now_clock = wd_now.as_ref().read().data(); + + // info!("cs_name = {:?}", cs_data.name); + // info!("cs_last = {:?}", cs_data.cs_last); + // info!("cs_now_clock = {:?}", cs_now_clock); + // info!("wd_name"); + // info!("wd_last = {:?}", cs_data.watchdog_last); + // info!("wd_now_clock = {:?}", wd_now_clock); // 如果时钟源没有被监视,则开始监视他 if !cs_data @@ -814,29 +847,37 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> { .flags .insert(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG); // 记录此次检查的时刻 - cs_data.watchdog_last = cs_now_clock; + cs_data.watchdog_last = CycleNum::new(wd_now_clock); + cs_data.cs_last = cs_now_clock; cs.update_clocksource_data(cs_data.clone())?; continue; } - // debug!("cs_data.watchdog_last = {:?},cs_now_clock = {:?}", cs_data.watchdog_last, cs_now_clock); - // 计算时钟源的误差 + + let wd_dev_nsec = clocksource_cyc2ns( + CycleNum((wd_now_clock - cs_data.watchdog_last.data()) & wd_now_data.mask.bits), + wd_now_data.mult, + wd_now_data.shift, + ); + let cs_dev_nsec = clocksource_cyc2ns( - CycleNum(cs_now_clock.div(cs_data.watchdog_last).data() & cs_data.mask.bits), - cs_data.mult, - cs_data.shift, + CycleNum(cs_now_clock.div(cs_data.cs_last).data() & cs_data.mask.bits), + cs_data.mult, // 2343484437 + cs_data.shift, // 23 ); // 记录此次检查的时刻 - cs_data.watchdog_last = cs_now_clock; + cs_data.watchdog_last = CycleNum::new(wd_now_clock); + cs_data.cs_last = cs_now_clock; cs.update_clocksource_data(cs_data.clone())?; + + // 判断是否有误差 if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() { // debug!("set_unstable"); // 误差过大,标记为unstable info!("cs_dev_nsec = {}", cs_dev_nsec); info!("wd_dev_nsec = {}", wd_dev_nsec); - cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?; + cs.set_unstable(cs_dev_nsec.abs_diff(wd_dev_nsec).try_into().unwrap())?; continue; } - // debug!("clocksource_watchdog aaa"); // 判断是否要切换为高精度模式 if !cs_data @@ -845,7 +886,7 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> { && cs_data .flags .contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS) - && cur_wd_data + && wd_now_data .flags .contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS) { @@ -861,7 +902,7 @@ pub fn clocksource_watchdog() -> Result<(), SystemError> { } fn create_new_watchdog_timer_function() { - let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock_irqsave(); + let mut cs_watchdog = CLOCKSOURCE_WATCHDOG.lock_irqsave(); cs_watchdog.timer_expires += WATCHDOG_INTERVAL; //创建定时器执行watchdog @@ -890,25 +931,13 @@ fn __clocksource_watchdog_kthread() { } // 检查是否需要停止watchdog - CLOCKSOUCE_WATCHDOG + CLOCKSOURCE_WATCHDOG .lock_irqsave() .clocksource_stop_watchdog(wd_list.len()); drop(wd_list); // 将不稳定的时钟源精度都设置为最低,然后删除unstable标记 for clock in del_clocks.iter() { clock.clocksource_change_rating(0); - let mut data = clock.clocksource_data(); - data.watchdog_last = clock.read(); - debug!("kthread: watchdog_last = {:?}", data.watchdog_last); - data.flags.remove(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE); - clock - .update_clocksource_data(data) - .expect("clocksource_watchdog_kthread: failed to update clocksource data"); - - // 重新插入监视链表 - clock - .clocksource_enqueue_watchdog() - .expect("clocksource_watchdog_kthread: failed to enqueue watchdog list"); } } @@ -947,7 +976,7 @@ pub fn clocksource_resume_watchdog() { /// # 根据精度选择最优的时钟源,或者接受用户指定的时间源 pub fn clocksource_select() { let list_guard = CLOCKSOURCE_LIST.lock(); - if FINISHED_BOOTING.load(Ordering::Relaxed) || list_guard.is_empty() { + if !FINISHED_BOOTING.load(Ordering::Relaxed) || list_guard.is_empty() { return; } let mut best = list_guard.front().unwrap().clone(); diff --git a/kernel/src/time/jiffies.rs b/kernel/src/time/jiffies.rs index cde4ebd7..4025295f 100644 --- a/kernel/src/time/jiffies.rs +++ b/kernel/src/time/jiffies.rs @@ -48,16 +48,20 @@ impl Clocksource for ClocksourceJiffies { fn clocksource(&self) -> Arc { self.0.lock_irqsave().self_ref.upgrade().unwrap() } - fn update_clocksource_data(&self, _data: ClocksourceData) -> Result<(), SystemError> { + fn update_clocksource_data(&self, data: ClocksourceData) -> Result<(), SystemError> { let d = &mut self.0.lock_irqsave().data; - d.set_flags(_data.flags); - d.set_mask(_data.mask); - d.set_max_idle_ns(_data.max_idle_ns); - d.set_mult(_data.mult); - d.set_name(_data.name); - d.set_rating(_data.rating); - d.set_shift(_data.shift); - d.watchdog_last = _data.watchdog_last; + d.set_name(data.name); + d.set_rating(data.rating); + d.set_mask(data.mask); + d.set_mult(data.mult); + d.set_shift(data.shift); + d.set_max_idle_ns(data.max_idle_ns); + d.set_flags(data.flags); + d.watchdog_last = data.watchdog_last; + d.cs_last = data.cs_last; + d.set_uncertainty_margin(data.uncertainty_margin); + d.set_maxadj(data.maxadj); + d.cycle_last = data.cycle_last; return Ok(()); } @@ -76,8 +80,10 @@ impl ClocksourceJiffies { max_idle_ns: Default::default(), flags: ClocksourceFlags::new(0), watchdog_last: CycleNum::new(0), + cs_last: CycleNum::new(0), uncertainty_margin: 0, maxadj: 0, + cycle_last: CycleNum::new(0), }; let jiffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies { data, diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs index 2e695a40..e7d6f16f 100644 --- a/kernel/src/time/mod.rs +++ b/kernel/src/time/mod.rs @@ -13,6 +13,7 @@ pub mod clocksource; pub mod jiffies; pub mod sleep; pub mod syscall; +pub mod tick_common; pub mod timeconv; pub mod timekeep; pub mod timekeeping; diff --git a/kernel/src/time/tick_common.rs b/kernel/src/time/tick_common.rs new file mode 100644 index 00000000..24e89c68 --- /dev/null +++ b/kernel/src/time/tick_common.rs @@ -0,0 +1,25 @@ +use crate::{ + arch::interrupt::TrapFrame, + process::ProcessManager, + smp::{core::smp_get_processor_id, cpu::ProcessorId}, + time::timer::run_local_timer, +}; + +use super::timer::update_timer_jiffies; + +/// # 函数的功能 +/// 用于周期滴答的事件处理 +pub fn tick_handle_periodic(trap_frame: &TrapFrame) { + let cpu_id = smp_get_processor_id(); + + tick_periodic(cpu_id, trap_frame); +} + +fn tick_periodic(cpu_id: ProcessorId, trap_frame: &TrapFrame) { + if cpu_id.data() == 0 { + update_timer_jiffies(1); + run_local_timer(); + } + + ProcessManager::update_process_times(trap_frame.is_from_user()); +} diff --git a/kernel/src/time/timekeep.rs b/kernel/src/time/timekeep.rs index 0d81d6fa..b003b207 100644 --- a/kernel/src/time/timekeep.rs +++ b/kernel/src/time/timekeep.rs @@ -1,10 +1,16 @@ #![allow(dead_code)] +use core::intrinsics::unlikely; + use system_error::SystemError; use crate::driver::rtc::interface::rtc_read_time_default; -use super::PosixTimeSpec; +use super::{PosixTimeSpec, NSEC_PER_SEC}; + +// 参考:https://code.dragonos.org.cn/xref/linux-3.4.99/include/linux/time.h#110 +const KTIME_MAX: i64 = !(1u64 << 63) as i64; +const KTIME_SEC_MAX: i64 = KTIME_MAX / NSEC_PER_SEC as i64; #[allow(non_camel_case_types)] pub type ktime_t = i64; @@ -31,3 +37,25 @@ pub fn ktime_get_real_ns() -> i64 { let kt: ktime_t = ktime_get_real().unwrap_or(0); return ktime_to_ns(kt); } + +// # 用于将两个ktime_t类型的变量相加 +// #[inline(always)] +// pub(super) fn ktime_add(add1: ktime_t, add2: ktime_t) -> ktime_t { +// let res = add1 + add2; +// } + +/// # 通过sec和nsec构造一个ktime_t +#[inline(always)] +fn ktime_set(secs: i64, nsecs: u64) -> ktime_t { + if unlikely(secs >= KTIME_SEC_MAX) { + return KTIME_MAX; + } + + return secs * NSEC_PER_SEC as i64 + nsecs as i64; +} + +/// # 将PosixTimeSpec转换成ktime_t +#[inline(always)] +pub fn timespec_to_ktime(ts: PosixTimeSpec) -> ktime_t { + return ktime_set(ts.tv_sec, ts.tv_nsec as u64); +} diff --git a/kernel/src/time/timekeeping.rs b/kernel/src/time/timekeeping.rs index deaad142..f8c1b351 100644 --- a/kernel/src/time/timekeeping.rs +++ b/kernel/src/time/timekeeping.rs @@ -1,12 +1,13 @@ use alloc::sync::Arc; -use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, AtomicUsize, Ordering}; -use log::{debug, info}; +use core::intrinsics::{likely, unlikely}; +use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; +use log::{debug, info, warn}; use system_error::SystemError; use crate::{ - arch::{CurrentIrqArch, CurrentTimeArch}, + arch::CurrentIrqArch, exception::InterruptArch, - libs::rwlock::{RwLock, RwLockReadGuard}, + libs::rwlock::RwLock, time::{ jiffies::{clocksource_default_clock, jiffies_init}, timekeep::ktime_get_real_ns, @@ -14,10 +15,11 @@ use crate::{ }, }; +use super::timekeep::{ktime_t, timespec_to_ktime}; use super::{ clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ}, syscall::PosixTimeval, - TimeArch, NSEC_PER_SEC, + NSEC_PER_SEC, }; /// NTP周期频率 pub const NTP_INTERVAL_FREQ: u64 = HZ; @@ -28,17 +30,12 @@ pub const NTP_SCALE_SHIFT: u32 = 32; /// timekeeping休眠标志,false为未休眠 pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false); -/// 已经递增的微秒数 -static __ADDED_USEC: AtomicI64 = AtomicI64::new(0); /// timekeeper全局变量,用于管理timekeeper模块 static mut __TIMEKEEPER: Option = None; #[derive(Debug)] pub struct Timekeeper { inner: RwLock, - - /// 上一次更新墙上时间时的CPU周期数 - last_update_cpu_cycle: AtomicUsize, } #[allow(dead_code)] @@ -68,6 +65,8 @@ pub struct TimekeeperData { wall_to_monotonic: PosixTimeSpec, total_sleep_time: PosixTimeSpec, xtime: PosixTimeSpec, + /// 单调时间和实时时间的偏移量 + real_time_offset: ktime_t, } impl TimekeeperData { pub fn new() -> Self { @@ -98,6 +97,7 @@ impl TimekeeperData { tv_nsec: 0, tv_sec: 0, }, + real_time_offset: 0, } } } @@ -105,7 +105,6 @@ impl Timekeeper { fn new() -> Self { Self { inner: RwLock::new(TimekeeperData::new()), - last_update_cpu_cycle: AtomicUsize::new(0), } } @@ -118,7 +117,7 @@ impl Timekeeper { let mut timekeeper = self.inner.write_irqsave(); // 更新clock let mut clock_data = clock.clocksource_data(); - clock_data.watchdog_last = clock.read(); + clock_data.cycle_last = clock.read(); if clock.update_clocksource_data(clock_data).is_err() { debug!("timekeeper_setup_internals:update_clocksource_data run failed"); } @@ -144,33 +143,150 @@ impl Timekeeper { timekeeper.mult = clock_data.mult; } - /// # 获取当前时钟源距离上次watchdog检测走过的纳秒数 - #[allow(dead_code)] - pub fn tk_get_ns(&self) -> u64 { - let timekeeper: RwLockReadGuard<'_, TimekeeperData> = self.inner.read_irqsave(); + pub fn timekeeping_get_ns(&self) -> i64 { + let timekeeper = self.inner.read_irqsave(); let clock = timekeeper.clock.clone().unwrap(); - drop(timekeeper); - let clock_now = clock.read(); + let cycle_now = clock.read(); let clock_data = clock.clocksource_data(); - let clock_delta = clock_now.div(clock_data.watchdog_last).data() & clock_data.mask.bits(); + let cycle_delta = (cycle_now.div(clock_data.cycle_last)).data() & clock_data.mask.bits(); return clocksource_cyc2ns( - CycleNum::new(clock_delta), - clock_data.mult, - clock_data.shift, - ); + CycleNum::new(cycle_delta), + timekeeper.mult, + timekeeper.shift as u32, + ) as i64; } - #[inline] - fn do_read_cpu_cycle_ns(&self) -> usize { - let prev = self.last_update_cpu_cycle.load(Ordering::SeqCst); - CurrentTimeArch::cycles2ns(CurrentTimeArch::get_cycles().wrapping_sub(prev)) + /// # 处理大幅度调整 + pub fn timekeeping_bigadjust(&self, error: i64, interval: i64, offset: i64) -> (i64, i64, i32) { + let mut error = error; + let mut interval = interval; + let mut offset = offset; + + // TODO: 计算look_head并调整ntp误差 + + let tmp = interval; + let mut mult = 1; + let mut adj = 0; + if error < 0 { + error = -error; + interval = -interval; + offset = -offset; + mult = -1; + } + while error > tmp { + adj += 1; + error >>= 1; + } + + interval <<= adj; + offset <<= adj; + mult <<= adj; + + return (interval, offset, mult); } - fn mark_update_wall_time_ok(&self) { - self.last_update_cpu_cycle - .store(CurrentTimeArch::get_cycles(), Ordering::SeqCst); + /// # 调整时钟的mult减少ntp_error + pub fn timekeeping_adjust(&self, offset: i64) -> i64 { + let mut timekeeper = self.inner.write_irqsave(); + let mut interval = timekeeper.cycle_interval.data() as i64; + let mut offset = offset; + let adj: i32; + + // 计算误差 + let mut error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1); + + // 误差超过一个interval,就要进行调整 + if error >= 0 { + if error > interval { + error >>= 2; + if likely(error <= interval) { + adj = 1; + } else { + (interval, offset, adj) = self.timekeeping_bigadjust(error, interval, offset); + } + } else { + // 不需要校准 + return offset; + } + } else if -error > interval { + if likely(-error <= interval) { + adj = -1; + interval = -interval; + offset = -offset; + } else { + (interval, offset, adj) = self.timekeeping_bigadjust(error, interval, offset); + } + } else { + // 不需要校准 + return offset; + } + + // 检查最大调整值,确保调整值不会超过时钟源允许的最大值 + let clock_data = timekeeper.clock.clone().unwrap().clocksource_data(); + if unlikely( + clock_data.maxadj != 0 + && (timekeeper.mult as i32 + adj + > clock_data.mult as i32 + clock_data.maxadj as i32), + ) { + warn!( + "Adjusting {:?} more than ({} vs {})", + clock_data.name, + timekeeper.mult as i32 + adj, + clock_data.mult as i32 + clock_data.maxadj as i32 + ); + } + + if error > 0 { + timekeeper.mult += adj as u32; + timekeeper.xtime_interval += interval as u64; + timekeeper.xtime_nsec -= offset as u64; + } else { + timekeeper.mult -= adj as u32; + timekeeper.xtime_interval -= interval as u64; + timekeeper.xtime_nsec += offset as u64; + } + timekeeper.ntp_error -= (interval - offset) << timekeeper.ntp_error_shift; + + return offset; + } + /// # 用于累积时间间隔,并将其转换为纳秒时间 + pub fn logarithmic_accumulation(&self, offset: u64, shift: i32) -> u64 { + let mut timekeeper = self.inner.write_irqsave(); + let clock = timekeeper.clock.clone().unwrap(); + let clock_data = clock.clocksource_data(); + let nsecps = (NSEC_PER_SEC as u64) << timekeeper.shift; + let mut offset = offset; + + // 检查offset是否小于一个NTP周期间隔 + if offset < timekeeper.cycle_interval.data() << shift { + return offset; + } + + // 累积一个移位的interval + offset -= timekeeper.cycle_interval.data() << shift; + clock_data + .cycle_last + .add(CycleNum::new(timekeeper.cycle_interval.data() << shift)); + if clock.update_clocksource_data(clock_data).is_err() { + debug!("logarithmic_accumulation:update_clocksource_data run failed"); + } + timekeeper.clock.replace(clock.clone()); + + // 更新xime_nsec + timekeeper.xtime_nsec += timekeeper.xtime_interval << shift; + while timekeeper.xtime_nsec >= nsecps { + timekeeper.xtime_nsec -= nsecps; + timekeeper.xtime.tv_sec += 1; + // TODO: 处理闰秒 + } + + // TODO:更新raw_time + + // TODO:计算ntp_error + + return offset; } } @@ -201,19 +317,15 @@ pub fn getnstimeofday() -> PosixTimeSpec { Some(tk) => { xtime = tk.xtime; drop(tk); - // 提供基于cpu周期数的ns时间,以便在两次update_wall_time之间提供更好的精度 - let cpu_delta_ns = timekeeper().do_read_cpu_cycle_ns() as u64; - // 尚未同步到xtime的时间 - let tmp_delta_ns = __ADDED_USEC.load(Ordering::SeqCst) as u64 * 1000; + nsecs = timekeeper().timekeeping_get_ns(); - nsecs = cpu_delta_ns + tmp_delta_ns; // TODO 不同架构可能需要加上不同的偏移量 break; } } } - xtime.tv_nsec += nsecs as i64; + xtime.tv_nsec += nsecs; xtime.tv_sec += xtime.tv_nsec / NSEC_PER_SEC as i64; xtime.tv_nsec %= NSEC_PER_SEC as i64; // debug!("getnstimeofday: xtime = {:?}, nsecs = {:}", xtime, nsecs); @@ -267,8 +379,6 @@ pub fn timekeeping_init() { timekeeper.wall_to_monotonic.tv_sec, ) = (-timekeeper.xtime.tv_nsec, -timekeeper.xtime.tv_sec); - __ADDED_USEC.store(0, Ordering::SeqCst); - drop(irq_guard); drop(timekeeper); jiffies_init(); @@ -276,7 +386,8 @@ pub fn timekeeping_init() { } /// # 使用当前时钟源增加wall time -pub fn update_wall_time(delta_us: i64) { +/// 参考:https://code.dragonos.org.cn/xref/linux-3.4.99/kernel/time/timekeeping.c#1041 +pub fn update_wall_time() { // debug!("enter update_wall_time, stack_use = {:}",stack_use); compiler_fence(Ordering::SeqCst); let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; @@ -285,60 +396,74 @@ pub fn update_wall_time(delta_us: i64) { return; } - // ===== 请不要删除这些注释 ===== - // let clock = timekeeper.clock.clone().unwrap(); - // let clock_data = clock.clocksource_data(); - // let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits(); + let mut tk = timekeeper().inner.write_irqsave(); + // 获取当前时钟源 + let clock = tk.clock.clone().unwrap(); + let clock_data = clock.clocksource_data(); + // 计算从上一次更新周期以来经过的时钟周期数 + let mut offset = (clock.read().div(clock_data.cycle_last).data()) & clock_data.mask.bits(); + // 检查offset是否达到了一个NTP周期间隔 + if offset < tk.cycle_interval.data() { + return; + } - // timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift; - // // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查 - // timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1; - // timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift; + // 将纳秒部分转换为更高精度的格式 + tk.xtime_nsec = (tk.xtime.tv_nsec as u64) << tk.shift; - // timekeeper.xtime.tv_nsec += offset as i64; - // while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) { - // timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64; - // timekeeper.xtime.tv_sec += 1; - // // TODO 需要处理闰秒 - // } - // ================ - compiler_fence(Ordering::SeqCst); - - __ADDED_USEC.fetch_add(delta_us, Ordering::SeqCst); - compiler_fence(Ordering::SeqCst); - let mut retry = 10; - - let usec = __ADDED_USEC.load(Ordering::SeqCst); - - // 一分钟同步一次 - loop { - if (usec & !((1 << 26) - 1)) != 0 { - if __ADDED_USEC - .compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst) - .is_ok() - || retry == 0 - { - // 同步时间 - // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入 - // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。 - let mut timekeeper = timekeeper().inner.write_irqsave(); - timekeeper.xtime.tv_nsec = ktime_get_real_ns(); - timekeeper.xtime.tv_sec = 0; - __ADDED_USEC.store(0, Ordering::SeqCst); - - drop(timekeeper); - break; - } - retry -= 1; - } else { - break; + let mut shift = (offset.ilog2() - tk.cycle_interval.data().ilog2()) as i32; + shift = shift.max(0); + // let max_shift = (64 - (ntp_tick_length().ilog2()+1)) - 1; + // shift = min(shift, max_shift) + while offset >= tk.cycle_interval.data() { + offset = timekeeper().logarithmic_accumulation(offset, shift); + if offset < tk.cycle_interval.data() << shift { + shift -= 1; } } - timekeeper().mark_update_wall_time_ok(); - // TODO 需要检查是否更新时间源 + + timekeeper().timekeeping_adjust(offset as i64); + + // 处理xtime_nsec下溢问题,并对NTP误差进行调整 + if unlikely((tk.xtime_nsec as i64) < 0) { + let neg = -(tk.xtime_nsec as i64); + tk.xtime_nsec = 0; + tk.ntp_error += neg << tk.ntp_error_shift; + } + + // 将纳秒部分舍入后存储在xtime.tv_nsec中 + tk.xtime.tv_nsec = ((tk.xtime_nsec as i64) >> tk.shift) + 1; + tk.xtime_nsec -= (tk.xtime.tv_nsec as u64) << tk.shift; + + // 确保经过舍入后的xtime.tv_nsec不会大于NSEC_PER_SEC,并在超过1秒的情况下进行适当的调整 + if unlikely(tk.xtime.tv_nsec >= NSEC_PER_SEC.into()) { + tk.xtime.tv_nsec -= NSEC_PER_SEC as i64; + tk.xtime.tv_sec += 1; + // TODO: 处理闰秒 + } + + // 更新时间的相关信息 + timekeeping_update(); + compiler_fence(Ordering::SeqCst); drop(irq_guard); compiler_fence(Ordering::SeqCst); } -// TODO timekeeping_adjust // TODO wall_to_monotic + +/// 参考:https://code.dragonos.org.cn/xref/linux-3.4.99/kernel/time/timekeeping.c#190 +pub fn timekeeping_update() { + // TODO:如果clearntp为true,则会清除NTP错误并调用ntp_clear() + + // 更新实时时钟偏移量,用于跟踪硬件时钟与系统时间的差异,以便进行时间校正 + update_rt_offset(); +} + +/// # 更新实时偏移量(墙上之间与单调时间的差值) +pub fn update_rt_offset() { + let mut timekeeper = timekeeper().inner.write_irqsave(); + let ts = PosixTimeSpec::new( + -timekeeper.wall_to_monotonic.tv_sec, + -timekeeper.wall_to_monotonic.tv_nsec, + ); + timekeeper.real_time_offset = timespec_to_ktime(ts); +} diff --git a/kernel/src/time/timer.rs b/kernel/src/time/timer.rs index 270140ec..917502ca 100644 --- a/kernel/src/time/timer.rs +++ b/kernel/src/time/timer.rs @@ -366,11 +366,17 @@ pub fn try_raise_timer_softirq() { } } +/// 处理本地定时器中断 +pub fn run_local_timer() { + assert!(!CurrentIrqArch::is_irq_enabled()); + try_raise_timer_softirq(); +} + /// 更新系统时间片 -pub fn update_timer_jiffies(add_jiffies: u64, time_us: i64) -> u64 { +pub fn update_timer_jiffies(add_jiffies: u64) -> u64 { let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst); compiler_fence(Ordering::SeqCst); - update_wall_time(time_us); + update_wall_time(); compiler_fence(Ordering::SeqCst); return prev + add_jiffies;