時間子係統8_動態時鍾(NO_HZ)
// 高分辨率模式下的周期事件仿真 // 通過hrtimer仿真周期時鍾,由hrtimer_interrupt作為時鍾事件處理函數 // 函數任務: // 1.更新jiffies // 2.在irq上下文 // 2.1 如果當前處於idle狀態 // 2.1.1 喂狗softlockup_watchdog,防止誤發生softlockup // 2.1.2 更新idle狀態經曆的jiffies // 2.2 更新進程時間 // 3.調度hrtimer下一個周期繼續運行 1.1 static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) { struct tick_sched *ts = container_of(timer, struct tick_sched, sched_timer); struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); int cpu = smp_processor_id(); //高分辨率模式下,如果支持動態時鍾,則需要檢查是否本cpu負責更新全局時間 #ifdef CONFIG_NO_HZ //負責更新jiffies if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) tick_do_timer_cpu = cpu; #endif if (tick_do_timer_cpu == cpu) tick_do_update_jiffies64(now); //在irq上下文 if (regs) { //當前處於idle狀態 if (ts->tick_stopped) { //喂狗,防止誤發生softlockup touch_softlockup_watchdog(); //更新idle狀態的jiffies ts->idle_jiffies++; } //更新進程時間 update_process_times(user_mode(regs)); } //調度hrtimer下一個周期繼續運行 hrtimer_forward(timer, now, tick_period); return HRTIMER_RESTART; } // 關閉時鍾 // 函數任務: // 1.檢查下一個定時器輪事件是否在一個周期之後 // 1.1 如果是這樣,重新編程clockevent設備,直到未來合適的時間才恢複。 // 2.在tick_sched中更新統計信息 // 注:在idle進程中停用時鍾 2.1 void tick_nohz_stop_sched_tick(int inidle); .. // 恢複時鍾 // 函數任務: // 1.更新jiffies // 2.統計tick_sched中idle時間 // 3.設置tick_sched->tick_stopped=0,因此時鍾現在再次激活 // 4.重編程clockevent設備 2.2 void tick_nohz_restart_sched_tick(void); .. // 動態時鍾數據結構 3.1 struct tick_sched { struct hrtimer sched_timer; //用於實現動態時鍾的定時器 unsigned long check_clocks; enum tick_nohz_mode nohz_mode; //當前動態時鍾所處的模式 ktime_t idle_tick; //存儲在禁用周期時鍾之前,上一個時鍾信號的到期時間 int inidle; //處於idle進程中 int tick_stopped; //1,即當前沒有基於周期時鍾信號的工作要做,否則為0 unsigned long idle_jiffies; //存儲周期時鍾禁用時的jiffies unsigned long idle_calls; //內核試圖停用周期時鍾的次數 unsigned long idle_sleeps; //存儲了周期時鍾上一次禁用的時間 int idle_active; //激活了idle狀態 ktime_t idle_entrytime; //idle 被調用時的時間 ktime_t idle_waketime; //idle 被打斷的時間 ktime_t idle_exittime; //離開idle狀態的時間 ktime_t idle_sleeptime; //累計時鍾停用的總時間 ktime_t idle_lastupdate; ktime_t sleep_length; //存儲周期時鍾將禁用的長度,即從時鍾禁用起,到預計將發生下一個時鍾信號為止 unsigned long last_jiffies; // unsigned long next_jiffies; //存儲了下一個定時器到期的jiffies值 ktime_t idle_expires; //下一個將到期的經典定時器的到期時間 int do_timer_last; //記錄此cpu在停用時鍾之前是否為執行do_timer的cpu } // 低分辨率模式下的動態時鍾事件處理函數 // 在低分辨率模式下開啟動態時鍾時,關閉周期時鍾,由該函數處理時鍾事件。 4.1 static void tick_nohz_handler(struct clock_event_device *dev) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); struct pt_regs *regs = get_irq_regs(); int cpu = smp_processor_id(); ktime_t now = ktime_get(); dev->next_event.tv64 = KTIME_MAX; //由本cpu負責更新全局時間 if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) tick_do_timer_cpu = cpu; //更新全局時間 if (tick_do_timer_cpu == cpu) tick_do_update_jiffies64(now); //idle狀態停用了周期時鍾,喂狗,防止誤發生softlockup if (ts->tick_stopped) { touch_softlockup_watchdog(); //更新idle狀態持續的jiffies ts->idle_jiffies++; } //更新本cpu的時間 update_process_times(user_mode(regs)); profile_tick(CPU_PROFILING); //重編程下一個時鍾事件到期時間 while (tick_nohz_reprogram(ts, now)) { now = ktime_get(); tick_do_update_jiffies64(now); } }
最後更新:2017-04-03 14:54:29