83
技術社區[雲棲]
時間子係統14_全局時間維護
// 更新全局時間(由動態時鍾調用) // 函數任務: // 1.更新last_jiffies_update,記錄距離上次更新jiffies經曆的ns // 2.更新jiffies_64,牆上時間,計算cpu負載 // 3.更新下次周期時鍾的到期時間 // 注: // 1.在關中斷情況下調用該函數 // 2.last_jiffies_update,記錄距離上次更新經曆的時鍾周期(ns) 1.1 static void tick_do_update_jiffies64(ktime_t now) { unsigned long ticks = 0; ktime_t delta; write_seqlock(&xtime_lock); //距離上次更新jiffies經曆的ns delta = ktime_sub(now, last_jiffies_update); if (delta.tv64 >= tick_period.tv64) { //一個時鍾周期剩餘的ns delta = ktime_sub(delta, tick_period); //正常情況下,相鄰更新的jiffies差一個時鍾周期 last_jiffies_update = ktime_add(last_jiffies_update, tick_period); //慢速路徑: // jiffies距離上次更新的時間超過一個時鍾周期 if (unlikely(delta.tv64 >= tick_period.tv64)) { s64 incr = ktime_to_ns(tick_period); //剩餘的時鍾周期 ticks = ktime_divns(delta, incr); last_jiffies_update = ktime_add_ns(last_jiffies_update, incr * ticks); } //更新jiffies_64,更新牆上時間,計算cpu間負載 do_timer(++ticks); //周期時鍾下次到期時間 tick_next_period = ktime_add(last_jiffies_update, tick_period); } write_sequnlock(&xtime_lock); } // 更新全局時間 // 函數任務: // 1.更新jiffies_64 // 2.更新牆上時間 // 3.計算cpu間負載 // 調用路徑:tick_do_update_jiffies64->do_timer 1.2 void do_timer(unsigned long ticks) { jiffies_64 += ticks; update_wall_time(); calc_global_load(); } // 更新牆上時間(xtime) // 函數任務: // 1.計算距離上次更新牆上時間經曆的cycle // 2.每隔一個NTP間隔相應的cycle數 // 2.1 以clock->cycle_interval為單位,更新clock->cycle_last // 2.2 以xtime_interval為單位,更新clock->xtime_nsec // 2.3 進位clock->xtime_nsec到s // 3.根據NTP矯正clocksource // 4.更新xtime的納秒數 // 5.檢查是否有更好的時鍾源 // 注: // #define NTP_SCALE_SHIFT 32 1.3 void update_wall_time(void) { cycle_t offset; struct clocksource *clock; clock = timekeeper.clock; //距離上次更新牆上時間經曆的cycle #ifdef CONFIG_GENERIC_TIME offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask; #else offset = clock->cycle_interval; #endif //牆上時鍾的納秒數 clock->xtime_nsec = (s64)xtime.tv_nsec << clock->shift; //通過時鍾源的cycle計算經曆的NTP間隔 while (offset >= clock->cycle_interval) { //以NTP間隔對應的內部時鍾cycle更新xtime offset -= clock->cycle_interval; clock->cycle_last += clock->cycle_interval; clock->xtime_nsec += clock->xtime_interval; //ns進位到s if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) { clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift; xtime.tv_sec++; second_overflow(); } clock->raw_time.tv_nsec += clock->raw_interval; if (clock->raw_time.tv_nsec >= NSEC_PER_SEC) { clock->raw_time.tv_nsec -= NSEC_PER_SEC; clock->raw_time.tv_sec++; } //累積時間相對於NTP的誤差 clock->error += tick_length; //等效: // 1.將t1 = clock->xtime_interval>>clock->shift,得到一個NTP間隔相應的cycle數 // 2.將t2 = t1<<NTP_SCALE_SHIFT, 放大t1指定的位數 clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift); } //矯正clocksource clocksource_adjust(offset); if (unlikely((s64)clock->xtime_nsec < 0)) { s64 neg = -(s64)clock->xtime_nsec; clock->xtime_nsec = 0; clock->error += neg << (NTP_SCALE_SHIFT - clock->shift); } //更新xtime的納秒數 xtime.tv_nsec = ((s64)clock->xtime_nsec >> clock->shift) + 1; clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift; clock->error += clock->xtime_nsec << (NTP_SCALE_SHIFT - clock->shift); //檢查是否有更好的時鍾源 change_clocksource(); }
最後更新:2017-04-03 14:54:38