Java Top.

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

>>查看课程

1.介绍

此快速文章专注于JMH(Java Microbenchmark Harness)。首先,我们熟悉API并学习其基础知识。然后我们会看到一些最好的做法,我们应该在编写微币时考虑。

简单地说,JMH照顾JVM热身和代码优化路径,使基准测试尽可能简单。

2.入门

要开始,我们实际上可以继续使用Java 8并简单地定义依赖项:

<依赖项>  org.openjdk.jmh   JMH-CORE   1.28   <依赖项>  org.openjdk.jmh   JMH-Generator-AnnProcess  <版本> 1.28  

最新版本的JMH核心JMH注释处理器可以在Maven Central中找到。

接下来,通过利用创建一个简单的基准@基准注释(在任何公共类别中):

@benchmark public void init(){// do nothe}

然后我们添加启动基准测试过程的主类:

公共类BenchmarkRunner {公共静态void main(String [] args)抛出异常{org.openjdk.jmh.main.main(args);}}

现在跑步BenchmarkRunner.将执行我们的可争解地有些无用的基准。运行完成后,介绍了一个摘要表:

#跑步完成。总时间:00:06:45基准模式CNT评分错误单元Benchmark.init Thrpt 200 30999210741.962±17510507.589 OPS / s

3.基准的类型

JMH支持一些可能的基准:吞吐量,AverageTime,采样时间, 和单身镜头。这些可以通过@benchmarkmode.注解:

@benchmark @benchmarkmode(mode.averagetime)public void init(){// do nothing}

结果表将具有平均时间度量(而不是吞吐量):

#跑步完成。总时间:00:00:40基准模式CNT分数错误单位Benchmark.init Avgt20≈10⁻⁹S/ op

4.配置预热和执行

通过使用@叉注释,我们可以建立基准执行如何发生:价值参数控制基准将执行的次数有多少次,以及暖身参数控件在收集结果之前,基准测试将如何干燥运行,例如:

@benchmark @fork(value = 1,harmups = 2)@benchmarkmode(mode.througuput)public void init(){// do nother}

这指示JMH在移动到实际定时基准测试之前运行两个热身叉子并丢弃结果。

此外,@暖身注释可用于控制预热迭代的数量。例如,@warmup(迭代= 5)告诉JMH,五个预热迭代就足够了,而不是默认值20。

5.状态

现在,我们现在可以通过利用来检查如何执行散列算法的基准算法的较低的微不足道和更具指示性的任务状态。假设我们决定通过将密码散列几百倍的密码添加密码数据库上的额外保护。

我们可以使用a探索性能影响状态目的:

@state(scope.benchmark)公共类executionplan {@param({“100”,“200”,“300”,“300”,“500”,“1000”})公共INT迭代;公共哈尔·穆尔穆尔3;公共字符串密码=“4V3rys3kur3p455w0rd”;@setup(level.invocation)public void setup(){murmur3 = hashing.murmur3_128()。newhasher();}}

我们的基准方法看起来像:

@fork(value = 1,harmups = 1)@benchmark @benchmarkmode(mode.througupul)公共void benchmurmur3_128(executionplan计划){for(int i = plan.jerigorations; i> 0; i--){plan.murmur3。putstring(plan.password,charset.defaultCharset());plan.murmur3.hash();}

这里,这个领域迭代将以适当的值填充@Param.通过JMH将其传递给基准方法时的注释。这@设置每次调用基准测试之前调用注释方法并创建一个新的哈赫确保隔离。

执行完成后,我们将获得类似于下面的结果:

#跑步完成。总时间:00:06:47基准(迭代)模式CNT分数误差单位Benchmark.benchmurmur3_128 100 Thrpt 20 92463.622±1672.227 Ops / s Benchmark.benchmurmur3_128 200 Thrpt 20 39737.532±5294.200 OPS / S Benchmark.benchmurmur3_128 300 Thrpt 20 30381.144±614.500OPS / S Benchmark.benchmurmur3_128 500 Thrpt 20 18315.211±222.534 Ops / s Benchmark.benchmurmur3_128 1000 Thrpt 20 8960.008±658.524 Ops / s

6.死代码消除

在运行Microbenchmarks时,要了解优化非常重要。否则,它们可能以非常误导的方式影响基准结果。

让事情更具体,让我们考虑一个例子:

@benchmark @outputtimeUnit(timeUnit.nanoseconds)@benchmarkmode(mode.averagetime)public void donothing(){} @benchmark @outputtimeUnit(tateUnit.nanoseconds)@benchmarkmode(mode.averageTime)public void objectcreation(){new object();}

我们预计对象分配的成本比一直无所作为。但是,如果我们运行基准:

基准模式CNT分数误差单位基准。DONOTHING AVGT 40 0.609±0.006 NS / OP基准.ObjectCreation AVGT 40 0.613±0.007 NS / OP

显然找到了一个地方Tlab.,创建和初始化对象几乎是免费的!只要通过查看这些数字,我们应该知道这里没有完全加起来。

在这里,我们是死者消除的受害者。编译器非常擅长优化冗余代码。事实上,这正是JIT编译器在这里做了什么。

为了防止这种优化,我们应该以某种方式欺骗编译器,并认为某些其他组件使用代码。实现这一目标的一种方法只是返回创建的对象:

@benchmark @outputtimeUnit(tateUnit.nanoseconds)@benchmarkmode(mode.averageTime)publice对象pillarsofcreation(){return new object();}

另外,我们可以让黑洞消耗它:

@benchmark @outputtimeUnit(timeUnit.nanoseconds)@benchmarkmode(mode.averageTime)公共空缺黑洞(Blackhole Blackhole){blackhole.consume(新对象());}

拥有黑洞消耗对象是一种说服JIT编译器不应用死代码消除优化的方法。无论如何,如果我们再次运行基准,数字会更有意义:

基准模式CNT分数误差单元Benchmark.Blackhole AVGT 20 4.126±0.173 NS / OP基准.DONOTHING AVGT 20 0.639±0.012 NS / OP基准.ObjectCreation AVGT 20 0.635±0.011 NS / OP基准.PillarsofCreation Avgt 20 4.061±0.037 ns / op

7.恒定折叠

让我们考虑另一个例子:

@benchmark public double dockedlog(){int x = 8;返回math.log(x);}

无论执行次数如何,基于常量的计算可能会返回完全相同的输出。因此,JIT编译器将替换对数函数调用的结果非常有机会:

@benchmark public double foldedlog(){返回2.0794415416798357;}

这种形式的部分评估称为常量折叠。在这种情况下,恒定的折叠完全避免了math.log.呼叫,这是基准的全部点。

为了防止常量折叠,我们可以封装状态对象内的恒定状态:

@state(scope.benchmark)公共静态类日志{public int x = 8;@benchmark public double log(log输入){return math.log(input.x);}

如果我们互相运行这些基准:

基准模式CNT分数错误单位基准.Foldedlog Thrpt 20 449313097.433±11850214.900 OPS / S Benchmark.log Thrpt 20 35317997.064±604370.461 OPS / s

显然,这是日志与之相比,基准正在做一些认真的工作折叠人,这是明智的。

结论

本教程专注于并展示了Java的微基准线束。

一如既往,可以找到代码示例在GitHub上

Java底部

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

>>查看课程
评论在本文上关闭!