Zoeken…


Invoering

Prestatiebenchmarks schrijven in Java is niet zo eenvoudig als System.currentTimeMillis() in het begin en aan het einde krijgen en het verschil berekenen. Om geldige prestatiebenchmarks te schrijven, moet men de juiste hulpmiddelen gebruiken.

Eenvoudig JMH-voorbeeld

Een van de hulpmiddelen voor het schrijven van goede benchmarktests is JMH . Laten we zeggen dat we de prestaties van het zoeken naar een element in HashSet willen vergelijken met TreeSet .

De eenvoudigste manier om JHM in uw project te krijgen - is door maven en schaduw plug-ins te gebruiken. Je kunt ook pom.xml uit JHM-voorbeelden .

<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>

Hierna moet u benchmarkklasse zelf schrijven:

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));
    }
}

Houd dit blackhole.consume() in gedachten, we komen er later op terug. We hebben ook de hoofdklasse nodig voor het uitvoeren van 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();
    }
}

En we zijn er helemaal klaar voor. We moeten alleen het mvn package (het maakt benchmarks.jar in uw /target ) en onze benchmark-test uitvoeren:

java -cp target/benchmarks.jar benchmark.BenchmarkMain

En na wat opwarm- en berekeningsiteraties, zullen we onze resultaten hebben:

# 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

Over dat blackhole.consume() . Als uw berekeningen de status van uw toepassing niet veranderen, zal Java deze waarschijnlijk gewoon negeren. Dus om dit te voorkomen, kunt u uw benchmarkmethoden een waarde laten retourneren of het Blackhole object gebruiken om het te consumeren.

Meer informatie over het schrijven van juiste benchmarks vindt u in de blog van Aleksey Shipilëv , in de blog van Jacob Jenkov en in de blog over Java-prestaties: 1 , 2 .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow