Dieser JMH-Benchmark ist auf allen Maschinen inkonsistent - warum?

8

Ich versuche, eine Methode wie folgt zu schreiben:

%Vor%

Und ich versuche die effizienteste Implementierung zu finden. Ich habe mich auf einen festgelegt, aber dann hat ein Mitarbeiter die Benchmarks durchgeführt und unterschiedliche relative Ergebnisse erzielt. Die schnellste Implementierung ist für mich nicht die schnellste.

Stimmt etwas nicht mit diesen Benchmarks?

%Vor%

Es gibt kleine Unterschiede in unseren Umgebungen.

Ich: Windows 10, JDK 1.8.0_45, "Nullen" ist die schnellste

Er: Windows 7, JDK 1.8.0_20, "Cast" ist der schnellste

Unsere Ergebnisse sind von Durchlauf zu Durchlauf konsistent, egal ob sie in einer IDE oder von der Befehlszeile aus ausgeführt werden. Wir verwenden JMH 1.10.5.

Was passiert hier? Der Benchmark scheint nicht vertrauenswürdig zu sein und ich weiß nicht, wie ich das beheben kann.

    
Michael Hixson 05.09.2015, 08:30
quelle

3 Antworten

6

Ich kann sogar auf derselben Maschine mit derselben Umgebung verschiedene Ergebnisse reproduzieren: manchmal ist cast etwas schneller, manchmal zeros ist.

%Vor%

Nach einigen Analysen habe ich festgestellt, dass das Problem nicht im Benchmark, sondern in JMH liegt. perfasm Profiler zeigte auf die Methode Blackhole.consume :

%Vor%

Der interessante Teil ist, wie bool1 und bool2 initialisiert werden:

%Vor%

Ja, sie sind jedes Mal zufällig! Wie Sie wissen, beruht der JIT-Compiler auf dem Ausführungsprofil für die Laufzeit, sodass der generierte Code abhängig von den Anfangswerten bool1 und bool2 leicht variiert, insbesondere in der Hälfte der Fälle, in denen die Verzweigung berücksichtigt wird halb - nicht genommen. Da kommt der Unterschied her.

Ich habe den Bericht gegen JMH mit dem vorgeschlagenen Fix eingereicht, falls die Autoren den Fehler bestätigen .

    
apangin 06.09.2015 03:25
quelle
2

CPU-Modelle entwickeln sich im Laufe der Zeit. Wenn sich die Balance der Betriebsleistung ändert oder es in der Verzweigungsvorhersage eine neuere Verbesserung gibt, dann haben Sie einen konsistenten Unterschied.

Wenn Sie diese eine Alternative verwerfen möchten, hat dies einen falschen Vorteil gegenüber einem bestimmten Datensatz (z. B. den nächsten Fall erraten zu können, wo es im wirklichen Leben nicht möglich ist), Sie könnten randomize / shuffle Ihren Datensatz und machen Sie es länger. Nur wenn Sie es versuchen möchten, obwohl es wahrscheinlich sinnlos (und zweifelhaft, wenn Sie genau die gleichen Daten ausführen müssen) sein kann.

%Vor%

P.D. # 1 Wenn Sie anstelle von synthetischen Daten auch Beispiele für echte Daten eingeben können, liefert dies möglicherweise aussagekräftigere Informationen. CPU-Raten zu viel in diesem Fall könnte tatsächlich gut sein.

    
Javier 05.09.2015 10:51
quelle
2

Wie JB Nizet bemerkt, können Sie nicht davon ausgehen, dass ein Programm dasselbe über mehrere JVMs und / oder Betriebssysteme hinweg ausführt, sogar noch mehr, wenn Sie verschiedene Maschinen haben.

Übrigens brauchen Sie nicht numberOfLeadingZeroes(a) :

%Vor%

Wenn Sie wirklich höchste Leistung benötigen, wählen Sie entweder eine zufällige Stichprobe von zu testenden Rechnern aus und wählen Sie diejenige aus, die am besten funktioniert (es sei denn, es gibt Maschinen mit wesentlich schlechterer Leistung, obwohl dies mit Ihrem Codebeispiel ziemlich unwahrscheinlich ist) ), oder füge alle Methoden hinzu und erstelle ein Kalibrierungsprogramm, das alle Versionen bencht und dasjenige auswählt, das am schnellsten für die Maschine ist, auf der es läuft.

Bearbeiten: Stellen Sie auch, wie Javier sagt, Benchmarks mit mehreren realen Workloads fest.

    
llogiq 05.09.2015 09:20
quelle

Tags und Links