参考: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. 论文翻译:2022_DeepFilterNet2: Towards Real-Time Speech Enhancement On Embedded Devices For Fullband Audio

    博客地址:凌逆战 论文地址:DeepFilternet2: 面向嵌入式设备的全波段音频实时语音增强 论文代码:https://github.com/Rikorose/DeepFilterNet 引用格 ...

  2. (GCC) gcc编译选项 -Wl, -start-group,whole-archive,-Wl, Bstatic

    1. start-group 编译选项 假设程序x依赖三个静态库:libX1.a.libX2.a和libX3.a,而libX2.a又依赖libX1.a,libX3.a依赖libX2.a和libX1.a ...

  3. 【Devexpress】Gridcontrol列标题换行

    gridView1.OptionsView.AllowHtmlDrawHeaders = true; gridView1.ColumnPanelRowHeight = 35; GridColumn g ...

  4. ssm 乱码

    1.post乱码:在web.xml中增加解决解决post乱码的过滤器 <!--解决POST乱码问题--> <filter> <filter-name>Charact ...

  5. 【实时数仓】Day00:数据流程、课程内容、框架结构、知识点总结

    一.数据流程 1.离线数仓 2.实时数仓 二.课程内容 1.数据采集层(ODS) 2.DWD层与DIM层数据准备 3.DWM层业务实现 4.DWS层业务实现 5.ClickHouse 6.数据可视化接 ...

  6. CCS选择器 选择器优先级 选择器常见属性

    目录 CSS前戏 1.css语法结构 2.css注释语法 3.引入css的多种方式 CSS基本选择器 1.标签选择器 2.类选择器 3.id选择器 4.通用选择器 CSS组合选择器 1.后代选择器(空 ...

  7. Vue element 自定义表单验证(验证手机号)

    <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" ...

  8. 2、Java封装、继承与多态

    /** * 类.对象.面向过程.面向对象的理解: * 1.类:类是封装对象的属性和方法的载体 * * 2.对象:对象是类抽象出来的一个实例 * * 3.面向过程:面向过程注重的是具体的实现过程,因果关 ...

  9. 用云服务器搭建frp服务(超详细)

    初学.没有云服务器的时候总想着怎样才能让别人访问到自己的项目. 在查阅了百度,逛过了一些论坛之后,了解到了 内网穿透 这个词. 经过一番钻研,通过 手机 + KSWEB + 电脑 成功将内网服务映射出 ...

  10. python进阶之路3之数据类型

    内容概要 pycharm下载与使用 python语法之注释 python语法之变量与常量 python基本数据类型(先大致了解有哪些) pycharm下载与使用 1.该软件分为收费版和免费版 免费版本 ...