JMH Benchmark 效能測試淺談
概述
轉自:https://testerhome.com/topics/11250
JMH 是一個由 OpenJDK/Oracle 裡面那群開發了 Java 編譯器的大牛們所開發的 Micro Benchmark Framework 。何謂 Micro Benchmark 呢?簡單地說就是在 method 層面上的 benchmark,精度可以精確到微秒級。可以看出 JMH 主要使用在當你已經找出了熱點函式,而需要對熱點函式進行進一步的優化時,就可以使用 JMH 對優化的效果進行定量的分析。
典型場景
- 想定量地知道某個函式需要執行多長時間,以及執行時間和輸入 n 的相關性
- 一個函式有兩種不同實現(例如實現 A 使用了 FixedThreadPool,實現 B 使用了 ForkJoinPool),不知道哪種實現效能更好
儘管 JMH 是一個相當不錯的 Micro Benchmark Framework,但很無奈的是網上能夠找到的文件比較少,而官方也沒有提供比較詳細的文件,對使用造成了一定的障礙。但是有個好訊息是官方的 Code Sample 寫得非常淺顯易懂,推薦在需要詳細瞭解 JMH 的用法時可以通讀一遍——本文則會介紹 JMH 最典型的用法和部分常用選項。
使用
我在idea中使用的時候 ,需要在pom.xml中使用如下配置:
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
<scope>provided</scope>
</dependency>
實際測試程式碼如下:(建立第一個BenchMark)
package normaltest;
import org.openjdk.jmh.annotations.*;
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;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
public class JMHFirstBenchmark {
@Benchmark//對要被測試效能的程式碼新增註解,說明該方法是要被測試效能的
public int sleepAWhile() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// ignore
}
return 0;
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(JMHFirstBenchmark.class.getSimpleName())
.forks(1)
.warmupIterations(3)
.measurementIterations(3)
.build();
new Runner(opt).run();
}
}
輸出結果:
# JMH version: 1.19
# VM version: JDK 1.8.0_144, VM 25.144-b01
# VM invoker: /usr/lib/jvm/java-8-oracle/jre/bin/java
# VM options: -javaagent:/home/lijun/Downloads/idea-IU-172.3317.76/lib/idea_rt.jar=36941:/home/lijun/Downloads/idea-IU-172.3317.76/bin -Dfile.encoding=UTF-8
# Warmup: 3 iterations, 1 s each
# Measurement: 3 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: normaltest.JMHFirstBenchmark.sleepAWhile
# Run progress: 0.00% complete, ETA 00:00:06
# Fork: 1 of 1
# Warmup Iteration 1: 50189.958 us/op
# Warmup Iteration 2: 50074.371 us/op
# Warmup Iteration 3: 50075.263 us/op
Iteration 1: 50071.800 us/op
Iteration 2: 50074.029 us/op
Iteration 3: 50072.798 us/op
Result "normaltest.JMHFirstBenchmark.sleepAWhile":
50072.876 ±(99.9%) 20.367 us/op [Average]
(min, avg, max) = (50071.800, 50072.876, 50074.029), stdev = 1.116
CI (99.9%): [50052.509, 50093.242] (assumes normal distribution)
# Run complete. Total time: 00:00:06
Benchmark Mode Cnt Score Error Units
JMHFirstBenchmark.sleepAWhile avgt 3 50072.876 ± 20.367 us/op
對 sleepAWhile() 的測試結果顯示執行時間平均約為50毫秒。因為我們的測試物件 sleepAWhile() 正好就是睡眠50毫秒,所以 JMH 顯示的結果可以說很符合我們的預期。
基本概念:
Mode
Mode 表示 JMH 進行 Benchmark 時所使用的模式。通常是測量的維度不同,或是測量的方式不同。目前 JMH 共有四種模式:
(1).Throughput: 整體吞吐量,例如“1秒內可以執行多少次呼叫”。
(2).AverageTime: 呼叫的平均時間,例如“每次呼叫平均耗時xxx毫秒”。
(3).SampleTime: 隨機取樣,最後輸出取樣結果的分佈,例如“99%的呼叫在xxx毫秒以內,99.99%的呼叫在xxx毫秒以內”
(4).SingleShotTime: 以上模式都是預設一次 iteration 是 1s,唯有 SingleShotTime 是隻執行一次。往往同時把 warmup 次數設為0,用於測試冷啟動時的效能。
Interation
Iteration是JMH進行測試的最小單位。大部分模式下,iteration代表的是一秒,JMH會在這一秒內不斷呼叫需要benchmark的方法,然後根據模式對其取樣,計算吞吐量,計算平均執行時間等。
Warmup
Warmup是指在實際進行Benchmark前先進行預熱的行為。因為JVM的JIT機制的存在,如果某個函式被呼叫多次以後,JVM會嘗試將其編譯成為機器碼從而提高執行速度。所以為了讓benchmark的結果更加接近真實情況就需要進行預熱。
註解
現在來解釋一下上面例子中使用到的註解,其實很多註解的意義完全可以望文生義 :)
@Benchmark
表示該方法是需要進行 benchmark 的物件,用法和 JUnit 的 @Test 類似。
@Mode
Mode 如之前所說,表示 JMH 進行 Benchmark 時所使用的模式。
@State
State 用於宣告某個類是一個“狀態”,然後接受一個 Scope 引數用來表示該狀態的共享範圍。因為很多 benchmark 會需要一些表示狀態的類,JMH 允許你把這些類以依賴注入的方式注入到 benchmark 函式裡。Scope 主要分為兩種。
(1).Thread: 該狀態為每個執行緒獨享。
(2).Benchmark: 該狀態在所有執行緒間共享。
關於State的用法,官方的 code sample 裡有比較好的例子。
@OutputTimeUnit
benchmark 結果所使用的時間單位。
啟動選項
解釋完了註解,再來看看 JMH 在啟動前設定的引數。
Options opt = new OptionsBuilder()
.include(FirstBenchmark.class.getSimpleName())
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(opt).run();
<font color=red>include</font>
benchmark 所在的類的名字,注意這裡是使用正規表示式對所有類進行匹配的。
fork
進行 fork 的次數。如果 fork 數是2的話,則 JMH 會 fork 出兩個程式來進行測試。
warmupIterations
預熱的迭代次數。
measurementIterations
實際測量的迭代次數。
相關文章
- JMH- benchmark基準測試
- 淺談效能測試
- 淺談效能測試分析
- 效能測試工作流程淺談
- 效能測試中唯一標識的 JMH 測試
- Java基準效能測試--JMH使用介紹Java
- 使用 Benchmark.NET 測試程式碼效能
- Jmh測試JDK,CGLIB,JAVASSIST動態代理方式的效能JDKCGLibJava
- 淺談前端測試前端
- c++效能測試工具:google benchmark入門(二)C++Go
- c++效能測試工具:google benchmark進階(一)C++Go
- JMH-大廠是如何使用JMH進行Java程式碼效能測試的?必須掌握!Java
- 淺談並行測試並行
- 淺談web介面測試Web
- benchmark 基準測試
- 淺談前端單元測試前端
- 淺談ddos的測試方式
- 淺談自動化測試
- JMH模擬鎖高爭用,長臨界區,測試鎖效能
- Java效能測試利器:JMH入門與實踐|得物技術Java
- 使用 JMH 做 Kotlin 的基準測試Kotlin
- 網路底層測試方法淺談
- 工具篇 | 淺談測試那些恩怨情仇
- AI演算法測試之淺談AI演算法
- 簡單效能測試:springboot-2.x vs actix-web-4.x benchmarkSpring BootWeb
- JAVA拾遺 — JMH與8個測試陷阱Java
- 淺談測試生涯如何轉型升級
- 淺談自動化測試框架開發框架
- 淺談.Net Core後端單元測試後端
- Go十大常見錯誤第2篇:benchmark效能測試的坑Go
- 淺談Nginx效能調優Nginx
- JB測試之旅-淺談自動化知識
- 淺談移動網際網路App測試APP
- 淺談pytest+HttpRunner如何展開介面測試HTTP
- 效能測試中伺服器關鍵效能指標淺析伺服器指標
- 淺談小程式效能優化優化
- 效能優化,實踐淺談優化
- 淺談網站效能之前端效能優化網站前端優化