970 Stimmen

Wie schreibe ich einen korrekten Mikro-Benchmark in Java?

Wie schreibt man einen korrekten Mikro-Benchmark in Java (und führt ihn aus)?

Ich bin auf der Suche nach einigen Codebeispielen und Kommentaren, die verschiedene Dinge veranschaulichen, über die man nachdenken sollte.

Beispiel: Sollte der Benchmark Zeit/Iteration oder Iterationen/Zeit messen und warum?

Verwandt: Ist das Benchmarking mit Stoppuhr akzeptabel?

0 Stimmen

Siehe [diese Frage][1] von vor ein paar Minuten für einige verwandte Informationen. edit: Entschuldigung, dies sollte keine Antwort sein. Ich hätte es als Kommentar posten sollen. [1]: stackoverflow.com/questions/503877/

0 Stimmen

Nachdem ich vorhatte, den Fragesteller auf eine Frage wie diese zu verweisen, stellte ich fest, dass es diese Frage nicht gab. Hier ist sie also, und hoffentlich werden im Laufe der Zeit einige gute Tipps gesammelt.

6 Stimmen

Java 9 könnte einige Funktionen für Micro-Benchmarking bieten: openjdk.java.net/jeps/230

865voto

Tipps zum Schreiben von Mikro-Benchmarks von den Schöpfern von Java HotSpot :

Regel 0: Lesen Sie einen seriösen Artikel über JVMs und Micro-Benchmarking. Ein guter Artikel ist Brian Goetz, 2005 . Erwarten Sie nicht zu viel von Micro-Benchmarks; sie messen nur einen begrenzten Bereich der JVM-Leistungsmerkmale.

Regel 1: Fügen Sie immer eine Aufwärmphase ein, in der Ihr Testkernel vollständig durchläuft, um alle Initialisierungen und Kompilierungen vor der/den Zeitmessphase(n) auszulösen. (Weniger Iterationen sind in der Aufwärmphase in Ordnung. Als Faustregel gelten mehrere zehntausend Iterationen der inneren Schleife.)

Regel 2: Laufen Sie immer mit -XX:+PrintCompilation , -verbose:gc usw., so dass Sie überprüfen können, ob der Compiler und andere Teile der JVM während der Timing-Phase nicht unerwartete Arbeiten durchführen.

Regel 2.1: Drucken Sie zu Beginn und am Ende der Zeitmessungs- und Aufwärmphase Meldungen aus, damit Sie überprüfen können, dass während der Zeitmessungsphase keine Ausgabe von Regel 2 erfolgt.

Regel 3: Achten Sie auf den Unterschied zwischen -client y -server sowie OSR und reguläre Kompilierungen. Die -XX:+PrintCompilation Flag meldet OSR-Kompilierungen mit einem at-Zeichen, um z.B. den nicht-initialen Einstiegspunkt zu kennzeichnen: Trouble$1::run @ 2 (41 bytes) . Bevorzugen Sie Server gegenüber Client und regulär gegenüber OSR, wenn Sie die beste Leistung wünschen.

Regel 4: Achten Sie auf die Auswirkungen der Initialisierung. Drucken Sie nicht zum ersten Mal während der Timing-Phase, da durch das Drucken Klassen geladen und initialisiert werden. Laden Sie keine neuen Klassen außerhalb der Aufwärmphase (oder der abschließenden Berichtsphase), es sei denn, Sie testen das Laden von Klassen speziell (und in diesem Fall laden Sie nur die Testklassen). Regel 2 ist Ihre erste Verteidigungslinie gegen solche Effekte.

Regel 5: Achten Sie auf die Auswirkungen von Deoptimierung und Neukompilierung. Nehmen Sie keinen Codepfad zum ersten Mal in der Timing-Phase, denn der Compiler könnte den Code auf der Grundlage einer früheren optimistischen Annahme, dass der Pfad überhaupt nicht verwendet werden würde, verwerfen und neu kompilieren. Regel 2 ist Ihre erste Verteidigungslinie gegen solche Effekte.

Regel 6: Verwenden Sie geeignete Werkzeuge, um die Gedanken des Compilers zu lesen, und lassen Sie sich von dem Code, den er produziert, überraschen. Überprüfen Sie den Code selbst, bevor Sie Theorien darüber aufstellen, was etwas schneller oder langsamer macht.

Regel 7: Reduzieren Sie das Rauschen bei Ihren Messungen. Führen Sie Ihren Benchmark auf einem leisen Rechner durch, und zwar mehrmals, wobei Sie Ausreißer aussortieren. Verwenden Sie -Xbatch um den Compiler mit der Anwendung zu serialisieren, und erwägen Sie die Einstellung -XX:CICompilerCount=1 um zu verhindern, dass der Compiler parallel zu sich selbst läuft. Versuchen Sie Ihr Bestes, um den GC-Overhead zu reduzieren, setzen Sie Xmx (groß genug) ist gleich Xms und verwenden UseEpsilonGC wenn sie verfügbar ist.

Regel 8: Verwenden Sie eine Bibliothek für Ihren Benchmark, da diese wahrscheinlich effizienter ist und bereits für diesen einzigen Zweck getestet wurde. Wie zum Beispiel JMH , Messschieber o Bill und Pauls hervorragende UCSD-Benchmarks für Java .

5 Stimmen

Auch dies war ein interessanter Artikel: ibm.com/developerworks/java/library/j-jtp12214

162 Stimmen

Verwenden Sie außerdem niemals System.currentTimeMillis(), es sei denn, Sie sind mit einer Genauigkeit von + oder - 15 ms einverstanden, was bei den meisten Kombinationen von Betriebssystem und JVM der Fall ist. Verwenden Sie stattdessen System.nanoTime().

5 Stimmen

261voto

Aravind Yarram Punkte 76365

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

Messschieber von Google

Tutorials für den Einstieg

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

JMH von OpenJDK

Tutorials für den Einstieg

  1. Vermeiden von Benchmarking-Fallen auf der JVM
  2. Verwendung von JMH für Java Microbenchmarking
  3. Einführung in JMH

42 Stimmen

+1 Sie hätte als Regel 8 der angenommenen Antwort hinzugefügt werden können: Regel 8: Weil so viele Dinge schief gehen können, sollten Sie lieber eine vorhandene Bibliothek verwenden, als zu versuchen, es selbst zu tun!

9 Stimmen

@Pangea jmh ist dem Caliper heutzutage wahrscheinlich überlegen, siehe auch: groups.google.com/forum/#!msg/mechanische-sympathie/m4opvy4xq3U/

97voto

Jon Skeet Punkte 1325502

Wichtige Dinge für Java-Benchmarks sind:

  • Wärmen Sie das JIT zunächst auf, indem Sie den Code mehrere Male ausführen vor der Zeitmessung es
  • Stellen Sie sicher, dass Sie den Test lange genug laufen lassen, um die Ergebnisse in Sekunden oder (besser) Zehntelsekunden messen zu können.
  • Sie können zwar nicht anrufen System.gc() zwischen den Iterationen auszuführen, ist es eine gute Idee, es zwischen den Tests laufen zu lassen, so dass jeder Test hoffentlich einen "sauberen" Speicherplatz zum Arbeiten bekommt. (Ja, gc() ist eher ein Hinweis als eine Garantie, aber es ist sehr wahrscheinlich dass er meiner Erfahrung nach wirklich Müll sammelt.)
  • Ich möchte die Iterationen und die Zeit sowie eine Bewertung von Zeit/Iteration anzeigen, die so skaliert werden kann, dass der "beste" Algorithmus eine Bewertung von 1,0 erhält und andere relativ bewertet werden. Dies bedeutet, dass Sie Folgendes ausführen können tous Algorithmen über einen längeren Zeitraum, wobei sowohl die Anzahl der Iterationen als auch die Zeit variiert wurden, aber dennoch vergleichbare Ergebnisse erzielt wurden.

Ich bin gerade dabei, einen Blog über den Entwurf eines Benchmarking-Frameworks in .NET zu schreiben. Ich habe eine Paar de frühere Stellen die Ihnen vielleicht ein paar Anregungen geben können - natürlich ist nicht alles geeignet, aber manches schon.

3 Stimmen

Kleines Manko: IMO sollte aus "so that each test gets" "so that each test might get" werden, da ersteres den Eindruck erweckt, dass der Aufruf gc immer gibt ungenutzten Speicher frei.

1 Stimmen

@SanjayT.Sharma: Nun, die Absicht ist, dass sie es tatsächlich tut. Es ist zwar nicht unbedingt garantiert, aber ein ziemlich deutlicher Hinweis. Wird bearbeitet, um klarer zu sein.

1 Stimmen

Ich bin nicht einverstanden mit dem Aufruf von System.gc(). Es ist ein Hinweis, das ist alles. Nicht einmal "es wird hoffentlich etwas tun". Sie sollten es niemals aufrufen. Das ist Programmierung, nicht Kunst.

50voto

assylias Punkte 308529

jmh ist eine neue Ergänzung zu OpenJDK und wurde von einigen Leistungsingenieuren von Oracle geschrieben. Sicherlich einen Blick wert.

Das jmh ist ein Java-Harness zum Erstellen, Ausführen und Analysieren von Nano-/Mikro-/Makro-Benchmarks, die in Java und anderen Sprachen für die JVM geschrieben wurden.

Sehr interessante Informationen vergraben in Kommentare zu den Stichprobentests .

Siehe auch:

1 Stimmen

Siehe auch diesen Blogbeitrag: psy-lob-saw.blogspot.com/2013/04/ für Einzelheiten zum Einstieg in JMH.

1 Stimmen

ZU IHRER INFORMATION, JEP 230: Mikrobenchmark-Suite ist ein OpenJDK Vorschlag auf der Grundlage dieses Java Microbenchmark Harness (JMH) Projekt. Wurde nicht für Java 9 ausgewählt kann aber später hinzugefügt werden.

23voto

Peter Lawrey Punkte 511323

Sollte der Benchmark Zeit/Iteration oder Iterationen/Zeit messen und warum?

Es hängt ab von was die Sie zu testen versuchen.

Wenn Sie interessiert sind an Latenzzeit verwenden Sie Zeit/Iteration, und wenn Sie Interesse an Durchsatz Iterationen/Zeit verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X