HPET を使用する x86_64 で (非 VDSO) clock_gettime() システムコールが表示されるはずですか?

HPET を使用する x86_64 で (非 VDSO) clock_gettime() システムコールが表示されるはずですか?

何度も使い方を調べているうちに、gettimeofday()vDSO について漠然とした知識しかなく、注意すべき使用上の落とし穴があるかどうか疑問に思ったため、今回は vDSO について簡単に調べてみることにしました。

によるとhttps://stackoverflow.com/questions/42622427/gettimeofday-not-using-vdsovDSOが使用されている場合はstrace一度もないgettimeofdayまたはを表示しますclock_gettime

私のThinkPad T400はしばらく前から壊れているようです。*トン*strace私が覚えている限り、これらの呼び出しはずっと続いています。(特に QEMU から)

上記の質問から試してみるとtestgtod.c(1000 回実行されます):gettimeofday()

$ 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 からの読み取りにはカーネル レベルのアクセス (ハードウェアまたはタイマー値への) が必要であると考え始めています。これは、syscall フォールバックを完全に説明するものです。

ちなみに、私の T400 の Core2 P8600 は と をサポートしていますtscconstant_tsc、 はサポートしていませんnonstop_tsc

どれも より評判の高い人が 1 つ以上のものを追加したい場合は、存在します。

答え1

記事では特に触れられていませんが、これRDTSC{,P}はユーザー空間から呼び出すことができる非特権命令である可能性があり、HPET からの読み取りにはカーネル レベルのアクセス (ハードウェアまたはタイマー値への) が必要であると考え始めています。これは、syscall フォールバックを完全に説明するものです。

これがまさにその理由だ。

tscと の両方をhpet時間ソースとしてサポートするシステムでは、2 つのクロック間の 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は非特権命令であり、その使用例は次の通りです。GCCマニュアル: そこから検索してrdtscサンプルコードをコンパイルすると、ユーザースペースで実行できることがわかります。(厳密に言えばRDTSCRDTSCP 特権を与えられるLinuxではデフォルトではそうではありませんが、特権を得るprctl

vDSOでは、clock_gettimeofday関連する機能は特定のクロックモードに依存します。__arch_get_hw_counterクロック モードが の場合VCLOCK_TSC、 はシステム コールなしで によって読み取られますRDTSC。 または の場合はVCLOCK_PVCLOCKVCLOCK_HVCLOCKハイパーバイザから情報を取得するために特定のページから読み取られます。 HPETクロックモードを宣言しない、デフォルトで終わるVCLOCK_NONEvDSO はシステム コールを発行して時間を取得します。

リンクしたパッチセットクロック間でクロック処理を統一することではなく、アーキテクチャ間でクロック処理を統一することです。vDSO をサポートしていないクロックがまだいくつかあり、その中には HPET や ACPI も含まれます。

関連情報