首页 > 编程语言 >(笔记)JMH基准测试,不错的JAVA基准测试工具

(笔记)JMH基准测试,不错的JAVA基准测试工具

时间:2022-12-05 10:41:06浏览次数:60  
标签:调用 JAVA 基准 Benchmark jmh JMH 测试 测试工具 注解


测试JAVA中的方法的执行性能,比较稳妥合理的方法,是用JMH(​​https://openjdk.java.net/projects/code-tools/jmh/​​)

这个JAVA的测试工具。
1)MAVEN加入库:

 

<properties>
<jmh.version>1.21</jmh.version>
</properties>

<dependencies>
<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>
</dependency>
</dependencies>

2 下面是测试下JDK中一些常见的循环迭代等的性能例子,比如:
   

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Fork(value = 2, jvmArgs = {"-Xms2G", "-Xmx2G"})
//@Warmup(iterations = 3)
//@Measurement(iterations = 8)
public class BenchmarkLoop {

@Param({"10000000"})
private int N;

private List<String> DATA_FOR_TESTING;

public static void main(String[] args) throws RunnerException {

Options opt = new OptionsBuilder()
.include(BenchmarkLoop.class.getSimpleName())
.forks(1)
.build();

new Runner(opt).run();
}

@Setup
public void setup() {
DATA_FOR_TESTING = createData();
}

@Benchmark
public void loopFor(Blackhole bh) {
for (int i = 0; i < DATA_FOR_TESTING.size(); i++) {
String s = DATA_FOR_TESTING.get(i); //take out n consume, fair with foreach
bh.consume(s);
}
}

@Benchmark
public void loopWhile(Blackhole bh) {
int i = 0;
while (i < DATA_FOR_TESTING.size()) {
String s = DATA_FOR_TESTING.get(i);
bh.consume(s);
i++;
}
}

@Benchmark
public void loopForEach(Blackhole bh) {
for (String s : DATA_FOR_TESTING) {
bh.consume(s);
}
}

@Benchmark
public void loopIterator(Blackhole bh) {
Iterator<String> iterator = DATA_FOR_TESTING.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
bh.consume(s);
}
}

private List<String> createData() {
List<String> data = new ArrayList<>();
for (int i = 0; i < N; i++) {
data.add("Number : " + i);
}
return data;
}

}

下面讲解下相关的注解:

@BenchmarkMode

Mode 表示 JMH 进行 Benchmark 时所使用的模式。通常是测量的维度不同,或是测量的方式不同。目前 JMH 共有四种模式:

  1. Throughput: 整体吞吐量,例如“1秒内可以执行多少次调用”,单位是操作数/时间。
  2. AverageTime: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”,单位是时间/操作数。
  3. SampleTime: 随机取样,最后输出取样结果的分布,例如“99%的调用在xxx毫秒以内,99.99%的调用在xxx毫秒以内”
  4. SingleShotTime: 以上模式都是默认一次 iteration 是 1s,唯有 SingleShotTime 是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。

@OutputTimeUnit

输出的时间单位。

@Iteration

Iteration 是 JMH 进行测试的最小单位。在大部分模式下,一次 iteration 代表的是一秒,JMH 会在这一秒内不断调用需要 Benchmark 的方法,然后根据模式对其采样,计算吞吐量,计算平均执行时间等。

@WarmUp

Warmup 是指在实际进行 Benchmark 前先进行预热的行为。

为什么需要预热?因为 JVM 的 JIT 机制的存在,如果某个函数被调用多次之后,JVM 会尝试将其编译成为机器码从而提高执行速度。为了让 Benchmark 的结果更加接近真实情况就需要进行预热。

@State

类注解,JMH测试类必须使用 @State 注解,它定义了一个类实例的生命周期,可以类比 Spring Bean 的 Scope。由于 JMH 允许多线程同时执行测试,不同的选项含义如下:

  1. Scope.Thread:默认的 State,每个测试线程分配一个实例;
  2. Scope.Benchmark:所有测试线程共享一个实例,用于测试有状态实例在多线程共享下的性能;
  3. Scope.Group:每个线程组共享一个实例;

@Fork

进行 fork 的次数。如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试。

@Meansurement

提供真正的测试阶段参数。指定迭代的次数,每次迭代的运行时间和每次迭代测试调用的数量(通常使用 @BenchmarkMode(Mode.SingleShotTime) 测试一组操作的开销——而不使用循环)

@Setup

方法注解,会在执行 benchmark 之前被执行,正如其名,主要用于初始化。

@TearDown

方法注解,与@Setup 相对的,会在所有 benchmark 执行结束以后执行,主要用于资源的回收等。

@Setup/@TearDown注解使用Level参数来指定何时调用fixture:

名称

描述

 

Level.Trial

默认level。全部benchmark运行(一组迭代)之前/之后

 

Level.Iteration

一次迭代之前/之后(一组调用)

 

Level.Invocation

每个方法调用之前/之后(不推荐使用,除非你清楚这样做的目的)

 

@Benchmark

方法注解,表示该方法是需要进行 benchmark 的对象。

@Param

成员注解,可以用来指定某项参数的多种情况。特别适合用来测试一个函数在不同的参数输入的情况下的性能。@Param 注解接收一个String数组,在 @Setup 方法执行前转化为为对应的数据类型。多个 @Param 注解的成员之间是乘积关系,譬如有两个用 @Param 注解的字段,第一个有5个值,第二个字段有2个值,那么每个测试方法会跑5*2=10次。

 

测试类型

       前面提到测试的类型是吞吐量,也就是一秒钟调用完成的次数,但是如果想知道做一次需要多少时间该怎么办?

其实 1 / 吞吐量 就是这个值

       JMH 提供了以下几种类型进行支持:

类型

描述

Throughput

每段时间执行的次数,一般是秒

AverageTime

平均时间,每次操作的平均耗时

SampleTime

在测试中,随机进行采样执行的时间

SingleShotTime

在每次执行中计算耗时

All

顾名思义,所有模式,这个在内部测试中常用

也可以用MAVEN的方式运行:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>benchmarks</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
$ mvn package 

$ java -jar target\benchmarks.jar BenchmarkLoop

 运行后结果:

Benchmark                        (N)  Mode  Cnt   Score   Error  Units
BenchmarkLoop.loopFor 10000000 avgt 10 61.673 ± 1.251 ms/op
BenchmarkLoop.loopForEach 10000000 avgt 10 67.582 ± 1.034 ms/op
BenchmarkLoop.loopIterator 10000000 avgt 10 66.087 ± 1.534 ms/op
BenchmarkLoop.loopWhile 10000000 avgt 10 60.660 ± 0.279 ms/op

 可以看出其SCORE的分数了。

标签:调用,JAVA,基准,Benchmark,jmh,JMH,测试,测试工具,注解
From: https://blog.51cto.com/u_14230175/5911445

相关文章

  • 快速比较JAVA中两个集合是否相等
    有几个方法:1)如果是不在乎顺序,只要内容相同就可以认为相等,则:public<TextendsComparable<T>>booleanisEquals(List<T>list1,List<T>list2){if(list1==nul......
  • Java同步器之ReentrantLock源码分析(一)
    一、概述ReentrantLock是Java并发包中提供的一个可重入的互斥锁。ReentrantLock和synchronized在基本用法,行为语义上都是类似的,同样都具有可重入性。只不过相比原生的Sync......
  • 两道面试题,带你解析Java类加载机制
    在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题:classGrandpa{static{System.out.println("爷爷在静态代码块");}}classFatherextendsGra......
  • JAVA 解压缩代码写法
    packagecom.chinaunicom.asset.common.utils.compress;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.compress.archivers.ArchiveEntry;importorg.......
  • Java8新特性之方法引用
    1.1基本概念方法引用主要指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行。方法引用是在特定场景下lambda表达式的一种......
  • JavaScript入门⑤-欲罢不能的对象原型与继承-全网一般图文版
    JavaScript入门系列目录JavaScript入门①-基础知识筑基JavaScript入门②-函数(1)基础{浅出}JavaScript入门③-函数(2)原理{深入}执行上下文JavaScript入门④-万物皆......
  • 介绍一个不错的web测试工具webbench
    除了APACHE的AB工具外,发现linux下的一个工具webbench也很不错,传说能模拟3万个并发访问.下面介绍下安装1tarzxvfwebbench.tar.gz2make......
  • javascript中屏蔽esc键
     今天有客户说网页输入时,不小心按ESC键,结果把结果清除了,想屏蔽,其实是可以的,虽然要求怪怪,JAVASCRIPT可以实现:<scripttype="text/javascr......
  • jaxb中对java.util.Date的处理
    JAXB是个好东西,转换JAVAOBJECT到XML的,最近发现JAXB中对java.util.Date的转换有些要注意的地方,笔记之。比如有一个POJO如下:importjava.util.Date;p......
  • javascrpt 监听元素变化的两个API
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="viewport"c......