JMH基准性能测试工具用法

JMH我也是头次才知道,人家2013年就出来了,作为一个老程序员略感尴尬,一直奔波于项目开发并没有深究技术本身,这次也是在研究多线程锁的时候发现了JMH这个工具, JMH是Java Microbenchmark Harness的简称 ,我们平时写性能测试执行时长都是记录当前时间然后在减去执行完之后的当前时间,以此得出花费时间,这种方式实际上是非常不可靠的,因为java的代码在运行的时候编译器会对语法进行各种优化,而且每次JVM启动的时机都是会影响准确性的,因为进程在操作系统中也是有优先级的,真正的测试应该是在jvm执行的时候准确测试,这时候传统的时间测试就不可行,JMH的诞生就是解决这个问题

一般对代码测试我们会想知道什么呢?比如我这个方法在一秒钟能执行多少次,这个方法有几百人相当于几百个线程并发的时候的执行效率,这个方法一次执行的时间或者每次执行的时间,或者在百分之多少的概率下执行时长,TPS(吞吐量),OPS(每秒可操作次数)等等。

JMH就可以对一个方法的性能做到全方位的测试甚至精确到毫秒,微妙,纳秒级别,也可以用很多个线程去执行这个方法,甚至可以用@State注解对方法添加执行前后的钩子,下面就实际用代码演示以下

一、添加JMH Maven依赖

在pom文件中添加如下依赖,需要注意jmh-generator-annprocess的作用域设置为provided,不然可能会报 Unable to find the resource: /META-INF/BenchmarkList 的错误

<code>

<

dependency

>

<

groupId

>

org.openjdk.jmh

groupId

>

<

artifactId

>

jmh-core

artifactId

>

<

version

>

1.21

version

>

dependency

>

<

dependency

>

<

groupId

>

org.openjdk.jmh

groupId

>

<

artifactId

>

jmh-generator-annprocess

artifactId

>

<

version

>

1.21

version

>

<

scope

>

provided

scope

>

dependency

>

/<code>

二、编写简单的JMH测试类

这里写一个最简单的基准性能测试方法,用一个空方法来理解JMH的用法,首先在空方法上加入了@Benchmark注解,此注解表示那个方法用于基准测试。

然后在main方法中用配置项的方式配置基准测试的一些参数,默认的参数因为太大,测试起来比较慢,这里全部改为最小的,可以方便快速测试看结果。

<code>

package

jmh;

import

org.openjdk.jmh.annotations.Benchmark;

import

org.openjdk.jmh.runner.Runner;

import

org.openjdk.jmh.runner.RunnerException;

import

org.openjdk.jmh.runner.options.Options;

import

org.openjdk.jmh.runner.options.OptionsBuilder;

import

org.openjdk.jmh.runner.options.TimeValue;

public

class

SimpleBenchmark

{

public

void

testBenchMark

()

{ }

public

static

void

main

(String[] args)

throws

RunnerException

{ Options optionsBuilder=

new

OptionsBuilder() .include(SimpleBenchmark

.

class

.

getSimpleName

()) .

forks

(1) //设置

JVM

进程启动数量,多个进程可以减少对测试结果的影响 .

warmupIterations

(1) //预热次数 .

warmupTime

(

TimeValue

.

seconds

(1)) //预热时间 .

measurementIterations

(1) //基准测试次数 .

measurementTime

(

TimeValue

.

seconds

(1)) //基准测试时间 .

build

()

;

new

Runner(optionsBuilder).run(); } }/<code>

观察输出结果

可以看到JMH的一些版本信息以及JVM的一些信息,我们的基准测试配置信息都加了注释说明

<code> 
 
 
 
 
 
 
 
 
 
 
 
 
Iteration   1: 3892608771.297 ops/s
Result "jmh.SimpleBenchmark.testBenchMark":
  3892608771.297 ops/s
 
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. 

Use

profilers (see -prof, -lprof), design factorial experiments, perform baseline

and

negative tests that provide experimental control, make sure the benchmarking environment

is

safe

on

JVM/OS/HW

level

, ask

for

reviews

from

the

domain

experts.

Do

not

assume the numbers tell you what you want them

to

tell.

Benchmark

Mode

Cnt Score

Error

Units SimpleBenchmark.testBenchMark thrpt

3892608771.297

ops/s Process finished

with

exit

code

0

/<code>

三、采用注解的方式测试

下面的代码加入了JMH常用的一些注解用于测试,后面有注解的详细解释,这里的代码加了休眠2秒可以更方便呢观察测试结果。

<code>

package

jmh;

import

org.openjdk.jmh.annotations.*;

import

org.openjdk.jmh.runner.Runner;

import

org.openjdk.jmh.runner.RunnerException;

import

org.openjdk.jmh.runner.options.Options;

import

org.openjdk.jmh.runner.options.OptionsBuilder;

import

java.util.concurrent.TimeUnit;

import

java.util.concurrent.atomic.AtomicInteger; ({Mode.Throughput,Mode.AverageTime,Mode.SampleTime,Mode.SingleShotTime}) (TimeUnit.SECONDS)

public

class

MyBenchmark

{

static

AtomicInteger atomicInteger=

new

AtomicInteger(); (value =

0

) (iterations =

5

,time =

1

) (iterations =

5

,time =

1

) (value =

1

)

public

void

testMethod

(TestState testState)

throws

InterruptedException

{ testState.getInteger().incrementAndGet(); TimeUnit.MILLISECONDS.sleep(

2000

); atomicInteger.incrementAndGet(); } (Scope.Benchmark)

public

static

class

TestState

{

private

AtomicInteger integer; (Level.Trial)

public

void

setup

()

{ System.out.printf(

"benchmark前"

); } (Level.Trial)

public

void

tearDown

()

{ System.out.printf(

"benchmark后"

); }

public

AtomicInteger

getInteger

()

{

return

atomicInteger; } }

public

static

void

main

(String[] args)

throws

RunnerException

{ Options options=

new

OptionsBuilder() .include(MyBenchmark

.

class

.

getSimpleName

()) .

build

()

;

new

Runner(options).run(); } }/<code>

四、JMH注解介绍


JMH基准性能测试工具用法


五、输出测试结果

这里截图只看最终的结果,每个模式花费的时间都有说明,第一个是吞吐量,第二个平均时间,中间那些都是在采样百分之多少的时候花费的时间,因为我们休眠了2秒钟,所以大部分都是2秒一次的操作。

当然JMH远不止这些功能,更多高级的用法推荐大家看官方例子

JMH基准性能测试工具用法


分享到:


相關文章: