1. 時間相關硬體
電腦系統中的時間主要由三種時鐘硬體提供的:系統時鐘(Real Time
Clock,RTC),可程式化間隔定時器(Programmable Interval Timer,PIT),時間戳記計數器(Time Stamp
Counter,TSC)。這些時鐘硬體都是基於固定頻率的晶振來提供時鐘方波訊號輸入。
一般說來,Linux核心主要需要兩種類型的時間:
一類是單步遞增性時鐘,不發送中斷,需要軟體主動去讀取其COUNTER寄存器來獲得時間的。TSC即屬於這一類。
另一種維持一個固定周期的定時器,以提醒核心或使用者一段時間已經過去了。通過周期性發送中斷達到記時目的。PIT屬於這一類。
RTC 通過主板上的電池來供電,在關機時維持日期和時間。RTC為整個電腦提供了一個計時標準,是底層的時鐘資料,也被稱為硬體時鐘CMOS時鐘。
PIT 定時/計數器所採用的最典型的晶片是Intel
8253/8254可程式化定時/計數晶片。定時/計數器從RTC接收輸入脈衝,然後開始遞減計數,當計數到零時,產生一個輸出脈衝,引發即時中斷處理程
序,然後定時/計數器複位又開始從頭計數。在開機時,作業系統通過擷取RTC中的時間資料來初始化系統時鐘,然後通過定時/計數晶片的向下計數引發時鐘中
斷,形成系統時鐘(clock tick),頻率大致在100-1000Hz之間。
TSC 是一個不斷增加的計數器,它在CPU的每個時鐘訊號到來時加1。也就是以處理器頻率加1。即在主流處理器上更新頻率可達到上GHz。
2. 時間相關資料結構
Linux有兩個重要的資料結構,一個是32位的不帶正負號的整數全域變數jiffies,
每次時鐘中斷時加1(一般相隔1ms-10ms),linux運行時就是以這個時間來記錄的,如進程時間片更新,執行定時服務等,可以視為Linux運行
的心跳。另一個是全域變數xtime,是timeval結構的變數。用來表示目前時間距UNIX時間基準1970-01-01
00:00:00的相對秒數值。其時間精度是納秒(先前的版本為微秒)。因為xtime主要供查詢使用,所以xtime的更新被放到
timer_interrupt()的後半段執行,和jiffies不同,不是每次時鐘中斷時都執行。因此看起來會比jiffies慢,兩者不同步
3. 時間相關係統調用
擷取時間的系統調用主要有兩個time()和gettimeofday()
time()即簡單的把xtime中的tv_sec返回到使用者空間。單位為秒。
gettimeofday()用來擷取精度為us的目前時間資訊和時區資訊。首先用當前的
jiffies減去上次更新xtime時的
jiffies,得到一個修正值即上次修正xtime到目前的差值,但是這個值是ms級精度的。要獲得us精度,需要用當前TSC值減去上次時鐘中斷髮生
時的TSC,用這兩個值更新xtime,並將這個值返回到使用者空間。在2.6.20中主要的調用路徑如下:
sys_gettimeofday()->
do_gettimeofday()->
offset = time_interpolator_get_offset(); ->
time_interpolator_get_counter(); ->
time_interpolator_get_cycles(); ->
get_cycles(); ->
rdtscll(); ->
get_scheduled_cycles(); ->
native_read_tsc(); ->
asm volatile("rdtsc" : "=A" (val)); //讀取TSC的值
4. 擷取精度更高的時間
在Linux中xtime的精度為ns,並且有getnstimeofday(),當並沒有作為系統調用提供。要在使用者空間獲得ns級的時間使用者可以自己實現。可以參考sys_gettimeofday 和 getnstimeofday():
sys_gettimeofday(struct timeval __user *tv){
offset = time_interpolator_get_offset();
sec = xtime.tv_sec;
nsec = xtime.tv_nsec;
usec = (nsec + offset) / 1000;
ktv->tv_sec = sec;
ktv->tv_usec = usec;
copy_to_user(tv, &ktv, sizeof(ktv));
}
getnstimeofday (struct timespec *tv)
{
sec = xtime.tv_sec;
nsec = xtime.tv_nsec+time_interpolator_get_offset();
tv->tv_sec = sec;
tv->tv_nsec = nsec;
}
5. 時鐘同步
在單處理系統中,因為系統時間(由時鐘中斷更新)和TSC(由處理器CLK訊號更新)都是由硬體負責運轉,獨立運行,所以可能出現不同步的問題(比如Linux時鐘中斷屏蔽時,jiffies不會更新)。Linux會在合適的時間使用TSC對系統時鐘進行校正。
在多處理系統中,因為有多個處理器,時鐘中斷是在處理器中廣播的,而由其中一個處理器進行時鐘中斷處理。但是TSC是每個處理器獨自擁有的,需要在各個TSC間進行同步。
在虛擬系統中(如VMware,Xen), 時鐘中斷由軟體類比產生,而TSC也不能直接從硬體上讀取,需要虛擬軟體利用處理器提供的能力,在 TSC真實的值上進行進一步的處理。