1. ホーム
  2. java

[解決済み] System.nanoTime()は全く使えないのか?

2022-04-26 18:18:38

質問

ブログ記事で紹介したように JavaにおけるSystem.nanoTime()の注意点 x86システムでは、JavaのSystem.nanoTime()は CPU のカウンタがあります。ここで、私が呼び出しの時間を測定するために使用する次のケースを考えてみましょう。

long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;

さて、マルチコアシステムでは、時間1を計測した後、スレッドは前のCPUのカウンタより小さい別のプロセッサにスケジューリングされる可能性があります。したがって、time2 の値は次のようになります。 少ない 時間1より したがって、timeSpentには負の値が入ることになります。

このケースを考えると、今のところSystem.nanotimeはかなり使い物にならないのではないでしょうか?

システム時刻を変更してもナノタイムに影響がないことは知っています。それは私が上で説明した問題ではありません。問題は、各CPUが電源を入れてから異なるカウンターを保持することです。このカウンターは、最初のCPUと比較して2番目のCPUでは低くなる可能性があります。スレッドはtime1を取得した後、OSによって2番目のCPUにスケジューリングされることがあるので、timeSpentの値は不正確で、マイナスになることもありえます。

解決方法は?

この回答は、2011年に、当時のOS上で動作する当時のSun JDKが実際に行っていたことの観点から書かれたものです。ずいぶん昔の話ですね。 レヴェントフさんの回答 は、より最新の視点を提供しています。

その投稿は間違いであり nanoTime が安全です。その投稿には、以下のようなコメントがあり、リンクしています。 David Holmesのブログ記事 Sunのリアルタイムと並行処理の専門家です。こう書いてある。

<ブロッククオート

System.nanoTime() は QueryPerformanceCounter/QueryPerformanceFrequency API を使用して実装されています [...] QPC が使用するデフォルトメカニズムは Hardware Abstraction layer(HAL) によって決定されます [...] このデフォルトはハードウェアだけでなく OS バージョン間でも変更されています。たとえば、Windows XP Service Pack 2 では、プロセッサ タイムスタンプ カウンタ (TSC) ではなく、パワー マネジメント タイマ (PMTimer) を使用するように変更されました。これは、SMP システムの異なるプロセッサで TSC が同期されていない問題や、パワー マネジメント設定によってその周波数(つまり、経過時間との関係)が変化するためです。

つまり、Windowsでは、この でした WinXP SP2までは問題なかったのですが、今はありません。

他のプラットフォームについて書かれたパートII(以上)は見当たりませんが、その記事にはLinuxが同じ問題に遭遇し、同じように解決したという記述があり、そのリンク先として clock_gettime(CLOCK_REALTIME)に関するFAQです。 と書いてある。

  1. clock_gettime(CLOCK_REALTIME) は、すべてのプロセッサ/コアで一貫していますか?(アーキテクチャは重要ですか? 例: ppc, arm, x86, amd64, sparc).

それは すべき でないとバグとみなされる。

しかし、x86/x86_64 では、非同期または可変周波数の TSC が時間の不一致を引き起こすことがあります。2.4 カーネルはこれに対する防御が全くなく、初期の 2.6 カーネルもこの点ではあまりうまくいっていませんでした。2.6.18 以降では、これを検出するロジックが改善され、通常は安全なクロックソースにフォールバックするようになりました。

ppcは常にタイムベースが同期しているので、問題ないはずです。

つまり、ホームズのリンクは、次のことを意味していると読み取れるのです。 nanoTime コール clock_gettime(CLOCK_REALTIME) というのは、IBM と Motorola は Intel と違って、マイクロプロセッサの設計を実際に知っているからです)。

SPARCやSolarisについては、残念ながら言及されていない。そしてもちろん、IBMのJVMが何をするのか見当もつかない。しかし、最新のWindowsとLinux上のSun JVMは、これを正しく実行しています。

編集部:この回答は、引用しているソースに基づいています。しかし、実際には完全に間違っているのではないかと、私はまだ心配しています。もっと最新の情報があれば、本当に貴重だと思います。私はちょうど Linuxのクロックに関する4年前の新しい記事 というのは便利かもしれません。