官网

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

如何在idea创建maven测试

  1. 创建Maven项目,添加依赖

        <dependencies>
            <!-- 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>
        </dependencies>
    
  2. idea安装JMH插件 JMH plugin v1.0.3

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

    compiler -> Annotation Processors -> Enable Annotation Processing

  4. 定义需要测试类PS (ParallelStream)

    package com.mashibing.jmh;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    public class PS {
    
    	static List<Integer> nums = new ArrayList<>();
    	static {
    		Random r = new Random();
    		for (int i = 0; i < 10000; i++) nums.add(1000000 + r.nextInt(1000000));
    	}
    
    	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;
    	}
    }
    
  5. 写单元测试

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

    public class Testt {
        @Benchmark
        @Warmup(iterations = 5, time = 1)
        @Fork(5)
        @BenchmarkMode(Mode.Throughput)
        @Measurement(iterations = 1,time = 3)
        public void ps_test() {
               PS.foreach();
           }
       }
      
    
  6. 运行测试类,如果遇到下面的错误:

    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

  7. 阅读测试报告

注解介绍

@Warmup

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)。所以,基准测试后对代码预热总计5秒(迭代5次,每次1秒)。预热对于压测来说非常非常重要,如果没有预热过程,压测结果会很不准确。这个注解对应的日志如下:

# Warmup Iteration   1: 0.827 ops/s
# Warmup Iteration   2: 0.821 ops/s
# Warmup Iteration   3: 0.826 ops/s
# Warmup Iteration   4: 0.829 ops/s
# Warmup Iteration   5: 0.825 ops/s

@Measurement

度量,其实就是一些基本的测试参数。
iterations 进行测试的轮次
time 每轮进行的时长
timeUnit 时长单位

@Fork

进行 fork 的次数。可用于类或者方法上。如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试。

@Benchmark

方法级注解,表示该方法是需要进行 benchmark 的对象,用法和 JUnit 的 @Test 类似。

@BenchmarkMode

基准测试类型。这里选择的是Throughput也就是吞吐量。根据源码点进去,每种类型后面都有对应的解释,比较好理解,吞吐量会得到单位时间内可以进行的操作数。

  • Throughput: 整体吞吐量,例如“1秒内可以执行多少次调用”。
  • AverageTime: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”。
  • SampleTime: 随机取样,最后输出取样结果的分布,例如“99%的调用在xxx毫秒以内,99.99%的调用在xxx毫秒以内”
  • SingleShotTime: 以上模式都是默认一次 iteration 是 1s,唯有 SingleShotTime 是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。
  • All(“all”, “All benchmark modes”);

官方样例:
http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/


hhhhh