52

Java アプリケーションでタイミング テストを実行したいと考えています。これは私が現在行っていることです:

long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");

このようなパフォーマンス テストに「問題」はありますか? より良い方法は何ですか?

重複:ストップウォッチのベンチマークは許容されますか?

4

9 に答える 9

36

このアプローチの 1 つの欠点は、doSomething()実行にかかる「実際の」時間が、システムで実行されている他のプログラムとその負荷によって大きく異なる可能性があることです。これにより、パフォーマンス測定が多少不正確になります。

コードがシングルスレッドであると仮定して、コードの実行にかかる時間を追跡するもう 1 つの正確な方法は、呼び出し中にスレッドによって消費される CPU 時間を調べることです。これは JMX クラスで行うことができます。特に、とThreadMXBeanThreadMXBeanfromのインスタンスを取得できますjava.lang.management.ManagementFactory。プラットフォームがサポートしている場合 (ほとんどの場合)、 のgetCurrentThreadCpuTime代わりに メソッドを使用System.currentTimeMillisして、同様のテストを実行します。ミリ秒ではなくナノ秒で時間をgetCurrentThreadCpuTime報告することに注意してください。

測定を実行するために使用できるサンプル (Scala) メソッドを次に示します。

def measureCpuTime(f: => Unit): java.time.Duration = {

  import java.lang.management.ManagementFactory.getThreadMXBean
  if (!getThreadMXBean.isThreadCpuTimeSupported)
    throw new UnsupportedOperationException(
      "JVM does not support measuring thread CPU-time")

  var finalCpuTime: Option[Long] = None
  val thread = new Thread {
    override def run(): Unit = {
      f
      finalCpuTime = Some(getThreadMXBean.getThreadCpuTime(
        Thread.currentThread.getId))
    }
  }
  thread.start()

  while (finalCpuTime.isEmpty && thread.isAlive) {
    Thread.sleep(100)
  }

  java.time.Duration.ofNanos(finalCpuTime.getOrElse {
    throw new Exception("Operation never returned, and the thread is dead " +
      "(perhaps an unhandled exception occurred)")
  })
}

(上記を自由に Java に翻訳してください!)

この戦略は完璧ではありませんが、システム負荷の変動の影響を受けにくくなっています。

于 2009-01-15T17:57:39.893 に答える
16

質問に示されているコードは、適切なパフォーマンス測定コードではありません。

  1. コンパイラは、ステートメントの順序を変更してコードを最適化することを選択する場合があります。はい、できます。つまり、テスト全体が失敗する可能性があります。テスト対象のメソッドをインライン化し、測定ステートメントをインライン化されたコードに並べ替えることができます。

  2. ホットスポットは、ステートメントの並べ替え、インライン コード、結果のキャッシュ、実行の遅延などを選択する場合があります。

  3. コンパイラ/ホットスポットにだまされなかったとしても、測定するのは「経過時間」です。測定する必要があるのは CPU 時間です (OS リソースを使用してこれらも含めたい場合や、マルチスレッド環境でロック競合を測定する場合を除きます)。

ソリューション?実際のプロファイラーを使用します。無料のプロファイラーとデモ/コマーシャルの強みの時間制限付きトライアルの両方がたくさんあります.

于 2009-01-15T20:23:44.980 に答える
3

Javaプロファイラーを使用するのが最良のオプションであり、コードに必要なすべての洞察が得られます。つまり、応答時間、スレッドCallTraces、メモリ使用率など

使いやすく、CPUにオーバーヘッドがないため、オープンソースのJavaプロファイラーであるJENSORをお勧めします。ダウンロードしてコードをインストルメント化すると、コードについて必要なすべての情報を取得できます。

次のサイトからダウンロードできます:http://jensor.sourceforge.net /

于 2009-01-24T06:40:12.833 に答える
1

の解像度はSystem.currentTimeMillis()オペレーティング システムによって異なることに注意してください。Windowsは約15ミリ秒だと思います。したがってdoSomething()、時間分解能よりも速く実行すると、デルタが 0 になります。doSomething()ループで複数回実行できますが、JVM が最適化する可能性があります。

于 2009-01-15T17:49:43.887 に答える
0

コードが JIT されて「ウォームアップ」されるように、タイミングを開始する前に doSomething() を実行したいと思うでしょう。

于 2009-01-15T17:45:14.070 に答える
0

これは、パフォーマンス テストのほんの一部です。テストする内容によっては、ヒープ サイズ、スレッド数、ネットワーク トラフィック、またはその他のホスト全体を確認する必要がある場合があります。それ以外の場合は、実行にかかる時間を確認したいだけの単純なことにその手法を使用します。

于 2009-01-15T17:46:49.667 に答える
0

Japexは、ベンチマークをすばやく作成する方法として、またはソース コードを通じて Java のベンチマークの問題を調査する方法として役立つ場合があります。

于 2009-01-15T18:37:54.447 に答える
0

netbeanseclipseのプロファイリング ツールを見たことがありますか。これらのツールを使用すると、コード内で常に時間を費やしているものをより適切に処理できます。これらのツールを使用して気づいていなかった問題を発見しました。

于 2009-01-15T18:06:46.163 に答える
0

これは、ある実装を別の実装と比較したり、コード内の遅い部分を見つけようとする場合に役立ちます (ただし、面倒な場合もあります)。これは知っておくと非常に優れた手法であり、おそらく他のどの手法よりも頻繁に使用することになるでしょうが、プロファイリング ツールにも精通している必要があります。

于 2009-01-15T17:53:46.923 に答える