在linux內核中獲得比jiffies精度更高的時間值【轉】


轉自: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;
}

注意這里使用了不同的時間結構。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM