web-dev-qa-db-ja.com

Javaでマイクロ秒の精度で時間を測定するにはどうすればよいですか?

私はインターネットでSystem.nanoTime()を使用することになっているのを見ましたが、それは私にとってはうまくいきません-それはミリ秒の精度で時間を与えてくれます。関数の実行前後にマイクロ秒が必要なので、どれだけ時間がかかるかを知ることができます。 Windows XPを使用しています。

基本的に、私はこのコードを持っています。たとえば、Javaリンクリストで100万から1000万の挿入を実行します。問題は、正確な正確さを測定できないことです。小さいリストにすべてを挿入するのにかかる時間が短くなります。

次に例を示します。

class test
{
    public static void main(String args[])
    {
        for(int k=1000000; k<=10000000; k+=1000000)
        {
            System.out.println(k);
            LinkedList<Integer> aux = new LinkedList<Integer>();
            //need something here to see the start time
            for(int i=0; i<k; i++)
                aux.addFirst(10000);
            //need something here to see the end time
            //print here the difference between both times
        }
    }
}

私はこれを何度も行いました-kごとに20回実行する外部ループがありました-しかし、結果は良くありません。現在使用しているもの(System.nanoTime())では正確な測定時間が得られないため、100万回の挿入にかかる時間が100万回よりも少ない場合があります。

編集2:はい、Sun JVMを使用しています。

編集3:コードで何か間違ったことをした可能性があります。それを変更すると、期待どおりに動作するかどうかを確認します。

編集4:私の間違い、System.nanoTime()は動作するようです。ふew。

22
jao

私の推測では、 System.nanoTime() は「システムで最も正確なシステムタイマー」を使用しているため、システムではミリ秒単位の精度しかありません。

31
Zach Scrivena

何をベンチマークしているのか正確にはわかりませんが、一般的に、実行に短い時間suchを要するテストでは、精度が低下します50ミリ秒以上が適切であり、very他の障害の影響を受けやすくなります。

私は通常、ベンチマークを少なくとも10秒間実行するようにしています。現在私が書いているフレームワークは、30秒かかるように実行する反復の数を推測します。つまり、他のプロセスがCPUを数ミリ秒間盗んだからといって、劇的に異なる結果が得られることはありません。

より長く実行することはほとんどの場合、より良いアプローチより細かい精度で測定することよりもです。

25
Jon Skeet

Java.timeの使用

参考までに、Java 9以降には、現在の瞬間を最大ナノ秒の解像度でキャプチャできる Clock の新しい実装があります。

Instant クラスは、 [〜#〜] utc [〜#〜] のタイムライン上の瞬間を ナノ秒 の解像度で表します(最大9(9 )小数の桁)。

Instant.now を呼び出して、現在の瞬間をキャプチャします。

  • Java 9以降では、その瞬間の解像度は最大 ナノ秒 になります。
  • Java 8では、現在の瞬間は ミリ秒 の解像度までしかキャプチャされません(実際にhold値をナノ秒で取得できますが、capture現在の瞬間(ミリ秒))。

    インスタントインスタント= Instant.now();

Duration クラスを使用して、タイムラインに接続されていない期間を表します。秒とナノ秒で時間を保持します。

Duration d = Duration.between( instantThen , Instant.now() );

明確にするために、質問で尋ねられた マイクロ秒 分解能は、ミリ秒とナノ秒の粒度の中間にあります。小数の桁数:ミリは3(0.123)、マイクロは6(0.123456)、ナノは9(0.123456789)です。

警告

Javaはコンピュータのハードウェアクロックに依存しています。他の人が警告したように、そのハードウェアはほぼ確実にナノ秒よりもはるかに低い精度およびはるかに低い解像度で時間をキャプチャします。

そのような細かい粒度でのベンチマークには問題が多く、非推奨が一般的です。

そして、 時期尚早の最適化 に注意してください。

JEP 230:Microbenchmark Suite のJavaプラットフォームにマイクロベンチマーク機能を追加する提案があります。 Java Microbenchmark Harness(JMH) に基づいています。


Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い レガシー 日時クラスに取って代わります。

Joda-Time プロジェクトは メンテナンスモード になり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 31 です。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明する場です。 IntervalYearWeekYearQuartermore などの便利なクラスがここにあります。

4
Basil Bourque

System.nanoTime()はCPUでカウンターを使用し、Windowsでは通常約1マイクロ秒の精度ですXPおよびLinux。

注:Windows XPは、異なるCPUを持つさまざまなCPUを補償しないため、マルチCPUマシンでは精度が低くなることがよくあります。Linuxは補償します。注2:System.currentTimeMillisに比べてドリフトします。 ()これは、時間を取得するために持っているクロックではなく、CPUのクロックの精度(一定期間にわたってそれほど正確である必要はない)に基づいているためです(1日あたりのドリフトが少ないため、ただし、粒度が低くなります)

ベンチマークでは、基本的に、新しいオブジェクトを作成できる速度をテストしています。当然のことながら、GCの設定とGCが最近実行された期間によって、結果は劇的に異なります。

次のオプションを使用してテストを実行すると、非常に異なる結果が表示されます。

-verbosegc -XX:NewSize=128m -mx256m
4
Peter Lawrey

それは変だ。 System.nanoTime()が機能するはずです。 Sun JVMを使用していますか?

1000回の操作を繰り返し、時間を1000で割って、知っておくべきことを見つけることができますか?

3
Sarel Botha

何千回もテストを繰り返す必要があります。ガベージコレクション、I/O、スワップイン/スワップアウト、レディキュースレッドのサイズなど、測定に影響を与える多くのことが発生しています。

3
Tiago

信頼できる結果が必要な場合は、プロファイラーを使用します。インストールが簡単で、バージョン1.6.0_07以降のJDKにバンドルされている VisualVM をお勧めします。

これは、いくつかのコマンドラインJDKツールと軽量プロファイリング機能を統合した使いやすいビジュアルツールです。

3
marcospereira

はい、通常、System.nanoTimeの精度と精度はSystem.currentTimeMillisよりもはるかに優れていますが、保証はありません。最悪の場合、同じくらい悪くなる可能性があります。

ThreadMXBean.getCurrentThreadCpuTimeは時間が短くなる傾向がありますが、その解決策は不明確であり、さらに不利な点があります(実際にCPU時間が必要ですか?、プラットフォーム依存のセマンティクス、プラットフォームでサポートされていますか?)。

3つすべての手法で時間を測定することもある程度のコストがかかります。つまり、時間自体が必要であり、測定をゆがめる可能性があります。コストはプラットフォームに大きく依存しますが、多くの場合、cost(System.currentTimeMillis)<< cost(System.nanoTime)<< cost(ThreadMXBean.getCurrentThreadCpuTime)です。

マイクロベンチマーク全般については、

1
DaveFar

基盤となるOSがナノ秒精度のタイマーを提供していない場合があります。

古い投稿 もあります。

1
starblue

最近のプロファイリングでは、ThreadMXBean.getCurrentThreadCpuTime()とオプション-XX:+UseLinuxPosixThreadCPUClocksが必要なことを行っていることがわかりました。

詳細は http://bugs.Java.com/view_bug.do?bug_id=6888526 を参照してください

0
Andrew Jessop

私が最終的に行った「迅速で汚い」ソリューション:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

更新:

私はもともとSystem.nanoTimeを使用していましたが、それが経過時間にのみ使用されるべきであることがわかり、最終的にコードを変更してミリ秒で動作するようにしたり、一部の場所で使用したりしました。

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

しかし、これは値の最後にゼロを追加するだけです(マイクロ=ミリ* 1000)

他の誰かがnanoTimeについて考えている場合に備えて、この警告をここに「警告サイン」として残しました:)

0
keisar

短い時間間隔に依存するこのようなベンチマークは、信頼できない結果をもたらします。 I/O、スワッピング、プロセススイッチ、キャッシュ、ガベージコレクションなどの外部要因により、常に異なる結果が得られます。さらに、JVMは呼び出しを最適化するため、最初に測定されたものが後の呼び出しよりも遅くなる可能性があります。 JVMは、実行するコマンドを最適化するためにますます起動します。

さらに、System.nanoTime()などのメソッドは、基盤となるシステムのタイマーに依存しています。それらはその正確さで測定するための粒度を持っていないかもしれません(そしておそらくそうするでしょう)。 [〜#〜] api [〜#〜] を引用するには:

この方法はナノ秒の精度を提供しますが、必ずしもナノ秒の精度を提供するわけではありません。値の変更頻度については保証されません。

高精度で実際に測定するには、精度が保証された外部タイミングハードウェアにアクセスする必要があります。

ベンチマークをより安定させるには、それを複数回実行し、ミリ秒よりも長い時間間隔を測定する必要があります。

0
Mnementh