2014年7月10日 星期四

Linux kernel計時器-jiffies與do_gettimeofday()

  最近有個工作是一位資深部門同事在會議中提出他發現了一個疑似跟timestamp有關的bug,簡單介紹一下就是這個timestamp在source code的其他地方是以system time 做儲存,也就是現實時間,維基條目有詳細的介紹(System time),但是某個地方的卻存成jiffies。由於怕如ˊ果有timestamp被拿來做「比較」的時候會出現單位上不同的bug,需要觀察在source code中,這個timestamp會被拿來做什麼事,於是直屬主管就將這項工作將給我。這篇文章是要來記錄一下system time跟jiffies的差異。



1. System time

  要在kernel中取得system time,有個linux kernel內建的函數可以使用,就是do_gettimeofdaydo_gettimeofday函數是宣告在kernel/time/timekeeping.c內,要使用必須將它#include進來,而do_gettimeofday的結構如下:
  do_gettimeofday所接收的argument是struct timeval這個資料結構,struct timeval被定義在linux/time.h內。
  time_t的單位是秒(second),而suseconds_t的單位是微秒(microsecond),結構都是long(長整數),32 bits。do_gettimeofday所取得的時間是從1970年1月1日0點0分0秒為起始時間開始計時到目前為止的(微)秒數,並將時間儲存在tv這個pointer的兩個成員裡。要取得目前的時間,可以從tv.tv_sec得到。

2. jiffies

  jiffies是一個unsigned long的32 bits變數,64 bits的jiffies還有額外的jiffies_64,這兩個都是kernel內的自訂變數,定義在linux/jiffies.h內。jiffies的計算是根據system會固定週期對kernel發出timer interrupt來執行遞增,是從kernel被啟動開始計時的。在這必須提到另外一個kernel中的變數HZ(赫茲)。

  HZ是固定值的變數,值是由不同的system來決定,預設值通常有100、250、300與1000。HZ的值代表著每一秒timer interrupt的數量,所以每個timer interrupt之間的間隔時間為1/HZ (HZ的倒數)。假設HZ=1000,代表一秒內有1000個timer interrupts發出,每個interrupt之間的間隔時間為1/HZ=0.001秒。在這例子下,若jiffies=2000,就知道經過了兩秒。

  由於jiffies是32 bits的變數,在值大於2^32-1=4294967295後就會overflow,在linux 2.6之後,jiffies的起始值為-300秒(-300*HZ),而在開機後五分鐘就會變成0,因此overflow。kernel有定義一些macro可以處理overflow (timer_after、time_after_eq、time_before與time_before_eq)。

3. jiffies與do_gettimeofday()

  從上面的簡介就可以知道存jiffies跟存do_gettimeofday給的tv_sec所計算的起始點不同,所以這兩個變數不能做比較。回到一開始提到的bug問題,追了code追半天,結果發現存成jiffies的timestamp並沒有被拿來比較,因此這個bug目前看來是無傷大雅,不過最近主管家裡有事都請假沒來公司,要等到他來公司後才能跟他做進一步的討論了。

Reference:
LDDP:九、計時器
Linux Kernel: 簡介HZ, tick and jiffies
http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/kernel/time/timekeeping.c

沒有留言:

張貼留言