IDEA下进行 JMH Java微基准测试工具套件

什么是JMH

JMH-Java Microbenchmark Harness(Java微基准测试)
用于测试某方法性能到底是好还是不好,换了方法实现之后性能好还是不好。

2013年首发
由JIT(JAVA即时编译器)开发人员开发、后来归与OpenJdk

官网 http://openjdk.java.net/projects/code-tools/jmh/

创建JMH测试

创建Maven项目,添加依赖

        <!-- JMH的核心包 https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>1.21</version>
        </dependency>

        <!-- JMH依赖注解,需要注解处理包 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>

idea安装JMH插件

JMH plugin

由于用到了注解,打开运行程序注解配置

compiler -> Annotation Processors -> Enable Annotation Processing
在这里插入图片描述

定义需要测试类NumsSum(ParallelStream)

package com.ls.jmh;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by 刘绍 on 2020/8/1.
 */
public class NumsSum{

    static List<Integer> nums = new ArrayList<>();
    static {
        Random r = new Random();
        for (int i = 0; i < 10000; i++) nums.add(1000000 + r.nextInt(1000000));
    }

    public static void foreach() {
        nums.forEach(v->isPrime(v));
    }

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

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

写单元测试

这个测试类要在test package下面

package com.ls;

import com.ls.jmh.NumsSum;
import org.openjdk.jmh.annotations.*;

/**
 * Created by 刘绍 on 2020/8/1.
 */
public class PSTest {
    @Benchmark
    @Warmup(iterations = 1,time = 2)
    @Threads(2)
    @Fork(2)
    @BenchmarkMode(Mode.Throughput)
    @Measurement(iterations = 2,time = 2)
    public void testForEach() {
        NumsSum.foreach();
    }
}

运行测试类,如果遇到下面的错误

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目录,解决办法是:

打开RunConfiguration -> Environment Variables -> include system environment viables

阅读测试报告

对照JMH中的基本概念阅读,有相关参数的解释

# JMH version: 1.21
# VM version: JDK 1.8.0_131, Java HotSpot(TM) 64-Bit Server VM, 25.131-b11
# VM invoker: C:\Program Files\Java\jdk1.8.0_131\jre\bin\java.exe
# VM options: -Dfile.encoding=UTF-8
# Warmup: 1 iterations, 2 s each
# Measurement: 2 iterations, 2 s each
# Timeout: 10 min per iteration
# Threads: 2 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: com.ls.PSTest.testForEach

# Run progress: 0.00% complete, ETA 00:00:12
# Fork: 1 of 2
# Warmup Iteration   1: 0.366 ops/s
Iteration   1: 0.707 ops/s
Iteration   2: 0.644 ops/s

# Run progress: 50.00% complete, ETA 00:00:25
# Fork: 2 of 2
# Warmup Iteration   1: 0.630 ops/s
Iteration   1: 0.638 ops/s
Iteration   2: 0.539 ops/s


Result "com.ls.PSTest.testForEach":
  0.632 ±(99.9%) 0.450 ops/s [Average]
  (min, avg, max) = (0.539, 0.632, 0.707), stdev = 0.070
  CI (99.9%): [0.182, 1.082] (assumes normal distribution)


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

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
PSTest.testForEach  thrpt    4  0.632 ± 0.450  ops/s

在这里插入图片描述
得分:每秒能执行 0.558 ±0.162

JMH中的基本概念

  • Warmup
    Warmup(iterations = 1,time = 3) 默认是运行10次,每次运行1秒,我们的例子是运行1次,每次3秒
    预热,由于JVM中对于特定代码会存在优化(本地化),预热对于测试结果很重要

  • Fork
    代表启动多个单独的进程分别测试

  • BenchmarkMode
    基准测试的模式 默认是Mode.Throughput,表示吞吐量(每秒钟执行多少次)

    其他参数还有
    AverageTime,表示每次执行时间
    SampleTime表示采样时间
    SingleShotTime表示只运行一次,用于测试冷启动消耗时间
    All表示统计前面的所有指标

  • Mesurement
    @Measurement(iterations = 1,time = 10)
    执行多少次,间隔多少秒开始下一次迭代

  • Timeout 默认为10分钟
    每次执行需要在多少分钟内完成,如果在规定时间内没完成就认为超时了。

  • Threads
    每次多少个线程来执行

  • Fork
    多个单独的进程分别测试每个方法,我们这里指定为每个方法启动一个进程。

  • Benchmark
    测试哪一段代码 PSTest.testForEach

官方样例:

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值