专栏首页泛泛聊后端微基准测试框架JMH

微基准测试框架JMH

最典型的场景就是你想知道两个功能相同的操作到底哪个性能比较好,通常会自己手撸一段代码,前后增加时间,然后对比多次执行的时间。这种做法比较原始,还要自己处理预热等问题。JMH提供了比较丰富的操作。且看如何使用。

使用示例

这个工具是JDK9 加入的,但是也可以直接使用Maven添加对应的依赖。

<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>${jmh.version}</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>${jmh.version}</version>
    <scope>provided</scope>
</dependency>

依赖添加完成以后即可编写性能测试程序

@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
public class JmhApplication {

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JmhApplication.class.getSimpleName())
                .forks(1)
                .warmupIterations(2)
                .measurementIterations(5)
                .build();

        new Runner(opt).run();
    }

    @Benchmark
    public void stringAdd(){
        String a = "";
        for (int i = 0; i < 10; i++) {
            a += i;
        }
    }

    @Benchmark
    public void stringBuilderAdd(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            sb.append(i);
        }
    }
}

如上述代码只需要在要进行基准测试的方法上增加Benchmark注解,即可进行基准测试。而类上的注解直接定义了基准测试的一些全局设置,如测试类型,时间单位等。

main方法里面使用Options类定义的预热运行测试方法的次数,以及运行基准测试运行方法的次数。接着构建Runner类运行基准测试。

// .... 省略其他输出
# Run progress: 50.00% complete, ETA 00:01:11
# Fork: 1 of 1
# Warmup Iteration   1: 23.463 ops/us
# Warmup Iteration   2: 19.687 ops/us
Iteration   1: 18.304 ops/us
Iteration   2: 20.687 ops/us
Iteration   3: 20.641 ops/us
Iteration   4: 20.194 ops/us
Iteration   5: 20.112 ops/us
// .... 省略其他输出
Benchmark                         Mode  Cnt   Score   Error   Units
JmhApplication.stringAdd         thrpt    5   5.711 ± 1.784  ops/us
JmhApplication.stringBuilderAdd  thrpt    5  19.988 ± 3.757  ops/us

结果如上,可以看出进行了2次的预热,执行5次迭代,来计算结果。最终输出了Benchmark的结果。关注点是Score和对应的单位Units,表示每个时间单位执行的操作次数。即第一个方法每微秒执行5.711 ± 1.784次,第二个方法是每微秒执行19.988 ± 3.757 次。

基准测试类型

基准测试类型,由注解BenchmarkMode来指定,主要由五种选择,实际是4种。

Throughput 整体吞吐量,结果是单位时间的执行次数。

Benchmark                         Mode  Cnt   Score   Error   Units
JmhApplication.stringAdd         thrpt    5   5.711 ± 1.784  ops/us
JmhApplication.stringBuilderAdd  thrpt    5  19.988 ± 3.757  ops/us

AverageTime 调用的平均时间,结果是执行一次所需要的时间。

Benchmark                        Mode  Cnt  Score   Error  Units
JmhApplication.stringAdd         avgt    5  0.150 ± 0.002  us/op
JmhApplication.stringBuilderAdd  avgt    5  0.049 ± 0.005  us/op

SampleTime 随机取样,最后输出取样结果的分布

Benchmark                                  Mode      Cnt     Score   Error  Units
stringAdd                                  sample  1264158     0.202 ± 0.019  us/op
stringAdd:stringAdd·p0.00                  sample              0.100          us/op
stringAdd:stringAdd·p0.50                  sample              0.200          us/op
stringAdd:stringAdd·p0.90                  sample              0.200          us/op
stringAdd:stringAdd·p0.95                  sample              0.200          us/op
stringAdd:stringAdd·p0.99                  sample              0.300          us/op
stringAdd:stringAdd·p0.999                 sample              2.200          us/op
stringAdd:stringAdd·p0.9999                sample             31.907          us/op
stringAdd:stringAdd·p1.00                  sample           3895.296          us/op
stringBuilderAdd                           sample  1968851     0.082 ± 0.008  us/op
stringBuilderAdd:stringBuilderAdd·p0.00    sample                ≈ 0          us/op
stringBuilderAdd:stringBuilderAdd·p0.50    sample              0.100          us/op
stringBuilderAdd:stringBuilderAdd·p0.90    sample              0.100          us/op
stringBuilderAdd:stringBuilderAdd·p0.95    sample              0.100          us/op
stringBuilderAdd:stringBuilderAdd·p0.99    sample              0.100          us/op
stringBuilderAdd:stringBuilderAdd·p0.999   sample              0.300          us/op
stringBuilderAdd:stringBuilderAdd·p0.9999  sample             10.896          us/op
stringBuilderAdd:stringBuilderAdd·p1.00    sample           3563.520          us/op

SingleShotTime 以上模式都是默认一次 iteration 是 1秒,唯有 SingleShotTime 是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。

// 预热修改为0,执行的次数修改为1
Options opt = new OptionsBuilder()
                .include(JmhApplication.class.getSimpleName())
                .forks(1)
                .warmupIterations(0)
                .measurementIterations(1)
                .build();
// 结果如下
Benchmark                        Mode  Cnt      Score   Error  Units
JmhApplication.stringAdd           ss       32612.100          us/op
JmhApplication.stringBuilderAdd    ss          18.500          us/op

All 运行全部以上的基准测试模式

其中最常用的是Throughput和AverageTime模式,其他的在正常场景基本上可以略过。

后续

工具使用起来比较方便,功能也是挺多,此处不逐个介绍。一个很大的缺点是文档比较少,官方有完整的示例代码,可以直接阅读和执行来学习如何使用。

本文分享自微信公众号 - 泛泛聊后端(HelloBackend),作者:李鸿坤

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 手把手教你自定义Spring Boot Starter

    官方提供的Spring Boot Starter涵盖面非常广,几乎所有流行的组件和方案都可以找到对应的封装。不过每个系统总会有自己的公共代码,可以自己进行St...

    李鸿坤
  • Log4j2日志框架

    log4j2是一个比较新的日志框架,作为log4j的升级版本,修复了它的锁竞争问题提升了性能,提供了丰富的组件支持以及良好的语义配置。

    李鸿坤
  • Java日志门面系统

    一个线上程序的运行情况监测,日志扮演着极其重要的角色。Java发展了20年,日志系统也是百家争鸣,不同历史时期出现的开源组件往往有着不同的日志实现,应用的整合难...

    李鸿坤
  • 一个限制进程 CPU 使用率的解决方案

    版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转...

    耕耘实录
  • 嵌入式中的人工神经网络

    人工神经网络在AI中具有举足轻重的地位,除了找到最好的神经网络模型和训练数据集之外,人工神经网络的另一个挑战是如何在嵌入式设备上实现它,同时优化性能和功率效率。...

    半吊子全栈工匠
  • 找出链表中倒数第K个节点

    思路1:如果能从链表尾部开始遍历,那只需倒序遍历 k 个节点即是要找出的节点,但是由于是单链表,只能从头结点开始遍历。

    谭小谭
  • 五大数据分析模型,产品经理必会

    要进行一次完整的数据分析,首先要明确数据分析思路,如从那几个方面开展数据分析,各方面都包含什么内容或指标。是分析框架,给出分析工作的宏观框架,根据框架中包含的内...

    双面人
  • 基于matplotlib和keras的神经网络结果可视化

    在使用神经网络进行模型训练的时候,我们可以通过误差损失函数、精度等一系列指标来判断最终神经网络的拟合效果,一般的问题中,无论是回归还是拟合,本质上都是“一个拟合...

    统计学家
  • 未来数字银行:KCASH与其打造的数字生态

    随着数字货币行业发展,越来越多的币种,越来越多的idea被生产出来,随之而来的也有越来越多的问题。试想数千万种数字货币(有专家指出未来每个细分行业都会出现行业数...

    Bit书生
  • 基于matplotlib和keras的神经网络结果可视化

    在使用神经网络进行模型训练的时候,我们可以通过误差损失函数、精度等一系列指标来判断最终神经网络的拟合效果,一般的问题中,无论是回归还是拟合,本质上都是“一个拟合...

    小草AI

扫码关注云+社区

领取腾讯云代金券