轉自:http://blog.chinaunix.net/uid-20672257-id-2831219.html
內核一般通過jiffies值來獲取當前時間。盡管該數值表示的是自上次系統啟動到當前的時間間隔,但因為驅動程序的生命期只限於系統的運行期 (uptime),所以也是可行的。驅動程序利用jiffies的當前值來計算不同事件間的時間間隔。 硬件給內核提供一個系統定時器用以計算和管理時間,內核通過編程預設系統定時器的頻率,即節拍率(tick rate),每一個周期稱作一個tick(節拍)。Linux內核從2.5版內核開始把頻率從100調高到1000(當然帶來了很多優點,
也有一些缺點)。jiffies是內核中的一個全局變量,用來記錄自系統啟動一來產生的節拍數。譬如,如果計算系統運行了多長時間,可以用 jiffies/tick rate 來計算。
jiffies定義在文件
如果您需要更精確的時間來測量或者記錄某些事情的話,內核中有個xtime全局變量,類型是struct timespec {time_t tv_sec; long tv_nsec;}按照這個數據結構,它是ns級的。
而且還有一個current_kernel_time函數,通過它就可以獲取xtime的值。但是xtime是在時鍾中斷里更新的,而一個tick往往是 10ms或者100ms,它只能保證在時鍾中斷ISR調用時刻,它返回的值是精確到ns級,並不能保證任何一個調用這個函數的時刻都能這樣,原因是xtime的更新速度比它差幾個數量級。
如果需要精確到微妙級別,可以使用do_gettimeofday函數。該函數並不返回今天是本周的星期幾或類似的信息;它是用微秒值來填充一個指向struct timeval的指針變量。相應的原型如下:
#include
void do_gettimeofday(struct timeval *tv);
源碼中聲明的do_gettimeofday在Alpha和Sparc之外的體系結構上有“接近微秒級的分辨率” ,在Alpha和Sparc上和jiffies值的分辨率一樣。Sparc的移植版本在2.1.34版的內核中升級了,可以支持更細粒度的時間度量。
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
unsigned long nsec, sec, lost;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = system_timer->offset();
lost = jiffies - wall_jiffies;
if (lost)
usec += lost * USECS_PER_JIFFY;
sec = xtime.tv_sec;
nsec += xtime.tv_nsec;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
/* usec may have gone up a lot: be safe */
while (nsec >= 1000000000) {
nsec -= 1000000000;
sec++;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
從中可以發現,我們只要稍微的修改一下代碼就可以達到納秒的精確度了
void do_gettimeofday_nsec(struct timespec *tv)
{
unsigned long flags;
unsigned long seq;
unsigned long usec, sec, lost;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = system_timer->offset();
lost = jiffies - wall_jiffies;
if (lost)
usec += lost * USECS_PER_JIFFY;
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
/* usec may have gone up a lot: be safe */
while (usec >= 1000000) {
usec -= 1000000;
sec++;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
注意這里使用了不同的時間結構。