Ich schrieb einen JMH-Benchmark mit 2 Methoden: M1 und M2. M1 ruft M2 auf, aber aus irgendeinem Grund behauptet JMH, dass M1 schneller ist als M2.jmh zeigt an, dass M1 schneller ist als M2, aber M1 delegiert an M2
Hier ist der Benchmark-Quelle-Code:
import java.util.concurrent.TimeUnit;
import static org.bitbucket.cowwoc.requirements.Requirements.assertThat;
import static org.bitbucket.cowwoc.requirements.Requirements.requireThat;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {
@Benchmark
public void assertMethod() {
assertThat("value", "name").isNotNull().isNotEmpty();
}
@Benchmark
public void requireMethod() {
requireThat("value", "name").isNotNull().isNotEmpty();
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
}
In dem obigen Beispiel M1 assertThat()
ist, M2 ist requireThat()
. Bedeutung, assertThat()
ruft requireThat()
unter der Haube auf. Hier
ist der Maßstab Ausgabe:
# JMH 1.13 (released 8 days ago)
# VM version: JDK 1.8.0_102, VM 25.102-b14
# VM invoker: C:\Program Files\Java\jdk1.8.0_102\jre\bin\java.exe
# VM options: -ea
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mycompany.jmh.MyBenchmark.assertMethod
# Run progress: 0.00% complete, ETA 00:01:20
# Fork: 1 of 1
# Warmup Iteration 1: 8.268 ns/op
# Warmup Iteration 2: 6.082 ns/op
# Warmup Iteration 3: 4.846 ns/op
# Warmup Iteration 4: 4.854 ns/op
# Warmup Iteration 5: 4.834 ns/op
# Warmup Iteration 6: 4.831 ns/op
# Warmup Iteration 7: 4.815 ns/op
# Warmup Iteration 8: 4.839 ns/op
# Warmup Iteration 9: 4.825 ns/op
# Warmup Iteration 10: 4.812 ns/op
# Warmup Iteration 11: 4.806 ns/op
# Warmup Iteration 12: 4.805 ns/op
# Warmup Iteration 13: 4.802 ns/op
# Warmup Iteration 14: 4.813 ns/op
# Warmup Iteration 15: 4.805 ns/op
# Warmup Iteration 16: 4.818 ns/op
# Warmup Iteration 17: 4.815 ns/op
# Warmup Iteration 18: 4.817 ns/op
# Warmup Iteration 19: 4.812 ns/op
# Warmup Iteration 20: 4.810 ns/op
Iteration 1: 4.805 ns/op
Iteration 2: 4.816 ns/op
Iteration 3: 4.813 ns/op
Iteration 4: 4.938 ns/op
Iteration 5: 5.061 ns/op
Iteration 6: 5.129 ns/op
Iteration 7: 4.828 ns/op
Iteration 8: 4.837 ns/op
Iteration 9: 4.819 ns/op
Iteration 10: 4.815 ns/op
Iteration 11: 4.872 ns/op
Iteration 12: 4.806 ns/op
Iteration 13: 4.811 ns/op
Iteration 14: 4.827 ns/op
Iteration 15: 4.837 ns/op
Iteration 16: 4.842 ns/op
Iteration 17: 4.812 ns/op
Iteration 18: 4.809 ns/op
Iteration 19: 4.806 ns/op
Iteration 20: 4.815 ns/op
Result "assertMethod":
4.855 �(99.9%) 0.077 ns/op [Average]
(min, avg, max) = (4.805, 4.855, 5.129), stdev = 0.088
CI (99.9%): [4.778, 4.932] (assumes normal distribution)
# JMH 1.13 (released 8 days ago)
# VM version: JDK 1.8.0_102, VM 25.102-b14
# VM invoker: C:\Program Files\Java\jdk1.8.0_102\jre\bin\java.exe
# VM options: -ea
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mycompany.jmh.MyBenchmark.requireMethod
# Run progress: 50.00% complete, ETA 00:00:40
# Fork: 1 of 1
# Warmup Iteration 1: 7.193 ns/op
# Warmup Iteration 2: 4.835 ns/op
# Warmup Iteration 3: 5.039 ns/op
# Warmup Iteration 4: 5.053 ns/op
# Warmup Iteration 5: 5.077 ns/op
# Warmup Iteration 6: 5.102 ns/op
# Warmup Iteration 7: 5.088 ns/op
# Warmup Iteration 8: 5.109 ns/op
# Warmup Iteration 9: 5.096 ns/op
# Warmup Iteration 10: 5.096 ns/op
# Warmup Iteration 11: 5.091 ns/op
# Warmup Iteration 12: 5.089 ns/op
# Warmup Iteration 13: 5.099 ns/op
# Warmup Iteration 14: 5.097 ns/op
# Warmup Iteration 15: 5.090 ns/op
# Warmup Iteration 16: 5.096 ns/op
# Warmup Iteration 17: 5.088 ns/op
# Warmup Iteration 18: 5.086 ns/op
# Warmup Iteration 19: 5.087 ns/op
# Warmup Iteration 20: 5.097 ns/op
Iteration 1: 5.097 ns/op
Iteration 2: 5.088 ns/op
Iteration 3: 5.092 ns/op
Iteration 4: 5.097 ns/op
Iteration 5: 5.082 ns/op
Iteration 6: 5.089 ns/op
Iteration 7: 5.086 ns/op
Iteration 8: 5.084 ns/op
Iteration 9: 5.090 ns/op
Iteration 10: 5.086 ns/op
Iteration 11: 5.084 ns/op
Iteration 12: 5.088 ns/op
Iteration 13: 5.091 ns/op
Iteration 14: 5.092 ns/op
Iteration 15: 5.085 ns/op
Iteration 16: 5.096 ns/op
Iteration 17: 5.078 ns/op
Iteration 18: 5.125 ns/op
Iteration 19: 5.089 ns/op
Iteration 20: 5.091 ns/op
Result "requireMethod":
5.091 �(99.9%) 0.008 ns/op [Average]
(min, avg, max) = (5.078, 5.091, 5.125), stdev = 0.010
CI (99.9%): [5.082, 5.099] (assumes normal distribution)
# Run complete. Total time: 00:01:21
Benchmark Mode Cnt Score Error Units
MyBenchmark.assertMethod avgt 20 4.855 � 0.077 ns/op
MyBenchmark.requireMethod avgt 20 5.091 � 0.008 ns/op
diese lokal zu reproduzieren:
- erstellen Maven Projekt des über den Benchmark enthält.
die folgende Abhängigkeit hinzufügen:
<dependency> <groupId>org.bitbucket.cowwoc</groupId> <artifactId>requirements</artifactId> <version>2.0.0</version> </dependency>
- Alternativ laden Sie die Bibliothek von https://bitbucket.org/cowwoc/requirements/
ich folgende Fragen:
- Können Sie dieses Ergebnis auf Ihrem Ende reproduzieren?
- Was ist mit dem Benchmark falsch?
UPDATE: Ich stellte einen aktualisierte Benchmark-Source-Code, Benchmark-Ausgang, jmh-Testausgang und xperfasm Ausgang https://bitbucket.org/cowwoc/requirements/downloads pro Aleksey Shipilev ‚s Vorschlag. Ich kann diese nicht an Stackoverflow senden, da die Anzahl der Fragen auf 30.000 Zeichen begrenzt ist.
UPDATE2: Ich bekomme endlich konsistente, aussagekräftige Ergebnisse.
Benchmark Mode Cnt Score Error Units
MyBenchmark.assertMethod avgt 60 22.552 ± 0.020 ns/op
MyBenchmark.requireMethod avgt 60 22.411 ± 0.114 ns/op
von consistent
, ich meine, dass ich fast die gleichen Werte für Läufe erhalten.
Durch meaningful
, ich meine, dass assertMethod()
langsamer ist als requireMethod()
.
ich folgende Änderungen vorgenommen:
- Gesperrt den CPU-Takt (min/max CPU Satz auf 99% in Energieoptionen von Windows)
- Added Optionen JVM
-XX:-TieredCompilation -XX:-ProfileInterpreter
Ist jemand in der Lage um diese Ergebnisse ohne die Verdoppelung der Laufzeiten zu erreichen?
UPDATE3: Das Deaktivieren von Inlining führt zu den gleichen Ergebnissen ohne merkliche Leistungsabschwächung. Ich habe eine ausführlichere Antwort here gepostet.
Dies mag nicht das Problem sein, aber Sie sollten Eingaben von '@ State'-Feldern erhalten und die Ausgaben an' @ Benchmark' return value oder an das explizite 'Blackhole' versenken. Siehe: https://gist.github.com/shipilev/712b5e4e4800c3ed982dcbae97e4d6df –
Ich kann den Unterschied in der ähnlichen Konfiguration sowieso nicht reproduzieren, was einige Zweifel an der Gültigkeit der Umgebungseinstellungen aufkommen lässt. Versuchen Sie JMH Core Benchmark Tests durchzuführen? Runnable JAR: http://central.maven.org/maven2/org/openjdk/jmh/jmh-core-benchmarks/1.13/jmh-core-benchmarks--1.13-full.jar –
@AlekseyShipilev Guter Fang über das Nicht-Finale Eingänge und Sinken der Ausgabe. Ich bekomme jetzt realistischere Zahlen (siehe ** UPDATE2 **), aber 'assertMethod()' ist immer noch schneller als 'requireMethod()'. Ich habe auch die JMH Core Benchmarktests durchgeführt, wie Sie erwähnt haben, und sie scheinen wieder normal zu sein.Ich kann das Ergebnis nicht auf Stackoverflow aufgrund der 30k Zeichen Grenze veröffentlichen, aber wenn Sie mir eine E-Mail senden (siehe mein Profil, um meine E-Mail-Adresse zu erhalten), schicke ich Ihnen die Datei. – Gili