Frage

Wie schreibt man (und Lauf) ein korrektes Mikro-Benchmark in Java?

Ich bin auf der Suche für einige Codebeispiele und Kommentare verschiedene Dinge darstellen, um darüber nachzudenken.

Beispiel: Sollte die Benchmark misst die Zeit / Iteration oder Iterationen / Zeit, und warum

Siehe auch: Ist Stoppuhr benchmarking akzeptabel

?
War es hilfreich?

Lösung

Tipps über Mikro-Benchmarks schreiben von den Machern von Java HotSpot :

Regel 0: Lesen Sie einen seriösen Papier auf JVMs und Mikro-Benchmarking. Ein guter ist Brian Goetz, 2005 . Sie nicht zu viel erwarten von Mikro-Benchmarks; sie messen nur eine begrenzte Anzahl von JVM Leistungsmerkmale.

Regel 1: immer eine Aufwärmphase enthalten, die Ihr Testkernel durch die ganzen Weg läuft, genug, um alle Initialisierungen und Compilations zu triggern, bevor die Taktphase (n). (Weniger Iterationen ist OK auf der Warm-up-Phase. Als Faustregel mehrere ist Zehntausende von inneren Schleifendurchläufe).

Regel 2:. läuft immer mit -XX:+PrintCompilation, -verbose:gc etc., so dass Sie, dass der Compiler und andere Teile der JVM überprüfen können nicht unerwartet Arbeit während der Taktphase tun

Regel. 2.1: Print-Nachrichten am Anfang und Ende des Timings und Warm-up-Phasen, so können Sie sicherstellen, dass es keine Ausgabe von Regel 2 während der Taktphase

Regel 3: Achten Sie auf den Unterschied zwischen -client und -server und OSR und regelmäßigen Compilations. Die -XX:+PrintCompilation Flagge berichtet OSR Compilations mit einem at-Zeichen, welches den Nicht-Anfangseintrittspunkt zu bezeichnen, zum Beispiel: Trouble$1::run @ 2 (41 bytes). Bevorzuge Server zum Client, und regelmäßig zu OSR, wenn Sie nach dem besten Leistung sind.

Regel 4: Seien Sie die Initialisierung Effekte bewusst. Nicht zum ersten Mal während der Taktphase drucken, da das Drucken lädt und initialisiert Klassen. Keine neuen Klassen laden außerhalb der Warm-up-Phase (oder Abschlussbericht Phase), es sei denn Sie das Laden von Klassen testen speziell (und in diesem Fall Last nur die Testklassen). Regel 2 ist Ihre erste Verteidigungslinie gegen solche Effekte.

Regel 5: Beachten Sie Deoptimierung und Neuübersetzung Effekte. Nehmen Sie keinen Codepfad zum ersten Mal in der Taktphase, da der Compiler den Code Junk und neu kompiliert werden kann, basierend auf einer früheren optimistische Annahme, dass der Pfad nicht verwendet werden würde. Regel 2 ist Ihre erste Verteidigungslinie gegen solche Effekte.

Regel 6: geeignete Werkzeuge Verwenden Sie die Compiler Gedanken zu lesen, und erwarten, dass durch den Code überrascht werden sie produziert. Überprüfen Sie den Code selbst vor dem Bilden Theorien über das, was etwas schneller oder langsamer.

Regel 7: reduziert Lärm in Ihren Messungen. Führen Sie Ihre Benchmark in einer ruhigen Maschine, und führen Sie es mehrmals, Ausreißer zu verwerfen. Verwenden Sie -Xbatch den Compiler mit der Anwendung zu serialisiert und betrachten -XX:CICompilerCount=1 Einstellung der Compiler um zu verhindern, mit sich selbst parallel laufen. Versuchen Sie Ihr Bestes GC Overhead zu reduzieren, setzen Xmx (groß genug) gleich Xms und verwenden UseEpsilonGC wenn es verfügbar ist.

Regel 8: eine Bibliothek für Ihre Benchmark verwenden, da es wahrscheinlich effizienter und wurde bereits für diesen einen Zweck ausgetestet. Wie JMH , Caliper oder Bill und Paul Excellent UCSD Benchmarks für Java .

Andere Tipps

Ich weiß, diese Frage markiert wurde als beantwortet, aber ich wollte zwei Bibliotheken erwähnen, die uns helfen, Mikro-Benchmarks zu schreiben

Caliper von Google

Erste Schritte Tutorials

  1. http://codingjunkie.net/micro-benchmarking-with-caliper/
  2. http://vertexlabs.co.uk/blog/caliper

JMH von OpenJDK

Erste Schritte Tutorials

  1. Vermeidung Benchmarking Pitfalls auf der JVM
  2. http://nitschinger.at/Using-JMH-for-Java-Microbenchmarking
  3. http://java-performance.info/jmh/

Wichtige Dinge für Java-Benchmarks sind:

  • die JIT erster mehrmals, indem Sie den Code-Warm up , bevor eine Zeit es
  • Stellen Sie sicher, dass Sie es für lange laufen genug, um die Ergebnisse in Sekunden oder (besser) zehn Sekunden
  • messen
  • Sie können zwar nicht System.gc() zwischen Iterationen nennen können, dann ist es eine gute Idee, es zwischen den Tests zu laufen, so dass jeder Test hoffentlich einen „sauberen“ Speicherplatz erhalten wird, mit zu arbeiten. (Ja, das ist gc() eher ein Hinweis als eine Garantie, aber es ist sehr wahrscheinlich , dass es wirklich wird Müll in meiner Erfahrung zu sammeln.)
  • Ich mag Iterationen und Zeit, und eine Punktzahl von Zeit / Iteration anzuzeigen, die so skaliert werden können, dass der „beste“ Algorithmus einen Wert von 1,0 und anderen bekommt in einer relativen Art und Weise erzielt. Das bedeutet, Sie ausführen können, alle Algorithmen für eine längere Zeit, die beide Anzahl der Iterationen und zeitlich veränderliche, aber immer noch vergleichbare Ergebnisse zu erzielen.

Ich bin gerade dabei, über die Gestaltung eines Benchmarking-Rahmen in .NET des Bloggens. Ich habe eine Paar von früher Beiträge die in der Lage sein, Ihnen einige Ideen zu geben - nicht alles sinnvoll sein wird, natürlich, aber einige können es sein,

.

jmh ist eine neue Ergänzung OpenJDK und wurde geschrieben von einige Performance-Ingenieure von Oracle. Sicherlich einen Blick wert.

  

Die jmh ist ein Java-Gurtzeug für Gebäude, Laufen und Analyse von Nano / Mikro / Makro Benchmarks geschrieben in Java und anderen Sprachen die JVM Targeting.

Sehr interessante Informationen begraben in der Probe Tests Kommentare .

Siehe auch:

  

Sollte die Benchmark misst die Zeit / Iteration oder Iterationen / Zeit, und warum?

Es hängt von was Sie testen wollen.

Wenn Sie interessieren sich für Latenz , Zeit / Iteration verwenden und wenn Sie Interesse an Durchsatz , verwenden Iterationen / Zeit.

Stellen Sie sicher, dass Sie irgendwie Ergebnisse verwenden, die in gebenchmarkt Code berechnet werden. Andernfalls wird Ihr Code wegoptimiert werden kann.

Wenn Sie versuchen, zwei Algorithmen zu vergleichen, tut mindestens zwei Benchmarks für jeden, abwechselnd die Reihenfolge. das heißt:.

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

Ich habe einige deutliche Unterschiede (5-10% manchmal) gefunden in der Laufzeit des gleichen Algorithmus in verschiedenen Durchgängen ..

Also, stellen Sie sicher, dass n ist sehr groß, so dass die Laufzeit jeder Schleife an den sehr mindestens 10 Sekunden oder so. Je mehr Iterationen, die höherwertigen Zahlen in Ihrer Benchmark Zeit und desto zuverlässigen, dass Daten vorhanden sind.

Es gibt viele mögliche Gefahren für das Schreiben von Mikro-Benchmarks in Java.

Erstens: Sie haben mit allen Arten von Veranstaltungen zu berechnen, die Zeit mehr nehmen oder weniger zufällig: Die Garbage-Collection, Caching-Effekte (von OS für Dateien und der CPU für Speicher), IO etc

.

Zweitens:. Sie können nicht die Genauigkeit der gemessenen Zeiten für sehr kurze Intervalle vertrauen

Drittens: Die JVM optimiert Ihren Code während der Ausführung. So unterschiedliche Läufe in der gleichen JVM-Instanz werden schneller und schneller.

Meine Empfehlungen: Machen Sie Ihre Benchmark einige Sekunden laufen, das ist zuverlässiger als eine Laufzeit über Millisekunden. Warm laufen die JVM (Mittel läuft die Benchmark mindestens einmal ohne Messung, dass die JVM Optimierungen führen kann). Und führen Sie Ihre Benchmark mehrere Male (vielleicht 5 mal) und nehmen den Median-Wert. Führen Sie all Mikro-Benchmark in einer neuen JVM-Instanz (Aufruf für jeden Benchmark neues Java) sonst Optimierung Auswirkungen der JVM können später Ausführen von Tests beeinflussen. Sie nicht ausführen Dinge, die nicht in der Warm-up-Phase ausgeführt werden (wie dies könnte klassen Last und Neuübersetzung auslösen).

Es sollte auch beachtet werden, dass es auch wichtig sein könnte, die Ergebnisse der Mikro-Benchmark zu analysieren, wenn verschiedene Implementierungen zu vergleichen. Daher sollte ein Signifikanztest gemacht werden.

Das ist, weil die Umsetzung A während der meisten der Läufe der Benchmark als Implementierung B schneller sein könnte. Aber A könnte auch eine höhere Verbreitung hat, so dass der gemessene Performance-Vorteil von A wird nicht von Bedeutung sein, wenn im Vergleich zu B.

So ist es auch wichtig, ein Mikro-Benchmark richtig zu schreiben und laufen, sondern auch richtig zu analysieren.

http://opt.sourceforge.net/ Java Micro Benchmark - Steuerungsaufgaben erforderlich, um den Vergleich zu bestimmen Leistungsmerkmale des Computersystems auf verschiedenen Plattformen. Kann verwendet werden, Optimierungsentscheidungen zu führen und verschiedene Java-Implementierungen zu vergleichen.

auf die andere ausgezeichnete Beratung hinzuzufügen, ich auch unter Hinweis auf die folgenden sein würde:

Bei einigen CPUs (z.B. Intel Core i5 Bereich mit Turboboost), die Temperatur (und die Anzahl der Kerne zur Zeit verwendet wird, sowie thier utilization percent) wirkt sich auf die Taktgeschwindigkeit. Da CPUs dynamisch getaktet werden, kann dies Ihre Ergebnisse beeinflussen. Zum Beispiel, wenn Sie eine Single-Threaded-Anwendung haben, ist die maximale Taktrate (mit Turbo Boost) höher als bei einer Anwendung alle Kerne verwenden. Dies kann daher mit Vergleich von Ein- und Mehrgewinden Leistung auf einigen Systemen stören. Beachten Sie, dass die Temperatur und volatages auch beeinflussen, wie lange Turbo Frequenz beibehalten wird.

Vielleicht ein grundsätzlicher wichtiger Aspekt, dass Sie die direkte Kontrolle über haben: Stellen Sie sicher, dass Sie das Richtige sind Messen! Zum Beispiel, wenn Sie System.nanoTime() Benchmark ein bestimmtes Stück Code verwenden, setzen Sie die Anrufe auf die Zuweisung an Orten, die Sinn machen Messung Dinge zu vermeiden, die Sie in beispielsweise nicht daran interessiert sind, nicht tun.

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

Das Problem ist, Sie nicht sofort die Endzeit bekommen, wenn der Code abgeschlossen ist. Stattdessen versuchen Sie wie folgt vor:

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top