当前位置:网站首页 > 技术博客 > 正文

jvm检测工具




1.1 什么是基准测试

通过设计合理的测试方法,选用合适的测试工具和被测系统,实现对某个特定目的场景中某项性能指标进行定量的测试。

1.2 基准测试的前置准备

面对日益复杂的系统和不断增长的用户数,以及性能测试可能涉及到的多个业务系统,只有做到基准测试所涉及的业务场景、系统架构、测试环境等在可控状态下,才能得到相对准确的结果,为容量规划、缺陷定位、系统调优提供参考和依据。

在做基准测试之前,需要明确以下事宜:

  • 测试目的:明确测试的目的,测试什么?用什么测试方法、策略?
  • 测试环境:被测系统的环境是什么,SIT还是UAT或是PAT?
  • 测试限制:要执行测试有哪些限制因素,该如何解决?
  • 风险因素:测试可能存在哪些风险,解决方案是什么?
  • 结果分析:对测试结果如何分析?测试产生的数据如何分析、定位?

1.3 基准测试的意义

  • 为容量规划确定系统和应用程序的极限;
  • 为配置测试的参数和配置选项提供参考依据;
  • 为验收测试确定系统是否具备自己所宣称的能力;
  • 为性能基线的建立提供长期的数据统计来源以及比较基准;

2.1 JHM 介绍

JMH(Java Microbenchmark Harness)是Java用来做基准测试一个工具,该工具由openJDK提供并维护,精度可以达到纳秒级。该工具是由 Oracle 内部实现 JIT 的大牛们编写的,他们应该比任何人都了解 JIT 以及 JVM 对于基准测试的影响。

2.2 相关网站

  • JMH 官网
  • JMH 官方用例
  • JMH 官方用例 翻译

2.3 快速使用

2.3.1 加入Maven依赖

因为 JMH 是 JDK9 自带的,如果是 JDK9 之前的版本需要加入如下依赖

 
2.3.2 Hello, JMH!
 

小tips: 如果在IntelliJ IDEA中运行,必须使用RUN模式,DEBUG将会发生错误。

执行结果如下:

 

通过观察日志可以得出wellHelloThere()函数一秒可以执行.497(误差 ±.714)次。

3.1 测试模式

JMH中有四种测试模式,分别是Mode.Throughput、Mode.AverageTime、Mode.SampleTime和Mode.SingleShotTime。

名称描述Mode.Throughput计算吞吐量Mode.AverageTime计算平均运行时间Mode.SampleTime在测试中,随机进行采样执行的时间Mode.SingleShotTime测量单次操作的时间Mode.All所有模式依次运行
3.1.1 @BenchmarkMode

在测试方法上添加@BenchmarkMode注解可以指定多种测试模式。

 
3.2.2 OptionsBuilder::mode

OptionsBuilder中也有mode方法来添加指定的测试模式。

 

3.2 输出时间单位

JMH提供了两种方式来修改默认的输出时间单位。需要注意的是如果在一个测试中指定了多种测试模式,给定的时间单位将用于所有的测试。

3.2.1 @OutputTimeUnit

在测试方法上添加@BenchmarkMode注解可以设置时间单位,它需要一个标准Java类型java.util.concurrent.TimeUnit作为参数。

 
3.2.2 OptionsBuilder::timeout

OptionsBuilder中有timeout方法来添加指定的测试模式。

 

3.3 分支

默认JMH为每个试验(迭代集合)fork一个新的java进程。这样可以防止前面收集的“资料”——其他被加载类以及它们执行的信息对当前测试的影响。比如,实现了相同接口的两个类,测试它们的性能,那么第一个实现(目标测试类)可能比第二个快,因为JIT发现第二个实现类后就把第一个实现的直接方法调用替换为接口方法调用。

因此,不要把forks设为0,除非你清楚这样做的目的。

极少数情况下需要指定JVM分支数量时,使用@Fork对方法注解,就可以设置分支数量,预热(warmup)迭代数量和JVM分支的其他参数。

可能通过JMH API调用来指定JVM分支参数也有优势——可以使用一些JVM -XX:参数,通过JMH API访问不到它。这样就可以根据你的代码自动选择最佳的JVM设置(new Runner(opt).run()以简便的形式返回了所有的测试结果)。

3.3.1 @Fork
 
3.3.2 OptionsBuilder::forks
 

3.4 测试阶段其他配置

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

3.4.1 @Measurement
配置名称注解属性测量迭代次数@Measurement.iteration每次测量迭代的时长@Measurement.time每次测量迭代的时长单位@Measurement.timeUnit每次操作基准方法的调用数@Measurement.batchSize
3.4.2 OptionsBuilder::measurement*
配置名称对应方法测量迭代次数OptionsBuilder::measurementIterations()每次测量迭代的时长OptionsBuilder::measurementTime()每次测量迭代的时长单位OptionsBuilder::timeUnit()每次操作基准方法的调用数OptionsBuilder::measurementBatchSize()

3.5 预热阶段配置

3.5.1 @Warmup

与@Measurement相同,但是用于预热阶段

3.5.2 OptionsBuilder::warmup*

OptionsBuilder中有5个与@Warmup属性一一对应设置方法,分别为warmupTime(),warmupMode(),warmupIterations(),warmupBatchSize()和warmupForks()。

3.6 线程配置

JMH提供了设置运行基准测试的线程数的实现。

3.6.1 @Threads

该测试使用的线程数。默认是Runtime.getRuntime().availableProcessors()

3.6.2 OptionsBuilder::threads
 

3.7 测试参数

测试方法可以接收参数,这需要提供单个的参数类。

 

这个类必须遵循以下四条规则:

  • 有无参构造函数(默认构造函数)
  • 必须公共类
  • 如果是内部类,需要是静态内部类
  • 必须使用 @State 注解
3.7.1 测试参数状态

@State注解定义了给定类实例的可用范围。JMH可以在多线程同时运行的环境测试,因此需要选择正确的状态。

名称描述Scope.Thread默认状态。每个测试线程分配一个实例;Scope.Benchmark所有测试线程共享一个实例,用于测试有状态实例在多线程共享下的性能;Scope.Group每个线程组共享一个实例

除了将单独的参数类标记@State,也可以将你自己的benchmark类使用@State标记。上面所有的规则对这种情况也适用。

 
3.7.2 状态设置和清理

与JUnit测试类似,使用@Setup和@TearDown注解标记状态类的方法(这些方法在JMH文档中称为fixtures)。setup/teardown方法的数量是任意的。这些方法不会影响测试时间(但是Level.Invocation可能影响测量精度)。

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

名称描述Level.Trial默认level。全部benchmark运行(一组迭代)之前/之后Level.Iteration一次迭代之前/之后(一组调用)Level.Invocation每个方法调用之前/之后(不推荐使用,除非你清楚这样做的目的)

3.8 多参数的测试运行

很多情况下测试代码包含多个参数集合。幸运的是,要测试不同参数集合时JMH不会要求写多个测试方法。或者准确来说,测试参数是基本类型,基本包装类型或者String时,JMH提供了解决方法。

程序需要完成:

  • 定义@State对象
  • 在其中定义所有的参数字段
  • 每个字段都使用@Param注解

@Param注解使用String数组作为参数。这些字符串在任何@Setup方法被调用前转换为字段类型。然而,JMH文档中声称这些字段值在@Setup方法中不能被访问。

JMH使用所有@Param字段的输出结果。因此,如果第一个字段有2个参数,第二个字段有5个参数,测试将运行2 * 5 * Forks次。

 

[1] 《JMH - Java Microbenchmark Harness》.Jakob Jenkov. http://tutorials.jenkov.com/java-performance/jmh.html
[2] 《浅谈基准测试》.老_张(博客园).https://www.cnblogs.com/imyalost/p/9630843.html
[3] 《【基准测试】JMH 简单入门》.KIWI的碎碎念(博客园).https://www.cnblogs.com/kiwifly/p/11477153.html

官方用例: JMHSample_01_HelloWorld
官方用例: JMHSample_02_BenchmarkModes
官方用例: JMHSample_03_States
官方用例: JMHSample_04_DefaultState
官方用例: JMHSample_05_StateFixtures
官方用例: JMHSample_06_FixtureLevel
官方用例: JMHSample_07_FixtureLevelInvocation
官方用例: JMHSample_08_DeadCode
官方用例: JMHSample_09_Blackholes
官方用例: JMHSample_10_ConstantFold
官方用例: JMHSample_11_Loops
官方用例: JMHSample_12_Forking
官方用例: JMHSample_13_RunToRun
官方用例: JMHSample_15_Asymmetric
官方用例: JMHSample_16_CompilerControl
官方用例: JMHSample_17_SyncIterations
官方用例: JMHSample_18_Control
官方用例: JMHSample_20_Annotations
官方用例: JMHSample_21_ConsumeCPU
官方用例: JMHSample_22_FalseSharing
官方用例: JMHSample_23_AuxCounters
官方用例: JMHSample_24_Inheritance
官方用例: JMHSample_25_API_GA
官方用例: JMHSample_26_BatchSize
官方用例: JMHSample_27_Params
官方用例: JMHSample_28_BlackholeHelpers
官方用例: JMHSample_29_StatesDAG
官方用例: JMHSample_30_Interrupts
官方用例: JMHSample_31_InfraParams
官方用例: JMHSample_32_BulkWarmup
官方用例: JMHSample_33_SecurityManager
官方用例: JMHSample_34_SafeLooping
官方用例: JMHSample_35_Profilers
官方用例: JMHSample_36_BranchPrediction
官方用例: JMHSample_37_CacheAccess
官方用例: JMHSample_38_PerInvokeSetup

版权声明


相关文章:

  • 直流电机必须用l298n驱动吗2024-11-25 23:30:04
  • try again later云顶之弈2024-11-25 23:30:04
  • 服务器性能监控的主要内容2024-11-25 23:30:04
  • 微信小程序源码免费下载2024-11-25 23:30:04
  • k2p高恪固件评测2024-11-25 23:30:04
  • http的options2024-11-25 23:30:04
  • c语言中的scanf相当于c++中的什么2024-11-25 23:30:04
  • fork函数的作用2024-11-25 23:30:04
  • matlab求和∑函数例题2024-11-25 23:30:04
  • java中抽象类是什么2024-11-25 23:30:04