Suche…


Einführung

Das Schreiben von Leistungsbenchmarks in Java ist nicht so einfach wie das System.currentTimeMillis() am Anfang und am Ende und Berechnen der Differenz. Um gültige Leistungsbenchmarks zu schreiben, sollte man geeignete Werkzeuge verwenden.

Einfaches JMH-Beispiel

Eines der Tools zum Schreiben richtiger Benchmark-Tests ist JMH . HashSet , wir möchten die Leistung eines HashSet in HashSet und TreeSet .

Der einfachste Weg, um JHM in Ihr Projekt zu integrieren - besteht darin, das Plug-in für Maven und Schatten zu verwenden . Sie können auch pom.xml aus JHM-Beispielen sehen .

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <finalName>/benchmarks</finalName>
                        <transformers>
                            <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>org.openjdk.jmh.Main</mainClass>
                            </transformer>
                        </transformers>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>1.18</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.18</version>
    </dependency>
</dependencies>

Danach müssen Sie die Benchmark-Klasse selbst schreiben:

package benchmark;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

@State(Scope.Thread)
public class CollectionFinderBenchmarkTest {
    private static final int SET_SIZE = 10000;

    private Set<String> hashSet;
    private Set<String> treeSet;

    private String stringToFind = "8888";

    @Setup
    public void setupCollections() {
        hashSet = new HashSet<>(SET_SIZE);
        treeSet = new TreeSet<>();

        for (int i = 0; i < SET_SIZE; i++) {
            final String value = String.valueOf(i);
            hashSet.add(value);
            treeSet.add(value);
        }

        stringToFind = String.valueOf(new Random().nextInt(SET_SIZE));
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public void testHashSet(Blackhole blackhole) {
        blackhole.consume(hashSet.contains(stringToFind));
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public void testTreeSet(Blackhole blackhole) {
        blackhole.consume(treeSet.contains(stringToFind));
    }
}

Bitte beachte dieses blackhole.consume() , wir werden später darauf zurückkommen. Wir brauchen auch die Hauptklasse für das Laufen von Benchmark:

package benchmark;

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;

public class BenchmarkMain {
    public static void main(String[] args) throws RunnerException {
        final Options options = new OptionsBuilder()
                .include(CollectionFinderBenchmarkTest.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(options).run();
    }
}

Und wir sind fertig. Wir müssen nur das mvn package ausführen (es erstellt benchmarks.jar in Ihrem /target Ordner) und führen unseren Benchmark-Test aus:

java -cp target/benchmarks.jar benchmark.BenchmarkMain

Und nach einigen Aufwärm- und Berechnungs-Iterationen haben wir unsere Ergebnisse:

# Run complete. Total time: 00:01:21

Benchmark                                  Mode  Cnt   Score    Error  Units
CollectionFinderBenchmarkTest.testHashSet  avgt   20   9.940 ±  0.270  ns/op
CollectionFinderBenchmarkTest.testTreeSet  avgt   20  98.858 ± 13.743  ns/op

Über dieses blackhole.consume() . Wenn Ihre Berechnungen den Status Ihrer Anwendung nicht ändern, wird Java ihn höchstwahrscheinlich einfach ignorieren. Um dies zu vermeiden, können Sie Ihre Benchmark-Methoden entweder dazu bringen, einen bestimmten Wert zurückzugeben, oder das Objekt mit dem Blackhole Objekt verbrauchen.

Weitere Informationen zum Schreiben der richtigen Benchmarks finden Sie im Blog von Aleksey Shipilëv, im Blog von Jacob Jenkov und im Java-Performance-Blog: 1 , 2 .



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow