%20clock_gettime()%20%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%B3%E3%83%BC%E3%83%AB%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%82%8B%E3%81%AF%E3%81%9A%E3%81%A7%E3%81%99%E3%81%8B%3F.png)
何度も使い方を調べているうちに、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 は と をサポートしていますtsc
がconstant_tsc
、 はサポートしていませんnonstop_tsc
。
どれも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
サンプルコードをコンパイルすると、ユーザースペースで実行できることがわかります。(厳密に言えば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 も含まれます。