Java Language
Puntos de referencia
Buscar..
Introducción
Escribir puntos de referencia de rendimiento en java no es tan simple como obtener System.currentTimeMillis()
al principio y al final y calcular la diferencia. Para escribir puntos de referencia de rendimiento válidos, se deben usar las herramientas adecuadas.
Ejemplo simple de JMH
Una de las herramientas para escribir pruebas de referencia adecuadas es JMH . Digamos que queremos comparar el rendimiento de la búsqueda de un elemento en HashSet
vs TreeSet
.
La manera más fácil de conseguir JHM en su proyecto - es el uso de Maven y sombra plugin. También puedes ver pom.xml
de los ejemplos de JHM .
<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>
Después de esto necesitas escribir la clase de referencia en sí:
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));
}
}
Por favor, tenga en cuenta este blackhole.consume()
, volveremos más adelante. También necesitamos la clase principal para ejecutar 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();
}
}
Y estamos todos listos. Solo necesitamos ejecutar el mvn package
(creará benchmarks.jar
en su carpeta /target
) y ejecutamos nuestra prueba de referencia:
java -cp target/benchmarks.jar benchmark.BenchmarkMain
Y después de algunas iteraciones de calentamiento y cálculo, tendremos nuestros resultados:
# 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
Sobre eso blackhole.consume()
. Si sus cálculos no cambian el estado de su aplicación, Java probablemente lo ignorará. Por lo tanto, para evitarlo, puede hacer que sus métodos de referencia devuelvan algo de valor o utilizar el objeto Blackhole
para consumirlo.
Puede encontrar más información sobre cómo escribir puntos de referencia adecuados en el blog de Aleksey Shipilëv , en el blog de Jacob Jenkov y en el blog de java-performance: 1 , 2 .