参考:https://blog.csdn.net/agonie201218/article/details/122333354

1 简介

  JMHJava Microbenchmark Harness,JMH(Java Microbenchmark Harness)是用于代码微基准测试的工具套件,主要是基于方法层面的基准测试,精度可以达到纳秒级。

  该工具是由 Oracle 内部实现 JIT 的大牛们编写的,他们应该比任何人都了解 JIT 以及 JVM 对于基准测试的影响,测试结果可信度高。

  官网:https://openjdk.org/projects/code-tools/jmh/

2 应用场景

  当你定位到热点方法,希望进一步优化方法性能的时候,就可以使用 JMH 对优化的结果进行量化的分析。

  1)想准确地知道某个方法需要执行多长时间,以及执行时间和输入之间的相关性

  2)对比接口不同实现在给定条件下的吞吐量

  3)查看多少百分比的请求在多长时间内完成

3 基本使用

3.1 IDEA添加JMH插件

3.2 添加JMH依赖

<!--JMH-->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.23</version>
</dependency> <dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.23</version>
</dependency>

3.3 准备一个要测试的方法

public class JMHSample_01 {

    static List<Integer> nums = new ArrayList<>();
static {
Random r = new Random();
for (int i = 0; i < 10000; i++) nums.add(1000000 + r.nextInt(1000000));
} public static void foreach() {
nums.forEach(v->isPrime(v));
} public static boolean isPrime(int num) {
for(int i=2; i<=num/2; i++) {
if(num % i == 0) return false;
}
return true;
} }

3.4 在test下测试

public class JMHSample_01_test {

    @BenchmarkMode(Mode.AverageTime) // 指定mode为Mode.AverageTime
@Benchmark
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(2)
public void t(){
JMHSample_01.foreach();
} }

3.5 右键执行

3.5.1 可能出现的错误

打开Run-Edit Configuration → Environment Variables → include system environment viables

3.5.2 执行结果

4 相关注解介绍

4.1 @Benchmark

@Benchmark

  声明一个public方法为基准测试方法

4.2 @BenchmarkMode

@BenchmarkMode(Mode.AverageTime)

  通过JMH我们可以轻松的测试出某个接口的吞吐量、平均执行时间等指标的数据。

  假设我想测试平均耗时,那么可以使用@BenchmarkMode注解指定测试维度为Mode.AverageTime

  有一下几种模式:

    1)Throughput: 整体吞吐量,比如 QPS,单位时间内的调用量等;

    2)AverageTime: 平均耗时,指的是每次执行的平均时间。如果这个值很小不好辨认,可以把统计的单位时间调小一点;

    3)SampleTime: 随机取样,这和我们在第一课时里聊到的 TP 值是一个概念;

    4)SingleShotTime: 如果你想要测试仅仅一次的性能,比如第一次初始化花了多长时间,就可以使用这个参数,其实和传统的 main 方法没有什么区别;

    5)All: 所有的指标,都算一遍,你可以设置成这个参数看下效果。

4.3 @Measurement

@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)

  iterations:测试次数,注意,测试次数不是执行被测试方法的次数,每次测试会执行N次被测试方法

  time:每次测量的持续时间,timeUnit指定时间单位,本例中:每次测量持续1秒,1秒内执行的被测试方法的次数是不固定的,由方法执行耗时和time决定

4.4 @Warmup

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)

  为了数据准确,我们可能需要让被测试方法做下热身运动。jvm使用JIT即时编译器,一定的预热次数可让JIT对testGson方法的调用链路完成编译,去掉解释执行对测试结果的影响

  iterations:预热次数;

  time与timeUnit:每次预热的持续时间,timeUnit指定时间单位。

4.5 @Fork

@Fork(1)

  @Fork用于指定fork出多少个子进程来执行同一基准测试方法。

  fork 的值一般设置成 1,表示只使用一个进程进行测试;如果这个数字大于 1,表示会启用新的进程进行测试;但如果设置成 0,程序依然会运行,不过是这样是在用户的 JVM 进程上运行的,不推荐这么做

4.6 @Threads

@Threads(2)

  @Threads注解用于指定使用多少个线程来执行基准测试方法,如果使用@Threads指定线程数为2,那么每次测量都会创建两个线程来执行基准测试方法。

  如果@Measurement注解指定time为1s,基准测试方法的执行耗时为1s,那么如果只使用单个线程,一次测量只会执行一次基准测试方法,如果使用10个线程,一次测量就能执行10次基准测试方法。

4.7 @OutputTimeUnit

@OutputTimeUnit(TimeUnit.NANOSECONDS)

  OutputTimeUnit注解用于指定输出的方法执行耗时的单位。如果方法执行耗时为秒级别,为了便于 观察结果,我们可以使用@OutputTimeUnit指定输出的耗时时间单位为秒;如果方法执行耗时为毫秒级别,为了便于观察结果,我们可以使用@OutputTimeUnit指定输出的耗时时间单位为毫秒,否则使用默认的秒做单位,会输出10的负几次方这样的数字,不太直观。

4.8 @Group
  @Group 注解只能加在方法上,用来把测试方法进行归类。如果你单个测试文件中方法比较多,或者需要将其归类,则可以使用这个注解。

  与之关联的 @GroupThreads 注解,会在这个归类的基础上,再进行一些线程方面的设置。这两个注解都很少使用,除非是非常大的性能测试案例。

4.9 @State
  @State 指定了在类中变量的作用范围,用于声明某个类是一个“状态”,可以用 Scope 参数用来表示该状态的共享范围。这个注解必须加在类上,否则提示无法运行。

  Scope 有如下三种值:

  1)Benchmark :表示变量的作用范围是某个基准测试类。

  2)Thread :每个线程一份副本,如果配置了 Threads 注解,则每个 Thread 都拥有一份变量,它们互不影响。

  3)Group :联系上面的 @Group 注解,在同一个 Group 里,将会共享同一个变量实例

  在官方demo:JMHSample04DefaultState 测试文件中,演示了@Group的使用

4.10 @Setup 和 @TearDown

  和单元测试框架 JUnit 类似,@Setup 用于基准测试前的初始化动作,@TearDown 用于基准测试后的动作,来做一些全局的配置。

  这两个注解,同样有一个 Level 值,标明了方法运行的时机,它有三个取值。

  1)Trial :默认的级别,也就是 Benchmark 级别。

  2)Iteration :每次迭代都会运行。

  3)Invocation :每次方法调用都会运行,这个是粒度最细的。

  如果你的初始化操作,是和方法相关的,那最好使用 Invocation 级别。但大多数场景是一些全局的资源,比如一个 Spring 的 DAO,那么就使用默认的 Trial,只初始化一次就可以。

4.11 @Param
  @Param 注解只能修饰字段,用来测试不同的参数,对程序性能的影响。配合 @State注解,可以同时制定这些参数的执行范围。

4.12 @CompilerControl

  这可以说是一个非常有用的功能了。

  Java 中方法调用的开销是比较大的,尤其是在调用量非常大的情况下。拿简单的getter/setter 方法来说,这种方法在 Java 代码中大量存在。我们在访问的时候,就需要创建相应的栈帧,访问到需要的字段后,再弹出栈帧,恢复原程序的执行。

  如果能够把这些对象的访问和操作,纳入目标方法的调用范围之内,就少了一次方法调用,速度就能得到提升,这就是方法内联的概念。如下图所示,代码经过 JIT 编译之后,效率会有大的提升

这个注解可以用在类或者方法上,能够控制方法的编译行为,常用的有 3 种模式:

强制使用内联(INLINE),禁止使用内联(DONT_INLINE),甚至是禁止方法编译(EXCLUDE)等。

5 官方demo

http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

把官方demo的注解翻译后的demo

https://github.com/Childe-Chen/goodGoodStudy/tree/master/src/main/java/com/cxd/benchmark

6 结果输出形式

  使用 JMH 测试的结果,可以二次加工,进行图形化展示。结合图表数据,更加直观。通过运行时,指定输出的格式文件,即可获得相应格式的性能测试结果。

  比如下面这行代码,就是指定输出 JSON 格式的数据

Options opt = new OptionsBuilder()
.resultFormat(ResultFormatType.JSON)
.build();

  JMH 支持 5 种格式结果

  1)TEXT 导出文本文件。

  2)CSV 导出 csv 格式文件。

  3)SCSV 导出 scsv 等格式的文件。

  4)JSON 导出成 json 文件。

  5)LATEX 导出到 latex,一种基于 ΤΕΧ 的排版系统。

JMH测试工具的更多相关文章

  1. 渗透测试工具BurpSuite做网站的安全测试(基础版)

    渗透测试工具BurpSuite做网站的安全测试(基础版) 版权声明:本文为博主原创文章,未经博主允许不得转载. 学习网址: https://t0data.gitbooks.io/burpsuite/c ...

  2. linux压力测试工具stress

    最近给PASS平台添加autoscaling的功能,根据服务器的负载情况autoscaling,为了测试这项功能用到了stress这个压力测试工具,这个工具相当好用了.具体安装方式就不说了.记录下这个 ...

  3. [.NET] WebApi 生成帮助文档及顺便自动创建简单的测试工具

    ==========最终的效果图========== ==========下面开始干活:生成帮助文档========== 一.创建 WebApi 项目 二.找到 HelpPageConfig.cs 并 ...

  4. RabbitMQ调试与测试工具-v1.0.1 -提供下载测试与使用

    最近几天在看RabbitMQ,所以发了两天时间写了一个调试和测试工具.方便使用. 下载地址:RabbitMQTool-V1.0.1.zip

  5. HTTP压力测试工具

    HttpTest4Net是一款基于C#实现的和HTTP压力测试工具,通过工具可以简单地对HTTP服务进行一个压力测试.虽然VS.NET也集成了压力测试项目,但由于VS自身占用的资源导致了在配置不高的P ...

  6. 微软压力测试工具 web application stress

    转自 http://www.cnblogs.com/tonykan/p/3514749.html lbimba  铜牌会员 这里给广大的煤油推荐一个web网站压力测试工具.它可以用来模拟多个用户操作网 ...

  7. WebService如何调试及测试工具

    http://www.cnblogs.com/zfanlong1314/archive/2012/04/06/2434788.html 通常,我们在Visual Studio里调试ASP.NET网站, ...

  8. Android高手速成--第四部分 开发工具及测试工具

    第四部分 开发工具及测试工具 主要介绍和Android开发工具和测试工具相关的开源项目. 一.开发效率工具 Json2Java根据JSon数据自动生成对应的Java实体类,还支持Parcel.Gson ...

  9. Linux下四款Web服务器压力测试工具(http_load、webbench、ab、siege)介绍

    一.http_load程序非常小,解压后也不到100Khttp_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把 ...

  10. DNS压力测试工具dnsperf简介

    dnsperf是我最近写的一个开源的DNS压力测试工具,用户可以用它来对DNS服务器或者Local DNS做压力测试.dnsperf目前的实现是单进程模式,通过epoll非阻塞地处理网络事件. dns ...

随机推荐

  1. Python-OpenCV的安装及学习资料

    Conda环境安装 OpenCV pip install opencv-python opencv-contrib-python -i https://mirrors.aliyun.com/pypi/ ...

  2. 轻松玩转awk

    awk的处理方式 awk一次处理一行内容 awk对每行可以进行切片处理 例如 awk -F ':' '{print $1}' /etc/password -F指定每一行分割符号,这样就把被每行被:分割 ...

  3. 打印三位数的水仙花数Java

    public class Flower{ //水仙花数就是一个 个位数的立方+十位数的立方+百位数的立方=这个三位数 //153 = 1*1*1+5*5*5+3*3*3 public static v ...

  4. 【Shell案例】【wc、awk、cat、管道】1、统计文件的行数

    描述写一个 bash脚本以输出一个文本文件 nowcoder.txt中的行数示例:假设 nowcoder.txt 内容如下: #include <iostream> using names ...

  5. 【每日一题】【双指针/栈/reverse】2022年2月19日-判断是否为回文字符串

    给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文.如果是回文请返回true,否则返回false.   字符串回文指该字符串正序与其逆序逐字符一致.   数据范围:0 < n \l ...

  6. 【每日一题】【队列的实现类】【每层元素个数】2022年1月11日-NC15 求二叉树的层序遍历

    描述给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)例如:给定的二叉树是{3,9,20,#,#,15,7}, 注意:每一层上元素的个数 解答: import java.util ...

  7. 【每日一题】【List与Array互转】【工具类的使用】2021年12月10日-56. 合并区间

    以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] .请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入 ...

  8. linux常用命令精讲

    一.虚拟机三种网卡模式 1 桥接 相当于虚拟机和真机之间架了一座桥 2 NAT 虚拟系统借助 NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网(常用vm8) 3 仅主机 虚拟机和物理机在一 ...

  9. 来自一位十年.net研发老人的吐血整理:.Net技术栈-网址导航

    业余时间为什么整理这个? 内容聚合:不用一个一个搜索,我们很快可以进入常用技术官网 提高效率:多看官方文档可以最快,最准确的掌握相关的技术资讯,不用被一些没理解透或者有偏差的技术分享所带偏. 很多有经 ...

  10. 【FAQ】推送服务常见问题及解决方案

    一.推送成功收不到消息,推送返回:{"message":"success","requestID":"1523868*****28 ...