如何計算時間間隔(2014/2/20)

在進行重要的時間運算的時候,比如自己實現定時器,不能夠使用time/gettimeofday,建議使用TSC或jiffies。

1 問題

1.1現象1

應用(ePDG)中有許多的定時器,這些定時器通過一個隊列和一個線程進行管理。定時器加入到隊列時,用time/gettimeofday獲取當前時間(記爲timer_start),加上用戶傳入的延時參數(delay)會,得到定時器應該被觸發的時間(timer_start+delay)。線程每隔10ms,用time/gettimeofday獲取當前時間(curr_time),檢查隊列上的定時器的觸發時間是否小於當前時間,即滿足如下條件的定時器應該被觸發

(timer_start+delay)<curr_time

在系統運行過程中,用date命令修改OS時間後,發現定時器不會在指定的時間內被觸發。

1.2 現象2

應用(ePDG)會計算一個用戶在線時長。計算用戶在線時長非常簡單,用戶上線時調用time()函數獲取當前時間(logon_time),用戶下線是調用time()函數獲取當前時間(logout_time),logout_time-logon_time即用戶的在線時長。

用戶上線以後,用date命令修改OS時間後,發現用戶的在線時長明顯與實際不符。

2 分析

由於time/gettimeofday函數獲取的是OS wall時間,即我們看到的系統時間。如果修改wall 時間,time/gettimeofday函數獲取到的時間是會隨之變化的。所以,在不同的時間點調用time/gettimeofday函數獲得當前時間,然後相減獲得時間間隔的方法是不對的。

3 解決方案

使用TSC或jiffies來計算時間間隔。

4 關於時間

4.1 實際時間/wall時間

實際時間(牆上時間)定義在文件kernel/timer.c中:

struct timespec xtime;

timespec數據結構定義在文件<linux/time.h>中,形式如下:

structtimespec{      
    time_t  tv_sec;           /* 秒 */
    longtv_nsec;               /* 納秒 */
};

其中,xtime.tv_sec以秒爲單位,存放着自1970年7月1日以來經過的時間。xtime.tv_nsec記錄了自上一秒開始經過的納秒數。xtime是用過time interrupt來更新的。從用戶空間取得牆上時間的主要接口是gettimeofday/time。

實時時鐘(RTC)是用來持久存放系統時間的設備,即便系統關閉後,它可以靠主板上的微型電池提供的電力保持系統的計時。系統啓動時,內核通過讀取RTC來初始化WallTime,並存放在xtime變量中,這是RTC最主要的作用我們可以通過date命令修改實時時鐘。

4.2 jiffies

HZ

Linux核心每隔固定週期會發出timerinterrupt (IRQ 0),即每隔固定時間間隔調用一次時間中斷。HZ是用來定義每一秒有幾次timer interrupts。可以通過/proc/HZ查看HZ的值。

TICK

TickHZ的倒數,意即timerinterrupt每發生一次中斷的時間。如HZ250時,tick4毫秒(millisecond)

jiffies

<linux/jiffies.h>,定義了JiffiesLinux核心變數(32位元變數,unsignedlong),它被用來紀錄系統自開機以來,已經過多少的tick,在linux內核中jiffies遠比xtime重要。每發生一次timer interruptJiffies變數會被加一。由於時間中斷是通過底層的硬件實現的,所以通過jiffies獲取時間間隔不會隨着wall時間改變而改變。

4.3 TSC

TSC(time stamp counter)記錄自啓動以來處理器消耗的時鐘週期數,它是intel CPU提供的一個計數器。它在每個時鐘週期到來時,該計數器自動加一。因爲 TSC 隨着處理器週期速率的變化而變化,所以它提供了非常高的精確度。它經常被用來分析和檢測代碼。TSC 的值可以通過 rdtsc 指令來讀取。TSC 的節拍還可以轉換爲秒,轉換方法是將其除以 CPU 的時鐘速率(可以從內核變量 cpu_khz 獲取)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章