对JMH框架中OperationsPerInvocation这一参数的理解

5 篇文章 0 订阅
1 篇文章 0 订阅

JMH

jmh是java microbenchmark harness的缩写,用于Java的method层面的性能测试,框架使用比较方便,不像C++的gmock与gtest的语法规则那么复杂。对于jmh的学习主要参看下面这几个链接就可以了:

JMH简介

GitHub-Java Benchmark

JAVA拾遗 — JMH与8个代码陷阱

遇到的问题

在了解了基本语义之后,使用以下的测试代码来进行测试。

import xxx;

@BenchmarkMode(Mode.Throughput)
@State(Scope.Benchmark)
@Fork(1)
@Warmup(iterations = 5)
@Measurement(iterations = 10) 
public class EncodingBenchmark {

    @State(Scope.Benchmark)
    public static class DataGenerator {
        @Param({"100000"})
        public int amountOfPoints;

        @Setup(Level.Trial)
        public void setup() {
            //TODO
        }
    }

    @Benchmark
    @OperationsPerInvocation(100000)
    public void encodingBenchmark_oper100000_100000(DataGenerator dg) {
        ByteBufferBitOutput output = new ByteBufferBitOutput();
        Compressor c = new Compressor(dg.blockStart, output);

        for(int j = 0; j < dg.amountOfPoints; j++) {
            c.addValue(dg.uncompressedBuffer.getLong(), dg.uncompressedBuffer.getDouble());
        }
        c.close();
        dg.uncompressedBuffer.rewind();
    }

    @Benchmark
    @OperationsPerInvocation(1000)
    public void encodingBenchmark_oper1000_100000(DataGenerator dg) {
        ByteBufferBitOutput output = new ByteBufferBitOutput();
        Compressor c = new Compressor(dg.blockStart, output);

        for(int j = 0; j < dg.amountOfPoints; j++) {
            c.addValue(dg.uncompressedBuffer.getLong(), dg.uncompressedBuffer.getDouble());
        }
        c.close();
        dg.uncompressedBuffer.rewind();
    }
   
}

在写好maven工程之后,利用mvn clean compile和 mvn clean package  -Dmaven.javadoc.skip=true来编译和打包,再在命令行执行java -jar benchmark.jar。得出的吞吐率结果如下所示:

回顾上面的测试代码可以看到,encodingBenchmark_oper100000_100000和encodingBenchmark_oper1000_100000这两个函数体完全一致,除了一个是@OperationsPerInvocation(100000)一个是@OperationsPerInvocation(1),同时,可以看到encodingBenchmark_oper100000的吞吐率近似是encodingBenchmark_oper1000的100倍。那这是为什么???从字面意思来看,是说一次调用执行多少次操作,那调用指的是什么,操作又指的是什么?如果说调用是函数对for内层的调用,操作代表内层for循环的执行。这样的话,OperationsPerInvocation只要取值较大,吞吐性能就应该是接近的,绝对不会有如此大的差距。这两个到底该怎么理解,那个取值是可信的?谷歌之,官网解释,未得解,gayhub上大佬懒得教我,随便说了两句,不得其解。

解释与结论

其实应该这么想,JMH本身就是一个基准测试框架,应该从测试框架的角度去想。

1.OperationsPerInvocation这个参数,一次调用的操作数,这里的调用指的是jmh框架对这个method做一次benchmark,操作这里指的是for的内层子句。换言之,for的循环次数都是固定的,不受OperationsPerInvocation这一参数的影响。OperationsPerInvocation的意思是,衡量这么多的for循环操作的性能,取其中的多少次for来计算。encodingBenchmark_oper1000_100000这个函数,在框架中执行了100000次for循环,但是我计算吞吐率是并不取完,只用1000次来算吞吐,所以吞吐被相应的缩小。如果写一个encodingBenchmark_oper1000w_10w,这个吞吐会被放大,框架从实际的10w次循环中取1000w次(虚拟的)循环来计算吞吐,吞吐率会大约是encodingBenchmark_oper10w_10w的100倍,验证如下:

如果两个参数都是50000,与原本encodingBenchmark_oper10w_10w的吞吐率应该接近一致,验证如下:

2.如需要计算性能,OperationsPerInvocation的大小当于for循环次数一致(JMH测试陷阱中提到尽量不用循环,此文是为了解释OperationsPerInvocation的意义而设置的场景)。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值