Java基准测试 JMH

引入到工程

<dependencies>
    <dependency>
    <groupId>org.openjdk.jmhgroupId>
    <artifactId>jmh-coreartifactId>
    <version>1.9version>
    dependency>
dependencies>

功能支持

测量方式(@BenchmarkMode)
  • Mode.Throughput [default]计算一个时间单位内操作数量
  • Mode.AverageTime 计算平均运行时间

时间单位(@OutputTimeUnit)

  • TimeUnit.SECONDS [default]秒
  • TimeUnit.MILLISECONDS 毫秒(10-3秒)
  • TimeUnit.MICROSECONDS 微秒(10-6秒)
  • TimeUnit.NANOSECONDS 纳秒(10-9秒)

多线程共享(@State)

  • Scope.Thread [default]实例将分配给运行给定测试的每个线程
  • Scope.Benchmark 运行相同测试的所有线程将共享实例,可以用来测试状态对象的多线程性能
  • Scope.Group 实例分配给每个线程组(查看后面的线程组部分)

fork新的线程(@Fork)

默认JMH为每个试验(迭代集合)fork一个新的java进程。
不要把forks设为0,除非你清楚这样做的目的。

这样可以防止前面收集的“资料”——其他被加载类以及它们执行的信息对当前测试的影响。比如,实现了相同接口的两个类,测试它们的性能,那么第一个实现(目标测试类)可能比第二个快,因为JIT发现第二个实现类后就把第一个实现的直接方法调用替换为接口方法调用。

测试阶段的参数(@Measurement @Warmup)

  • 可以指定迭代的次数
  • 可以指定每次迭代的运行时间和时间单位(默认为秒)

Measurement用于测试阶段
Warmup用于预热阶段(不计入测试时长)

线程数(@Threads)

  • 默认是Runtime.getRuntime().availableProcessors()

fixtures注解(@Setup @TearDown)

  • Level.Trial [default]全部benchmark运行(一组迭代)之前/之后
  • Level.Iteration 一次迭代之前/之后(一组调用)
  • Level.Invocation 每个方法调用之前/之后(不推荐使用,除非你清楚这样做的目的)

开始运行

使用IDEA运行微基准测试(推荐)

在IDEA中,只需要在Plugins的列表中,搜索一下JMH关键字,就能找到JMH Plugin,然后安装下来,重启一下IDEA,就能运行JMH微测试。

main函数调用

main方法中通过几句代码调用JMH库

Options opt = new OptionsBuilder()
    .include(testClazz.class.getSimpleName())
    .forks(1)
    .build();
new Runner(opt).run();

anti-编译器优化

冗余代码消除是microbenchmark中众所周知的问题。通常的解决方法是以某种方式使用计算结果。JMH本身不会实施对冗余代码的消除。

方法一:方法返回值

    @Benchmark
    public int testMethod() {
        int a = 1;
        int b = 2;
        int sum = a + b;

        return sum;
    }

方法二:交给Blackhole

   @Benchmark
   public void testMethod(Blackhole blackhole) {
        int a = 1;
        int b = 2;
        int sum = a + b;
        blackhole.consume(sum);
    }

参考:JMH简介
参考:JMH - Java Microbenchmark Harness

你可能感兴趣的:(java)