JMH的全称是Java Microbenchmark Harness,即Java微基准测试工具。
JMH是一个用于构建,运行和分析基于Java及其他JVM语言的基准测试工具。它也是OpenJDK项目的一部分。
要运行JMH基准测试,推荐的方法是使用Maven来构建一个测试项目。生成相关的依赖信息,以及简单的测试骨架代码。由于这种方式比较纯粹,项目是全新的、自动生成的,不受其他环境的影响,因此比较可靠。
使用Maven创建一个JMH基准测试项目
使用以下Maven命令创建一个JMH测试项目。
$ mvn archetype:generate -DinteractiveMode=false \
-DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DarchetypeVersion=1.21 \
-DgroupId=org.sample -DartifactId=test -Dversion=1.0
其中,以archetype开头的3个参数为JMH依赖信息,JMH版本号为1.21。
-DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DarchetypeVersion=1.21
最后3个参数为测试项目的信息,分别是默认包名、项目名和版本号。
-DgroupId=org.sample -DartifactId=test -Dversion=1.0
1)生成的pom.xml主要代码如下
<groupId>org.sample</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>JMH benchmark sample: Java</name>
<!-- This is the demo/sample template build script for building Java benchmarks with JMH.
Edit as needed. -->
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>{jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>{jmh.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- JMH version to use with this project. -->
<jmh.version>1.21</jmh.version>
<!-- Java source/target to use for compilation. -->
<javac.target>1.8</javac.target>
<!-- Name of the benchmark Uber-JAR to generate. -->
<uberjar.name>benchmarks</uberjar.name>
</properties>
2)生成一个MyBenchmark.java类
默认生成一个测试类,类里面仅有一个测试方法testMethod(),该方法带有一个@Benchmark注解。
可以在testMethod()方法内添加想要测试的代码逻辑,执行基准测试的时候将会执行该方法。
package org.sample;
import org.openjdk.jmh.annotations.Benchmark;
public class MyBenchmark {
@Benchmark
public void testMethod() {
// This is a demo/sample template for building your JMH benchmarks. Edit as needed.
// Put your benchmark code here.
}
}
编译构建项目
编译项目。
$ cd test/
$ mvn clean verify
生成目标信息如下。
$ ls target/
benchmarks.jar generated-sources/ maven-status/
classes/ maven-archiver/ test-1.0.jar
其中,benchmarks.jar包含了待测试代码的class文件,以及执行测试需要依赖的JMH相关class文件。
执行基准测试
在完成代码的构建之后,可以执行以下命令执行测试。
执行命令后,JMH将会扫描并找到所有待测试的代码,并执行测试相应的方法。
执行的过程中,会输出测试相关数据,总体上可以分为3部分:
- 测试环境配置信息;
- 每轮测试的具体情况;
- 整体测试结果。
测试环境配置信息
通过输出信息,可以了解到测环境试配置如下:
- JMH版本号为1.21;
- JDK版本号为1.8.0_121;
- 热身:每轮测试进行5次热身迭代,每次迭代的时间为10s;
- 真正的基准测试:每轮测试进行5次基准迭代,每次迭代的时间为10s;
- 超时:每次迭代的超时时间为10分钟;
- 线程:执行测试的线程数为1,顺序执行每轮测试;
- 基准测试模式:默认进行吞吐量测试;
- 基准测试方法:org.sample.MyBenchmark.testMethod
$ java -jar target/benchmarks.jar
# JMH version: 1.21
# VM version: JDK 1.8.0_121, Java HotSpot(TM) 64-Bit Server VM, 25.121-b13
# VM invoker: C:\SDK\jdk1.8.0_121\jre\bin\java.exe
# VM options: <none>
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.MyBenchmark.testMethod
# Run progress: 0.00% complete, ETA 00:08:20
# Fork: 1 of 5
# Warmup Iteration 1: 1576551518.400 ops/s
# Warmup Iteration 2: 1529719054.021 ops/s
# Warmup Iteration 3: 1666073877.889 ops/s
# Warmup Iteration 4: 1640435331.734 ops/s
# Warmup Iteration 5: 1638832864.366 ops/s
Iteration 1: 1625641896.790 ops/s
Iteration 2: 1533553941.136 ops/s
Iteration 3: 1592753193.369 ops/s
Iteration 4: 1632034409.677 ops/s
Iteration 5: 1595397793.688 ops/s
# Run progress: 20.00% complete, ETA 00:06:44
# Fork: 2 of 5
# Warmup Iteration 1: 1464189837.888 ops/s
# Warmup Iteration 2: 1568131253.159 ops/s
# Warmup Iteration 3: 1512431773.674 ops/s
# Warmup Iteration 4: 1624047095.614 ops/s
# Warmup Iteration 5: 1599319656.890 ops/s
Iteration 1: 1549565370.435 ops/s
Iteration 2: 1479685624.920 ops/s
Iteration 3: 1546268750.693 ops/s
Iteration 4: 1624076911.097 ops/s
Iteration 5: 1547120121.585 ops/s
# Run progress: 40.00% complete, ETA 00:05:03
# Fork: 3 of 5
# Warmup Iteration 1: 1635927468.533 ops/s
# Warmup Iteration 2: 2117152863.952 ops/s
# Warmup Iteration 3: 2191950165.947 ops/s
# Warmup Iteration 4: 2117139604.170 ops/s
# Warmup Iteration 5: 1966743425.584 ops/s
Iteration 1: 2094680040.904 ops/s
Iteration 2: 2192052945.492 ops/s
Iteration 3: 2215953631.021 ops/s
Iteration 4: 2187306852.799 ops/s
Iteration 5: 2225823062.910 ops/s
# Run progress: 60.00% complete, ETA 00:03:22
# Fork: 4 of 5
# Warmup Iteration 1: 2215218138.467 ops/s
# Warmup Iteration 2: 2060564779.974 ops/s
# Warmup Iteration 3: 2128581454.514 ops/s
# Warmup Iteration 4: 2136226391.233 ops/s
# Warmup Iteration 5: 2190998438.402 ops/s
Iteration 1: 2149230777.286 ops/s
Iteration 2: 1962048343.572 ops/s
Iteration 3: 1632748373.818 ops/s
Iteration 4: 2069121825.198 ops/s
Iteration 5: 2137771926.471 ops/s
# Run progress: 80.00% complete, ETA 00:01:40
# Fork: 5 of 5
# Warmup Iteration 1: 2175401658.601 ops/s
# Warmup Iteration 2: 1998795501.979 ops/s
# Warmup Iteration 3: 2207762443.100 ops/s
# Warmup Iteration 4: 2158909861.991 ops/s
# Warmup Iteration 5: 2172243775.496 ops/s
Iteration 1: 2088490735.383 ops/s
Iteration 2: 2055344061.187 ops/s
Iteration 3: 2143537771.341 ops/s
Iteration 4: 2249547560.686 ops/s
Iteration 5: 2204700995.400 ops/s
Result "org.sample.MyBenchmark.testMethod":
1893378276.674 ±(99.9%) 219511037.182 ops/s [Average]
(min, avg, max) = (1479685624.920, 1893378276.674, 2249547560.686), stdev = 293040954.374
CI (99.9%): [1673867239.493, 2112889313.856] (assumes normal distribution)
# Run complete. Total time: 00:08:24
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.
Benchmark Mode Cnt Score Error Units
MyBenchmark.testMethod thrpt 25 1893378276.674 ± 219511037.182 ops/s
每轮测试的具体情况
总共运行了5轮测试,每轮测试的输出信息大致如下:
- 当前的测试进度,以及剩下的测试时间;
- 当前是第几轮测试;
- 热身标识和序号,以及QPS;
- 基准测试标识和序号,以及QPS。
进行多轮测试,可以确保结果不是随机的。
每一轮会先执行热身,防止受启动和运行波动的影响
热身之后的基准迭代测试,才会反应到测试结果中。
每1次迭代时间为10s,每一轮进行5次热身5次基准测试,大约占用100s。
整体测试结果
汇总本次基准测试的整体情况,包括测试运行时间和每个测试方法的QPS等信息。
Result块是基准测试目标方法的测试结果,其中(min, avg, max)是最小、平均和最大QPS。
本次基准测试,总共运行了8分钟24秒。
MyBenchmark.testMethod进行的是吞吐量(thrpt)测试,进行了25次基准迭代。
参考
https://github.com/openjdk/jmh
https://javadevcentral.com/jmh-benchmark-with-examples
http://tutorials.jenkov.com/java-performance/jmh.html
---转载本站文章请注明作者和出处 996极客教程(996geek.com),请勿用于任何商业用途---