JMH to doskonałe narzędzie do benchmarkowania fragmentów aplikacji oparty o JVM, dlatego, że mamy w nim możliwość “rozgrzania” JVM tak aby JIT mógł zrobić swoje, przed faktycznym benchmarkiem na podstawie którego jest robiony pomiar.
Na początek dodajemy zależność do maven’a:

<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.20</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.20</version>
    <scope>test</scope>
</dependency>


dlaczego scope test? osobiście polecam budowanie benchmarków jako JUnit lub MainClass w przestrzeni src/test/java
Tworzymy sobie klasę np: SerializableBenchmark i w niej piszemy metody:

public void ...

W metodzie wpisujemy:

int warmup = 5;
int iterations = 5;
int forks = 1;
int threads = 1;
String testClassRegExPattern = ".*Benchmark.*";
ResultFormatType resultsFileOutputType = ResultFormatType.TEXT;
String resultFilename = "jmh-result.txt";
Options opt = new OptionsBuilder().include(testClassRegExPattern).warmupIterations(warmup).measurementIterations(iterations)
                .forks(forks).threads(threads).shouldDoGC(true).shouldFailOnError(true).resultFormat(resultsFileOutputType)
                .result(resultFilename)
                .shouldFailOnError(true).jvmArgs("-server").build();
        try {
            Runner runner = new Runner(opt);
            runner.run();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

Gdzie:
testClassRegExPattern – regexp klas jakie ma uruchomić benchmark

I to jest nasza klasa testowa umożliwiająca wykonywanie benchmarków za pomocą testów jednostkowych.

W klasach które maja sie uruchomić jako benchmarki wpisujemy metodę z adnotacją: @Benchmark
Można również uruchomić test z bechmarkiem znajdującym się w tej samej klasie, przykład:

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class SerializationBenchmark {
    private ObjectMapper objectMapper = new ObjectMapper();
    public static final String JSON = “...”;

    @Test
    public void benchmark() {
        int warmup = 5;
        int iterations = 5;
        int forks = 1;
        int threads = 1;
        ResultFormatType resultsFileOutputType = ResultFormatType.TEXT;
        String resultFilename = "jmh-result.txt";
        Options opt = new OptionsBuilder().include("SerializationBenchmark")
                .warmupIterations(warmup).measurementIterations(iterations)
                .forks(forks).threads(threads)
                .shouldDoGC(true)
                .shouldFailOnError(true)
                .resultFormat(resultsFileOutputType)
                .result(resultFilename)
                .shouldFailOnError(true).jvmArgs("-server").build();
        try {
            Runner runner = new Runner(opt);
            runner.run();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Benchmark
    public void streamBuffer() throws Exception {
        ...
    }

    @Benchmark
    public void fillBuffer() throws Exception {
       ...
    }
}

Według mnie uruchamianie benchmarów JMH jako test jednostkowy jest dużo bardziej elastyczne niż uruchomienie tego za pomocą pluginu mavenowego.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *