Javaアプリケーションでタイミングテストを行いたい。これは私が現在行っていることです。
long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");
このようなパフォーマンステストで「間違った」何かがありますか?より良い方法は何ですか?
Duplicate: ストップウォッチのベンチマークは許容されますか?
このアプローチの欠点の1つは、doSomething()
の実行にかかる「リアルタイム」時間が、システムで実行されている他のプログラムとその負荷によって大きく異なる場合があることです。これにより、パフォーマンス測定が多少不正確になります。
コードがシングルスレッドであると仮定して、コードの実行にかかる時間を追跡するもう1つの正確な方法は、呼び出し中にスレッドが消費するCPU時間を調べることです。 JMXクラスを使用してこれを行うことができます。特に、 ThreadMXBean
で。 ThreadMXBean
のインスタンスを 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に自由に翻訳してください!)
この戦略は完全ではありませんが、システム負荷の変動の影響を受けにくくなります。
質問に示されているコードは、優れたパフォーマンス測定コードではありません。
コンパイラーは、ステートメントを並べ替えることでコードを最適化することを選択する場合があります。はい、できます。つまり、テスト全体が失敗する可能性があります。さらに、テスト中のメソッドをインライン化して、インライン化されたコードに測定ステートメントを並べ替えることもできます。
ホットスポットは、ステートメント、インラインコード、結果のキャッシュ、実行の遅延を並べ替える場合があります...
コンパイラ/ホットスポットがあなたをだまさないと仮定しても、あなたが測定するのは「壁時間」です。測定する必要があるのはCPU時間です(OSリソースを使用しており、これらも含める場合、またはマルチスレッド環境でロック競合を測定する場合を除く)。
ソリューション?実際のプロファイラーを使用します。無料のプロファイラーとデモ/コマーシャルの強力なもののタイムロックされたトライアルの両方がたくさんあります。
Java Profilerを使用するのが最良のオプションであり、コードに必要なすべての洞察が得られます。すなわち、応答時間、スレッドコールトレース、メモリ使用率など。
[〜#〜] jensor [〜#〜] 、オープンソースJavaプロファイラーは使いやすく、CPUにオーバーヘッドがないため、ダウンロードしてコードをインスツルメントすれば、コードについて必要なすべての情報を取得できます。
次からダウンロードできます: http://jensor.sourceforge.net /
System.currentTimeMillis()
の解像度はオペレーティングシステムによって異なることに注意してください。 Windowsは約15ミリ秒だと思います。したがって、doSomething()
が時間分解能よりも速く実行されると、0のデルタが得られます。doSomething()
をループで複数回実行できますが、JVMはそれを最適化できます。
コードがJITterで「ウォームアップ」されるように、タイミングを開始する前にSomething()を実行したいと思うと思います。
これはパフォーマンステストのほんの一部です。テスト対象に応じて、ヒープサイズ、スレッド数、ネットワークトラフィック、またはその他すべてのホスト全体を確認する必要があります。それ以外の場合は、単純に実行するのにかかる時間を確認したい単純なものにこの手法を使用します。
Japex は、ベンチマークをすばやく作成する方法として、またはソースコードを通じてJavaでベンチマークの問題を調査する方法として)役立つ場合があります。