274
王者榮耀
時間子係統5_低分辨率切換高分辨率
// 切換低分辨率動態時鍾模式、或高分辨率模式 // 調用路徑:run_timer_softirq->hrtimer_run_pending // 函數任務: // 1.如果高分辨率定時器框架已經激活,則直接返回 // 2.切換到高分辨率模式的條件: // 2.1 沒有開啟低分辨率動態時鍾 // 2.2 有高分辨率的clocksource // 2.3 clockevent設備支持單觸發模式 // 3.切換到低分辨率動態時鍾的條件: // 3.1 啟動時,沒有激活高分辨率率定時框架 // 3.2 clockevent設備支持單觸發模式 1.1 void hrtimer_run_pending(void) { if (hrtimer_hres_active()) return; if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) { //切換到高分辨率模式 hrtimer_switch_to_hres(); } } // 切換低分辨率模式的動態時鍾 // 函數任務: // 1.更新tick device單觸發方式,安裝nohz事件處理函數 // 2.初始化動態時鍾數據結構 // 2.1 標識動態時鍾當前為低分辨率模式 // 2.2 動態時鍾通過單調時鍾基礎管理 // 2.3 更新動態時鍾到期時間 // 3.更新動態時鍾,tick device到期時間 2.1 static void tick_nohz_switch_to_nohz(void) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t next; local_irq_disable(); //更新tick device單觸發方式,安裝nohz事件處理函數 if (tick_switch_to_oneshot(tick_nohz_handler)) { local_irq_enable(); return; } //低分辨率動態時鍾標識 ts->nohz_mode = NOHZ_MODE_LOWRES; //低分辨率動態時鍾依賴單調時鍾 hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); //下次到期時間 next = tick_init_jiffy_update(); //更新動態時鍾,tick device到期時間 for (;;) { hrtimer_set_expires(&ts->sched_timer, next); if (!tick_program_event(next, 0)) break; next = ktime_add(next, tick_period); } local_irq_enable(); } // 低分辨率動態事件處理函數 // 函數任務: // 1.選擇cpu負責更新jiffies // 2.如果距離上次更新jiffies已經有1 jiffy,更新jiffies // 3.如果動態時鍾已經停止,說明當前在idle狀態,喂狗,防止發生softlockup // 4.更新當前進程的運行時間 // 6.更新動態時鍾的下個周期時間 // 7.重編程tick device在動態時鍾的下個周期時間到期 // 注:tick_do_timer_cpu 保存負責更新jiffies的cpu 2.2 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(); //保證tick device在最近的時間內不會到期 dev->next_event.tv64 = KTIME_MAX; //選擇cpu負責更新jiffies if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) tick_do_timer_cpu = cpu; //更新jiffies if (tick_do_timer_cpu == cpu) tick_do_update_jiffies64(now); //動態時鍾停止,說明當前在idle狀態,喂狗,防止發生softlockup if (ts->tick_stopped) { touch_softlockup_watchdog(); ts->idle_jiffies++; } //更新進程的運行時間 update_process_times(user_mode(regs)); //重編程clockevent設備 while (tick_nohz_reprogram(ts, now)) { now = ktime_get(); tick_do_update_jiffies64(now); } } // 切換高分辨率模式 // 函數任務: // 1.更新clockevent為單觸發模式,安裝高分辨率事件處理程序 // 2.初始化動態時鍾 // 2.1 更新高分辨率激活標誌 // 2.2 更新時鍾基礎為高分辨率標誌 // 3.初始化動態時鍾 // 4.更新tick device到期時間為時鍾基礎中所有hrtimer最短的到期時間 3.1 static int hrtimer_switch_to_hres(void) { int cpu = smp_processor_id(); struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu); unsigned long flags; local_irq_save(flags); //更新clockevent為單觸發模式,安裝高分辨率事件處理程序 if (tick_init_highres()) { local_irq_restore(flags); return 0; } //高分辨率激活標誌 base->hres_active = 1; base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES; base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES; //初始化動態時鍾 tick_setup_sched_timer(); //更新tick device到期時間為時鍾基礎中所有hrtimer最短的到期時間 retrigger_next_event(NULL); local_irq_restore(flags); return 1; } // 更新clockevnet為單觸發模式,安裝事件處理程序 // 調用路徑:hrtimer_switch_to_hres->tick_switch_to_oneshot 3.2 int tick_init_highres(void) { return tick_switch_to_oneshot(hrtimer_interrupt); } // 更新clockevnet為單觸發模式,安裝事件處理程序 // 調用路徑:hrtimer_switch_to_hres->...->tick_switch_to_oneshot // 函數任務: // 1.更新設備為單觸發方式 // 2.安裝事件處理程序 // 3.更新廣播設備為單觸發方式 3.3 int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) { struct tick_device *td = &__get_cpu_var(tick_cpu_device); struct clock_event_device *dev = td->evtdev; //更新設備為單觸發方式 td->mode = TICKDEV_MODE_ONESHOT; //安裝事件處理程序 dev->event_handler = handler; //編程clockevent設備為單觸發方式 clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); //切換廣播設備為單觸發方式 tick_broadcast_switch_to_oneshot(); return 0; } // 初始化動態時鍾 // 調用路徑:hrtimer_switch_to_hres->tick_setup_sched_timer // 函數任務: // 1.初始化動態時鍾的hrtimer // 2.安裝動態時鍾的回調函數 // 3.更新動態時鍾下一個jiffies到期 3.4 void tick_setup_sched_timer(void) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t now = ktime_get(); u64 offset; //初始化hrtimer hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); //動態時鍾的回調函數 ts->sched_timer.function = tick_sched_timer; //下一個jiffies到期 hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); offset = ktime_to_ns(tick_period) >> 1; do_div(offset, num_possible_cpus()); offset *= smp_processor_id(); hrtimer_add_expires_ns(&ts->sched_timer, offset); //編程啟動動態時鍾 for (;;) { hrtimer_forward(&ts->sched_timer, now, tick_period); hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); if (hrtimer_active(&ts->sched_timer)) break; now = ktime_get(); } .... }
最後更新:2017-04-03 14:54:27