Java Microbenchmark Harness (JMH)

Java Microbenchmark Harness (JMH)

Use Case

  • 想準確知道 Method 需要執行多長時間,以及執行時間和輸入之間的相關性
  • 對比 介面 ,以不同條件下實現的吞吐量
  • 查看多少百分比的 Request 在多久的時間內完成

Annotation

  • @BenchmarkMode
    • 用於 class / method
      • Throughout: 整體吞吐量,例如 1秒內可以執行多少次呼叫,單位 ops/time
      • AverageTime: 每次操作的平均時間,單位 time/op
      • SampleTime: 隨機取樣,最後輸出取樣結果的分布
      • SingleShotTime: 只運行一次,同時常常把@Warmup次數設為0,用於測試冷啟動的性能
      • All: 上述所有模式皆執行一次
  • @State
    • 指定一個物件的作用範圍
      • Scope.Benchmark: 所有測試Thread 共享一個 instance,測試有狀態instanceMulti-Thread 共享下的性能
      • Scope.Group: 同一個 Thread 在同一個 group 裡共享 instance
      • Scope.Thread: default state, 每個 Test Thread 分配一個 instance
  • @OutputTimeUnit
    • 統計結果的時間單位,用於 class / method
  • @Warmup
    • 一般前幾次進行程式測試的時候都會比較慢,需要先預熱幾輪,保證測試正確性
      • iterations: 預熱次數
      • time: 每次預熱時間
      • timeUnit: default second
      • batchSize: 批次處理大小,每次操作呼叫幾次方法

預熱原因:

JVM 有 JIT 機制,如果某個func()被呼叫多次,JVM 會嘗試將其編譯為 Machine Code,從而提高執行速度,為了讓 benchmark 的結果更加接近真實情況就需要進行預熱。

  • @Measurement: 實際呼叫Method所需要配置的基本測試參數,可用於class/methodParams@Warmup相同
  • @Threads: 每個 Process 中的 Test Thread,可用於class/method
  • @Fork: 如果 fork number = 2,則 JMH 會 fork 兩個 Process 來進行測試,可用於class/method
  • @Param: 特別適合用來測試一個func()在不同參數輸入的情況下的性能,只能作用於 字段 上,使用此標註必須定義 @State

Result Analyze

Result "com.lex.StringConnectTest.testStringBuilderAdd":
  426.954 ±(99.9%) 60.926 ns/op [Average]
  (min, avg, max) = (409.871, 426.954, 452.426), stdev = 15.822
  CI (99.9%): [366.027, 487.880] (assumes normal distribution)
  • 426.954 ±(99.9%) 60.926 ns/op [Average]
    • 每次操作平均耗時 426.954 ± 60.926 納秒
  • 最小值: 409.871
  • 平均值: 426.954
  • 最大值: 452.426
  • 標準差: 15.822
  • 平均值的信賴區間: [366.027, 487.880]
Benchmark                               (length)  Mode  Cnt     Score     Error  Units
StringConnectTest.testStringAdd               10  avgt    5   133.950 ±   3.264  ns/op
StringConnectTest.testStringAdd               50  avgt    5  1121.863 ±  55.314  ns/op
StringConnectTest.testStringAdd              100  avgt    5  3544.262 ± 199.877  ns/op
StringConnectTest.testStringBuilderAdd        10  avgt    5    46.597 ±   3.005  ns/op
StringConnectTest.testStringBuilderAdd        50  avgt    5   217.872 ±  11.888  ns/op
StringConnectTest.testStringBuilderAdd       100  avgt    5   426.954 ±  60.926  ns/op
  • length: @Param value
  • Mode: @BenchmarkMode 哪一種模式
  • Cnt: @Measurement() 運行次數
  • Score:
    • If benchmark mode is Throughput, then a higher score indicates better performance, because it measures the number of operations that can be executed per unit of time (e.g. operations per second).
    • If the benchmark mode is AverageTime, then a lower score indicates better performance, because it measures the time taken for a single operation to execute (e.g. nanoseconds per operation).
  • Error: 誤差,信心區間
  • Units: 每次呼叫單位時間