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基準性能測試工具用法


分享到:


相關文章: