Gradle
plugins {
...
id "me.champeau.gradle.jmh" version "0.5.3"
...
}
gradle jmh
@State Anotasyonu
Scope.Benchmark
Açıklaması
şöyle. Tek bir nesneyi multi-threaded olarak test etmek içindir
By using benchmark scope, all of the threads used on the benchmark scope will share the same object.
@OutputTimeUnit Anotasyonu
We would like our results to be reported in microseconds, therefore we shall use @OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode Anotasyonu
On JMH, we have various benchmark modes depending on what we want to measure.
Throughput is when we want to measure the number of operations per unit of time.
AverageTime is when we want to measure the average time per operation.
SampleTime is when we want to sample the time for each operation including min, max time, and more than just the average.
SingleShotTime is when we want to measure the time for a single operation. This can help when we want to identify how the operation will do on a cold start.
All We also have the option to measure all of the above with @BenchmarkMode(Mode.All)
@Threads Anotasyonu
Kaç thread ile koşacağını belirtir
@Warmup Anotasyonu
Kaç defa ısınma yapılacağını belirtir
@Fork Anotasyonu
Benchmark testin kaç defa yapılacağını belirtir
@Measurement
Kaç yineleme yapılacağını belirtir. Çıktıda count sütununda gösterilir.
Kullanım
Örnek
Şöyle yaparız. Test sonucu nano saniyedir ve ortalaması alınır. Multi-threaded test yapar. Test 2 defa fork edilir ve her birisi 2 yineleme yapar.
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@State(Scope.Benchmark)
@Fork(value = 2)
@Measurement(iterations = 2)
@Warmup(iterations = 1)
public class MyBenchmark {
@Benchmark
public long foo() {
...
}
@Benchmark
public long bar() {
...
}
}
Örnek
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.profile.GCProfiler;
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;
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.All)
public class RateLimiterBenchmark {
private static final int FORK_COUNT = 2;
private static final int WARMUP_COUNT = 10;
private static final int ITERATION_COUNT = 10;
private static final int THREAD_COUNT = 2;
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder().addProfiler(GCProfiler.class).build();
new Runner(options).run();
}
@Setup
public void setUp() {
...
}
@Benchmark
@Threads(value = THREAD_COUNT)
@Warmup(iterations = WARMUP_COUNT)
@Fork(value = FORK_COUNT)
@Measurement(iterations = ITERATION_COUNT)
public String refillPermission() {
...
}
}
Çıktı
şöyle. Score sütunu değeri daha düşük olan daha hızlıdır
Benchmark Mode Cnt Score Error Units
RateLimiterBenchmark.refillPermission thrpt 20 13.594 ± 0.217 ops/us
RateLimiterBenchmark.refillPermission avgt 20 0.147 ± 0.002 us/op
RateLimiterBenchmark.refillPermission sample 10754462 0.711 ± 0.025 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.00 sample ≈ 0 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.50 sample 0.084 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.90 sample 0.125 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.95 sample 0.125 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.99 sample 0.209 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.999 sample 139.008 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p0.9999 sample 935.936 us/op
RateLimiterBenchmark.refillPermission:refillPermission·p1.00 sample 20709.376 us/op
RateLimiterBenchmark.refillPermission
Cnt ile kaç yineleme yapıldığı belirtilir.
@Measurement ile count yani iteration/yineleme değeri belirtilir. Açıklaması
şöyle
Count is the number of iterations. Apart from throughput where we measure the operations by time, the rest is the time per operation. Throughput, Average, and Single shot are straightforward. Sample lists the percentiles. Error is the margin of error.
Örnek
Şöyle
yaparız. Burada @Warmup ile @Setup ile işaretli kod çalıştırılıyor
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 20, time = 1)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@OperationsPerInvocation
public class MapBenchmark {
private static final int SIZE = 10;
private Map<Integer, String> mapOf;
private Map<Integer, String> hashMap;
@Setup
public void setup() {
mapOf = Map.of(
0, "value0",
1, "value1",
2, "value2",
3, "value3",
4, "value4",
5, "value5",
6, "value6",
7, "value7",
8, "value8",
9, "value9"
);
hashMap = new HashMap<>();
hashMap.put(0, "value0");
hashMap.put(1, "value1");
hashMap.put(2, "value2");
hashMap.put(3, "value3");
hashMap.put(4, "value4");
hashMap.put(5, "value5");
hashMap.put(6, "value6");
hashMap.put(7, "value7");
hashMap.put(8, "value8");
hashMap.put(9, "value9");
}
@Benchmark
public void testMapOf(Blackhole blackhole) {
Map<Integer, String> map = Map.of(
0, "value0",
1, "value1",
2, "value2",
3, "value3",
4, "value4",
5, "value5",
6, "value6",
7, "value7",
8, "value8",
9, "value9"
);
blackhole.consume(map);
}
@Benchmark
public void testHashMap(Blackhole blackhole) {
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(0, "value0");
hashMap.put(1, "value1");
hashMap.put(2, "value2");
hashMap.put(3, "value3");
hashMap.put(4, "value4");
hashMap.put(5, "value5");
hashMap.put(6, "value6");
hashMap.put(7, "value7");
hashMap.put(8, "value8");
hashMap.put(9, "value9");
blackhole.consume(hashMap);
}
@Benchmark
public void testGetMapOf() {
for (int i = 0; i < 10; i++) {
mapOf.get(i);
}
}
@Benchmark
public void testGetHashMap() {
for (int i = 0; i < SIZE; i++) {
hashMap.get(i);
}
}
}
Çıktı
şöyle. Score sütunu değeri daha düşük olan daha hızlıdır
Benchmark Mode Cnt Score Error Units
MapBenchmark.testGetHashMap avgt 20 14.999 ± 0.433 ns/op
MapBenchmark.testGetMapOf avgt 20 16.327 ± 0.119 ns/op
MapBenchmark.testHashMap avgt 20 84.920 ± 1.737 ns/op
MapBenchmark.testMapOf avgt 20 83.290 ± 0.471 ns/op