写点什么

Java 微基准测试神器 JMH 初探

作者:FunTester
  • 2023-02-28
    北京
  • 本文字数:1820 字

    阅读完需:约 6 分钟

当我们编写一段 Java 代码之后,如果想知道代码性能如何,就需要进行一些快速的性能测试。


当我们实现一个需求,面临 2 种及以上的方案,选择一种性能更好的方案时,也需要进行一些快速的性能测试。


在之前的实践中,我一开始的测试代码通常是这样的:


    public static void main(String[] args) {        long start = System.currentTimeMillis();        for (int i = 0; i < 100000; i++) {            doSomething();        }        long end = System.currentTimeMillis();        System.out.println(end - start);    }
复制代码


再到后来,变成这种:


    public static void main(String[] args) {        def test = {                doSomething()        }        new FunQpsConcurrent(test, "Demo").start();    }
复制代码


但最近又有了新的工具 JMH(Java Microbenchmark Harness)是用于代码微基准测试的工具套件,主要是基于方法层面的基准测试,精度可以达到纳秒级。该工具是由 Oracle 内部实现 JIT 的大牛们编写的,他们应该比任何人都了解 JIT 以及 JVM 对于基准测试的影响。


真可谓相见恨晚,上手也是非常迅速的,建议学习时间 2 小时,顺便看看官方 GitHub 仓库里面的错误示范,地址:https://github.com/lexburner/JMH-samples


PS:


  1. 如果你用的 Intellij,插件是真香。

  2. 如果要汇报,建议使用可视化工具,搜一下就有。


下面我分享一下我用 JMH 测试System.currentTimeMillis();System.nanoTime();两个方法的性能。外行大胆猜测,第二个方法应该性能比较差。原因是第二个方法获取到纳秒时间戳,应该会更消耗性能。


这是我的测试用例:


package com.funtest.groovytest;
import com.funtester.frame.SourceCode;import org.openjdk.jmh.annotations.*;import org.openjdk.jmh.results.format.ResultFormatType;import org.openjdk.jmh.runner.Runner;import org.openjdk.jmh.runner.RunnerException;import org.openjdk.jmh.runner.options.Options;import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.Throughput)@Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS)@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS)@Threads(2)@Fork(1)@State(value = Scope.Thread)@OutputTimeUnit(TimeUnit.NANOSECONDS)public class JmhT extends SourceCode {

@Param(value = {"10", "20", "50"}) private int length;
@Benchmark public void mill() { System.currentTimeMillis(); }
@Benchmark public void nano() { System.nanoTime(); }
public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(JmhT.class.getSimpleName()) .result("result.json") .resultFormat(ResultFormatType.JSON) .forks(1) .threads(20) .warmupIterations(2) .warmupBatchSize(1) .measurementIterations(2) .measurementBatchSize(2) .build(); new Runner(options).run(); }
}
复制代码


最后的 main 方法是为了生产result.json做可视化用的,如果单纯想知道性能差异,可以直接使用 Intellij 插件完成。用例中的length完全不用,只是想展示一下参数化的用法。


文字版测试结果如下:


Benchmark  (length)   Mode  Cnt  Score   Error   UnitsJmhT.mill        10  thrpt    2  0.015          ops/nsJmhT.mill        20  thrpt    2  0.015          ops/nsJmhT.mill        50  thrpt    2  0.016          ops/nsJmhT.nano        10  thrpt    2  0.091          ops/nsJmhT.nano        20  thrpt    2  0.088          ops/nsJmhT.nano        50  thrpt    2  0.084          ops/ns
复制代码


总体看就是System.nanoTime();性能要远远优于System.currentTimeMillis();,这是不是有点意外。


图片版本的报告



发布于: 刚刚阅读数: 3
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
Java微基准测试神器JMH初探_FunTester_InfoQ写作社区