%20(%D0%BD%D0%B5%20VDSO)%20%D0%BD%D0%B0%20x86_64%20%D1%81%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC%20HPET%3F.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
. VDSO на T400 выглядит, на мой взгляд, довольно неплохо:
$ 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/[email protected]/(июнь 2019 г.) предполагает, что почти все (если не все?) таймеры сейчас поддерживают vDSO, но в любом случае testgtod
указанная выше программа под названием CLOCK_REALTIME
, о которой в статье 2017 г. говорится, что тогда поддерживала vDSO.
Итак: я официально запутался :)
Прочитав до концаhttp://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/, Я вижумногоссылок на TSC. В статье об этом не упоминается, но я начинаю думать, что это может RDTSC{,P}
быть непривилегированная инструкция, которую можно вызвать из пользовательского пространства, в то время как чтение из HPET требует доступа на уровне ядра (к значениям оборудования или таймера). Что полностью объясняет откат syscall.
Кстати, Core2 P8600 в моем T400 поддерживает tsc
и constant_tsc
, но не nonstop_tsc
.
Ни один изтск gettimeofday часы-gettime вдсо hpetсуществовали, если кто-то с большей репутацией захочет добавить один или несколько из них.
решение1
В статье об этом не упоминается, но я начинаю думать, что это может
RDTSC{,P}
быть непривилегированная инструкция, которую можно вызвать из пользовательского пространства, в то время как чтение из HPET требует доступа на уровне ядра (к значениям оборудования или таймера). Что полностью объясняет откат системного вызова.
Это причина.
Вы можете проверить изменение поведения vDSO между двумя часами в любой системе, которая поддерживает как tsc
и hpet
в качестве источника времени:
$ 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
является непривилегированной инструкцией, и вы можете увидеть пример ее использования вруководство GCC: найдите rdtsc
там, скомпилируйте пример кода, и вы увидите, что можете запустить его в пользовательском пространстве. (Строго говоря, RDTSC
иRDTSCP
может быть привилегированным, они не являются стандартными в Linux, но они могутбыть привилегированным, используяprctl
.)
В vDSO clock_gettimeofday
и связанных с ним функциях используются определенные режимы синхронизации; см.__arch_get_hw_counter
. Если режим часов равен VCLOCK_TSC
, время считывается без системного вызова, с помощью RDTSC
; если это VCLOCK_PVCLOCK
или VCLOCK_HVCLOCK
, оно считывается с определенной страницы для извлечения информации из гипервизора. HPETне объявляет режим часов, поэтому в итоге получается значение по умолчаниюVCLOCK_NONE
, и vDSO выполняет системный вызов для получения времени.
Набор исправлений, на который вы ссылаетесьне было унификации обработки часов между часами, а унификации ее между архитектурами. Есть еще несколько часов без поддержки vDSO, среди них HPET и ACPI.