%20%E7%B3%BB%E7%B5%B1%E5%91%BC%E5%8F%AB%E5%97%8E%EF%BC%9F.png)
在無數次查找如何使用時,gettimeofday()
我決定這次快速深入了解一下 vDSO,因為我對它只有一個模糊的認識,並且想知道是否有任何我應該注意的使用陷阱。
根據https://stackoverflow.com/questions/42622427/gettimeofday-not-using-vdso,如果正在使用 vDSO,strace
應該絕不顯示gettimeofday
或clock_gettime
.
嗯,看起來我的 ThinkPad T400 已經壞了一段時間了:我總是看到*噸*strace
從我記事起,就一直有這樣的電話。 (特別是來自 QEMU。)
如果我嘗試testgtod.c
(運行gettimeofday()
1000 次)上述問題:
$ strace ./testgtod 2>&1 | grep clock_gettime | wc -l
1000
目前,我能發現的 ThinkPad 和 i3 桌上型電腦之間的唯一區別是 i3 使用 TSC,而 ThinkPad 使用 HPET,因為tsc: Marking TSC unstable due to TSC halts in idle
. (想知道這是否是一個暫停/恢復的事情,但後來注意到了時間戳 - 這是啟動後的 1.53 秒。)T400(當前......)運行 Arch,而 i3 盒子運行 Debian 9。
上述問題也參考了dump-vdso.c
。 T400 上的 vDSO 對我來說看起來相當不錯:
$ objdump -T vdso.so
vdso.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000740 w DF .text 000000000000005e LINUX_2.6 clock_gettime
00000000000007a0 g DF .text 0000000000000067 LINUX_2.6 __vdso_gettimeofday
00000000000007a0 w DF .text 0000000000000067 LINUX_2.6 gettimeofday
0000000000000810 g DF .text 0000000000000010 LINUX_2.6 __vdso_time
0000000000000810 w DF .text 0000000000000010 LINUX_2.6 time
0000000000000740 g DF .text 000000000000005e LINUX_2.6 __vdso_clock_gettime
0000000000000000 g DO *ABS* 0000000000000000 LINUX_2.6 LINUX_2.6
0000000000000820 g DF .text 0000000000000025 LINUX_2.6 __vdso_getcpu
0000000000000820 w DF .text 0000000000000025 LINUX_2.6 getcpu
我發現的另一個鏈接,https://bert-hubert.blogspot.com/2017/03/on-linux-vdso-and-clockgettime.html,表示 vDSO 代碼缺乏對某些計時器的支持,如果您使用其中之一,將回退到系統呼叫。那篇文章是 2017 年的,詳細資料在https://lore.kernel.org/linux-arm-kernel/[電子郵件受保護]/(2019 年 6 月)表明幾乎所有(如果不是全部?)計時器現在都有 vDSO 支持,但無論如何,testgtod
上面提到的程序稱為CLOCK_REALTIME
,2017 年的文章稱當時該程序是受 vDSO 支持的。
所以:我很困惑:)
通讀http://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/,我看到一個很多對 TSC 的引用。這篇文章並沒有真正提到它,但我開始認為這可能RDTSC{,P}
是一個可以從用戶空間調用的非特權指令,而從 HPET 讀取需要內核級訪問(對硬體或計時器值)。這可以完全解釋系統呼叫後備。
順便說一句,我的 T400 中的 Core2 P8600 確實支援tsc
和constant_tsc
,但不支援nonstop_tsc
。
答案1
這篇文章並沒有真正提到它,但我開始認為這可能
RDTSC{,P}
是一個可以從用戶空間調用的非特權指令,而從 HPET 讀取需要內核級訪問(對硬體或計時器值)。這可以完全解釋系統呼叫後備。
這就是原因。
tsc
您可以在支援和hpet
作為時間源的任何系統上驗證兩個時鐘之間 vDSO 行為的變化:
$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
$ echo tsc | sudo tee /sys/devices/system/clocksource/clocksource0/current_clocksource > /dev/null
$ strace -e clock_gettime date
Sun 24 Nov 10:49:49 CET 2019
+++ exited with 0 +++
$ echo hpet | sudo tee /sys/devices/system/clocksource/clocksource0/current_clocksource > /dev/null
$ strace -e clock_gettime date
clock_gettime(CLOCK_REALTIME, {tv_sec=1574589034, tv_nsec=589851883}) = 0
Sun 24 Nov 10:50:34 CET 2019
+++ exited with 0 +++
(記得恢復原來的時鐘來源。)
RDTSC
是一條非特權指令,您可以在中查看其使用範例海灣合作委員會手冊:搜尋rdtsc
那裡,編譯範例程式碼,你會發現可以在使用者空間中運行它。 (嚴格來說,RDTSC
並且RDTSCP
可以享有特權,預設情況下它們不在 Linux 下,但它們可以獲得特權使用prctl
.)
在vDSO中,clock_gettimeofday
相關功能依賴特定的時鐘模式;看__arch_get_hw_counter
。如果時鐘模式為VCLOCK_TSC
,則無需系統呼叫即可讀取時間,使用RDTSC
;如果是VCLOCK_PVCLOCK
或VCLOCK_HVCLOCK
,則從特定頁面讀取以從管理程式檢索資訊。高溫PET沒有聲明時鐘模式,所以最終得到預設值VCLOCK_NONE
,並且 vDSO 發出系統呼叫來檢索時間。
您連結到的補丁集不是要統一跨時脈的時脈處理,而是統一跨架構的時脈處理。還有一些時脈不支援 vDSO,其中包括 HPET 和 ACPI。