在无数次查找如何使用时,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。