09-JMH

benchmark 英 [ˈbentʃmɑːk] n. 基准,vt. 检测(用基准问题测试)

harness 英 [ˈhɑːnɪs] n. 马具;挽具;背带,保护带,vt. 控制,利用(以产生能量等)

测试:

  1. 自动化开发
  2. 性能开发:JMH
  3. 测试开发:为测试开发工具

QPS:query_per_seconds

1. what

Java_Microbenchmark_Harness

  1. JMH官网open in new window
  2. 2013首发,由JIT的开发人员开发,归于OpenJDK
  3. 官方样例open in new window

2. 创建JMH测试

JMHTest

1. 添加依赖

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.21</version>
    <scope>test</scope>
</dependency>



 





 



2. JMH插件

《 JMH Java Microbenchmark Harness》

image-20220825084909155

3. 打开注解配置

setting => compiler => Annotation Processors => Enable annotation processing

image-20220802085611882

4. 单元测试

这个测试类一定要在test package下面

/**
 * 不能用debug模式,用run即可
 */
public class JMHTest {

    // Benchmark:默认注解执行的时间很长,10分钟左右
    @Benchmark
    // 预热:迭代一次,3s
    // JVM中对于特定代码会存在优化(本地化),预热对于测试结果很重要
    @Warmup(iterations = 1, time = 3)
    // thread量
    @Fork(5)
    // 模式,吞吐量:1. 1秒n次 2. 1次n秒
    @BenchmarkMode(Mode.Throughput)
    // 方法调用次数
    @Measurement(iterations = 1, time = 3)
    public void testForEach() {
        JMH.parallel();
        // JMH.parallel();
    }
}

class JMH {

    static List<Integer> nums = new ArrayList<>();

    static {
        Random r = new Random();
        for (int i = 0; i < 1_000; i++) nums.add(1_000_000 + r.nextInt(1_000_000));
    }

    public static void foreach() {
        nums.forEach(JMH::isPrime);
    }

    static void parallel() {
        nums.parallelStream().forEach(JMH::isPrime);
    }

    static void isPrime(int num) {
        for (int i = 2; i <= num / 2; i++) {
            if (num % i == 0) return;
        }
    }
}





 
 
 
 
 
 
 
 
 
 
 
















 



 








5. 运行测试类

如果遇到下面的错误:

ERROR: org.openjdk.jmh.runner.RunnerException: ERROR: Exception while trying to acquire the JMH lock (C:\WINDOWS\/jmh.lock): C:\WINDOWS\jmh.lock (拒绝访问。), exiting. Use -Djmh.ignoreLock=true to forcefully continue.
	at org.openjdk.jmh.runner.Runner.run(Runner.java:216)
	at org.openjdk.jmh.Main.main(Main.java:71)

这个错误是因为JMH运行需要访问系统的TMP目录,更改TMP目录。解决办法是:

RunConfiguration => Environment Variables => include system environment viables

image-20220802112058700

6. 运行日志

JMH.foreach();

# JMH version: 1.21
# VM version: JDK 11.0.16, OpenJDK 64-Bit Server VM, 11.0.16+8-LTS
# VM invoker: /Users/list/Library/Java/JavaVirtualMachines/corretto-11.0.16/Contents/Home/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=56426:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
# Warmup: 1 iterations, 3 s each
# Measurement: 1 iterations, 3 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: com.list.test.JMHTest.testForEach

# Run progress: 0.00% complete, ETA 00:00:30
# Fork: 1 of 5
# Warmup Iteration   1: 8.843 ops/s
Iteration   1: 9.936 ops/s

# Run progress: 20.00% complete, ETA 00:00:27
# Fork: 2 of 5
# Warmup Iteration   1: 8.681 ops/s
Iteration   1: 8.791 ops/s

# Run progress: 40.00% complete, ETA 00:00:20
# Fork: 3 of 5
# Warmup Iteration   1: 9.971 ops/s
Iteration   1: 9.806 ops/s

# Run progress: 60.00% complete, ETA 00:00:13
# Fork: 4 of 5
# Warmup Iteration   1: 11.123 ops/s
Iteration   1: 11.070 ops/s

# Run progress: 80.00% complete, ETA 00:00:06
# Fork: 5 of 5
# Warmup Iteration   1: 10.568 ops/s
Iteration   1: 10.709 ops/s


Result "com.list.test.JMHTest.testForEach":
  10.062 ±(99.9%) 3.407 ops/s [Average]
  (min, avg, max) = (8.791, 10.062, 11.070), stdev = 0.885
  CI (99.9%): [6.655, 13.470] (assumes normal distribution)


# Run complete. Total time: 00:00:33

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
JMHTest.testForEach  thrpt    5  10.062 ± 3.407  ops/s






































 
 













JMH.parallel();

# JMH version: 1.21
# VM version: JDK 11.0.16, OpenJDK 64-Bit Server VM, 11.0.16+8-LTS
# VM invoker: /Users/list/Library/Java/JavaVirtualMachines/corretto-11.0.16/Contents/Home/bin/java
# VM options: -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=56493:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
# Warmup: 1 iterations, 3 s each
# Measurement: 1 iterations, 3 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: com.list.test.JMHTest.testForEach

# Run progress: 0.00% complete, ETA 00:00:30
# Fork: 1 of 5
# Warmup Iteration   1: 36.398 ops/s
Iteration   1: 42.182 ops/s

# Run progress: 20.00% complete, ETA 00:00:27
# Fork: 2 of 5
# Warmup Iteration   1: 50.741 ops/s
Iteration   1: 52.327 ops/s

# Run progress: 40.00% complete, ETA 00:00:20
# Fork: 3 of 5
# Warmup Iteration   1: 41.879 ops/s
Iteration   1: 38.045 ops/s

# Run progress: 60.00% complete, ETA 00:00:13
# Fork: 4 of 5
# Warmup Iteration   1: 46.885 ops/s
Iteration   1: 44.649 ops/s

# Run progress: 80.00% complete, ETA 00:00:06
# Fork: 5 of 5
# Warmup Iteration   1: 50.807 ops/s
Iteration   1: 57.188 ops/s


Result "com.list.test.JMHTest.testForEach":
  46.878 ±(99.9%) 29.890 ops/s [Average]
  (min, avg, max) = (38.045, 46.878, 57.188), stdev = 7.762
  CI (99.9%): [16.988, 76.768] (assumes normal distribution)


# Run complete. Total time: 00:00:33

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
JMHTest.testForEach  thrpt    5  46.878 ± 29.890  ops/s