JMH 性能測試分析工具

一 什麼是 JMH

       JMH 是在 method 層面上的 benchmark,精度可以精確到微秒級,是對熱點函數進行優化時,對優化結果進行定量分析的工具

二 JMH 的應用場景

典型場景:

  • 想定量地知道某個函數需要執行多長時間,以及執行時間和輸入 n 的相關性。
  • 一個函數有多種不同的實現,針對多種不同的實現,需要定量分析出那種實現性能更好。

三 JMH 的使用

3.1 引入依賴

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

3.2 使用介紹

下面樣例是比較一下 AtomicLong 和 LongAdder 的性能:

package com.sb.springbootjmh;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.Throughput)
@State(Scope.Thread)
public class Main {
    private static AtomicLong count = new AtomicLong();
    private static LongAdder longAdder = new LongAdder();
    public static void main(String[] args) throws Exception {
        Options options = new OptionsBuilder()
                .include(Main.class.getName())
                .forks(1)
                .warmupIterations(5)
                .measurementIterations(5)
                .build();
        new Runner(options).run();
    }

    @Benchmark
    @Threads(10)
    public void run0(){
        count.getAndIncrement();
    }

    @Benchmark
    @Threads(10)
    public void run1(){
        longAdder.increment();
    }
}

得到如下結果:

3.3 JMH註解說明

@Benchmark

       表示該方法是需要進行 benchmark 的對象,用法和 JUnit 的 @Test 類似。其中 Mode 有四種選擇:

  • Throughput: 整體吞吐量,例如“1秒內可以執行多少次調用”。
  • AverageTime: 調用的平均時間,例如“每次調用平均耗時xxx毫秒”。
  • SampleTime: 隨機取樣,最後輸出取樣結果的分佈,例如“99%的調用在xxx毫秒以內,99.99%的調用在xxx毫秒以內”
  • SingleShotTime: 以上模式都是默認一次 iteration 是 1s,唯有 SingleShotTime 是只運行一次。往往同時把 warmup 次數設爲0,用於測試冷啓動時的性能。

@State

   State 用於聲明某個類是一個“狀態”,然後接受一個 Scope 參數用來表示該狀態的共享範圍。因爲很多 benchmark 會需要一些表示狀態的類,JMH 允許你把這些類以依賴注入的方式注入到 benchmark 函數裏。Scope 主要分爲兩種。

  • Thread: 該狀態爲每個線程獨享。
  • Benchmark: 該狀態在所有線程間共享。

@OutputTimeUnit

       benchmark 結果所使用的時間單位。

3.4 JMH 啓動參數說明

Options options = new OptionsBuilder()
                .include(Main.class.getName())
                .forks(1)
                .warmupIterations(5)
                .measurementIterations(5)
                .build();
  • include

       benchmark 所在的類的名字,注意這裏是使用正則表達式對所有類進行匹配的。

  • fork

       進行 fork 的次數。如果 fork 數是2的話,則 JMH 會 fork 出兩個進程來進行測試。

  • warmupIterations

       預熱的迭代次數。

  • measurementIterations

       實際測量的迭代次數。

四 參考說明

    本文只是簡單的介紹 JMH 的使用,要想深入瞭解請參考如下鏈接:

   官網:http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

    https://blog.dyngr.com/blog/2016/10/29/introduction-of-jmh/

    https://www.jianshu.com/p/67a75e36166f

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章