歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 淺談時間函數gettimeofday的成本

淺談時間函數gettimeofday的成本

日期:2017/3/1 10:34:42   编辑:Linux編程

我們在程序中會頻繁地取當前時間,例如處理一個http請求時,兩次調用gettimeofday取差值計算出處理該請求消耗了多少秒。這樣的調用無處不在,所以我們有必要詳細了解下,gettimeofday這個函數做了些什麼?內核1ms一次的時鐘中斷處理真的可以支持tv_usec字段達到微秒精度嗎?它的調用成本在i386/x86_64體系架構上代價一樣嗎?如果在系統繁忙時,頻繁的調用它有問題嗎?

gettimeofday是C庫提供的函數(不是系統調用),它封裝了內核裡的sys_gettimeofday系統調用,就是說,歸根到底是系統調用。

但是,內核對於x86_64體系結構下,除了普通的系統調用外,還提供了sysenter和vsyscall方式來獲取內核態的數據。目前我們使用的操作系統大都是x86_64體系的,如果我們用strace命令跟蹤,就會發現gettimeofday命令實際上沒有執行系統調用(i386體系會有),這是因為:x86_64體系上,使用vsyscall實現了gettimeofday這個系統調用。具體就是,創建了一個共享的內存頁面,它是在內核態的,它的數據由內核來維護,但是,用戶態也有權限訪問這個內核頁面,由此,不通過中斷gettimeofday也就拿到了系統時間。

接下來,我來詳細回答以上4個問題。

一、gettimeofday做了些什麼?

它把內核保存的牆上時間和jiffies綜合處理後返回給用戶。解釋下牆上時間和jiffies是什麼:1、牆上時間就是實際時間(1970/1/1號以來的時間),它是由我們主板電池供電的(裝過PC機的同學都了解)RTC單元存儲的,這樣即使機器斷電了時間也不用重設。當操作系統啟動時,會用這個RTC來初始化牆上時間,接著,內核會在一定精度內根據jiffies維護這個牆上時間。2、jiffies就是操作系統啟動後經過的時間,它的單位是節拍數。有些體系架構,1個節拍數是10ms,但我們常用的x86體系下,1個節拍數是1ms。也就是說,jiffies這個全局變量存儲了操作系統啟動以來共經歷了多少毫秒。我們來看看gettimeofday是如何做的。首先它調用了sys_gettimeofday系統調用。

[cpp]
  1. asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
  2. {
  3. if (likely(tv != NULL)) {
  4. struct timeval ktv;
  5. do_gettimeofday(&ktv);
  6. if (copy_to_user(tv, &ktv, sizeof(ktv)))
  7. return -EFAULT;
  8. }
  9. if (unlikely(tz != NULL)) {
  10. if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
  11. return -EFAULT;
  12. }
  13. return 0;
  14. }
大家看到,它調用do_gettimeofday函數取到當前時間存儲到局部變量ktv上,www.linuxidc.com 然後調用copy_to_user把結果復制到用戶空間。每個體系都有自己的實現,我這裡就簡單列下x86_64體系下do_gettimeofday的實現:

[cpp]
  1. void do_gettimeofday(struct timeval *tv)
  2. {
  3. unsigned long seq, t;
  4. unsigned int sec, usec;
  5. do {
  6. seq = read_seqbegin(&xtime_lock);
  7. sec = xtime.tv_sec;
  8. usec = xtime.tv_nsec / 1000;
  9. /* i386 does some correction here to keep the clock
  10. monotonous even when ntpd is fixing drift.
  11. But they didn't work for me, there is a non monotonic
  12. clock anyways with ntp.
  13. I dropped all corrections now until a real solution can
  14. be found. Note when you fix it here you need to do the same
  15. in arch/x86_64/kernel/vsyscall.c and export all needed
  16. variables in vmlinux.lds. -AK */
  17. t = (jiffies - wall_jiffies) * (1000000L / HZ) +
  18. do_gettimeoffset();
  19. usec += t;
  20. } while (read_seqretry(&xtime_lock, seq));
  21. tv->tv_sec = sec + usec / 1000000;
  22. tv->tv_usec = usec % 1000000;
  23. }
大家看到,只是把xtime加以jiffies修正後返回給用戶而已。而xtime變量和jiffies的維護更新頻率,就決定了時間精度,上面說了,每10或者1ms才處理一次時鐘中斷,難道精度只到1ms嗎?繼續往下。
Copyright © Linux教程網 All Rights Reserved