JMH: 最裝逼钥组,最牛逼的基準(zhǔn)測試工具套件

JMH簡介

官網(wǎng):http://openjdk.java.net/projects/code-tools/jmh/

簡介:JMH is a Java harness for building, running, and analysing nano/micro/milli/macro benchmarks written in Java and other languages targetting the JVM鸵赫,由簡介可知掩浙,JMH不止能對Java語言做基準(zhǔn)測試谣妻,還能對運(yùn)行在JVM上的其他語言做基準(zhǔn)測試鳞滨。而且可以分析到納秒級別累盗。

推薦用法

官方推薦創(chuàng)建一個獨立的Maven工程來運(yùn)行JMH基準(zhǔn)測試寒矿,這樣更能確保結(jié)果的準(zhǔn)確性。當(dāng)然也可以在已存在的工程中若债,或者在IDE上運(yùn)行符相,但是越復(fù)雜,結(jié)果越不可靠(more complex and the results are less reliable)蠢琳。

簡單實用

推薦用法通過命令行創(chuàng)建啊终,構(gòu)建和運(yùn)行JMH基準(zhǔn)測試。

setup

生成一個新的JMH工程的maven命令如下:

 mvn archetype:generate 
 -DinteractiveMode=false 
 -DarchetypeGroupId=org.openjdk.jmh 
 -DarchetypeArtifactId=jmh-java-benchmark-archetype 
 -DgroupId=com.afei.jmh 
 -DartifactId=jmh 
 -Dversion=1.0.0-SNAPSHOT

執(zhí)行該命令后傲须,會創(chuàng)建一個Maven工程蓝牲,但是默認(rèn)生成的MyBenchmark.java并沒有在預(yù)期的包名com/afei/jmh中,即使加上參數(shù)-DpackageName=com.afei.jmh也不行泰讽,只能先手動將其挪到包名下例衍,這里作為一個小小的遺留問題。

壓測代碼

默認(rèn)生成的MyBenchmark.java源碼如下已卸,testMethod()中就是你要壓測的代碼佛玄,下面是筆者要壓測的洗牌算法:

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {

    @GenerateMicroBenchmark
    public List<Integer> testMethod() {
        int cardCount = 54;
        List<Integer> cardList = new ArrayList<Integer>();
        for (int i=0; i<cardCount; i++){
            cardList.add(i);
        }
        // 洗牌算法
        Random random = new Random();
        for (int i=0; i<cardCount; i++) {
            int rand = random.nextInt(cardCount);
            Collections.swap(cardList, i, rand);
        }
        return cardList;
    }

}

build

寫完代碼接下來就是構(gòu)建并打包,在pom.xml所在目錄執(zhí)行如下命令:

mvn clean package

說明:這一步咬最,也可以通過IDE工具構(gòu)建打包。

running

打包成功后在target目錄下生成了一個JAR文件:microbenchmarks.jar欠动,需要注意的是永乌,官網(wǎng)的運(yùn)行命令是java -jar target/benchmarks.jar,至于到底是benchmarks.jar還是microbenchmarks.jar具伍,取決于你的POM文件:

<configuration>
    <finalName>microbenchmarks</finalName>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>org.openjdk.jmh.Main</mainClass>
        </transformer>
    </transformers>
</configuration>

筆者生成的maven工程是microbenchmarks翅雏,所以,運(yùn)行時執(zhí)行如下命令:

java -jar target/microbenchmarks.jar

輸出結(jié)果如下:

# Run progress: 0.00% complete, ETA 00:00:10
# VM invoker: C:\Program Files\Java\jre1.8.0_181\bin\java.exe
# VM options: <none>
# Fork: 1 of 1
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.afei.jmh.MyBenchmark.testMethod
# Warmup Iteration   1: 1133.738 ns/op
# Warmup Iteration   2: 1169.750 ns/op
# Warmup Iteration   3: 1066.204 ns/op
# Warmup Iteration   4: 1086.300 ns/op
# Warmup Iteration   5: 1145.228 ns/op
Iteration   1: 1045.157 ns/op
Iteration   2: 1064.303 ns/op
Iteration   3: 1064.227 ns/op
Iteration   4: 1053.979 ns/op
Iteration   5: 1055.718 ns/op

Result : 1056.677  ±(99.9%) 30.809 ns/op
  Statistics: (min, avg, max) = (1045.157, 1056.677, 1064.303), stdev = 8.001
  Confidence interval (99.9%): [1025.868, 1087.486]

Benchmark                        Mode   Samples         Mean   Mean error    Units
c.a.j.MyBenchmark.testMethod     avgt         5     1056.677       30.809    ns/op

結(jié)果解讀

下面對輸出結(jié)果一些重要信息進(jìn)行解讀:

@Warmup

由于筆者加了這個注解:@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)人芽。所以望几,基準(zhǔn)測試后對代碼預(yù)熱總計5秒(迭代5次,每次1秒)萤厅。預(yù)熱對于壓測來說非常非常重要橄抹,如果沒有預(yù)熱過程靴迫,壓測結(jié)果會很不準(zhǔn)確。這個注解對應(yīng)的日志如下:

# Warmup Iteration   1: 1133.738 ns/op
# Warmup Iteration   2: 1169.750 ns/op
# Warmup Iteration   3: 1066.204 ns/op
# Warmup Iteration   4: 1086.300 ns/op
# Warmup Iteration   5: 1145.228 ns/op

@Measurement

另外一個重要的注解:@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)楼誓,表示循環(huán)運(yùn)行5次玉锌,總計5秒時間。

@Fork

這個注解表示fork多少個線程運(yùn)行基準(zhǔn)測試疟羹,如果@Fork(1)主守,那么就是一個線程,這時候就是同步模式榄融。

@BenchmarkMode&@OutputTimeUnit

基準(zhǔn)測試模式申明為:@BenchmarkMode(Mode.AverageTime)搭配@OutputTimeUnit(TimeUnit.NANOSECONDS)(可選基準(zhǔn)測試模式通過枚舉Mode得到)参淫,筆者的示例是AverageTime,即表示每次操作需要的平均時間愧杯,而OutputTimeUnit申明為納秒涎才,所以基準(zhǔn)測試單位是ns/op,即每次操作的納秒單位平均時間民效°疚基準(zhǔn)測試結(jié)果如下:

Result : 1056.677 ±(99.9%) 30.809 ns/op
  Statistics: (min, avg, max) = (1045.157, 1056.677, 1064.303), stdev = 8.001
  Confidence interval (99.9%): [1025.868, 1087.486]

最后一段結(jié)果如下,重點關(guān)注MeanUnits兩個字段畏邢,組合起來就是1227.928ns/op业扒,即每次操作耗時1056.677納秒:

Benchmark                        Mode   Samples         Mean   Mean error    Units
c.a.j.MyBenchmark.testMethod     avgt         5     1056.677       30.809    ns/op

如果我們將@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)的組合,改成@BenchmarkMode(Mode.Throughput)@OutputTimeUnit(TimeUnit.MILLISECONDS)舒萎,那么基準(zhǔn)測試結(jié)果就是每毫秒的吞吐量(即每毫秒多少次操作)程储,結(jié)果如下,表示943.437ops/ms:

Benchmark                        Mode   Samples         Mean   Mean error    Units
c.a.j.MyBenchmark.testMethod    thrpt         5      943.437       44.060   ops/ms

Mean error表示誤差臂寝,或者波動章鲤,與Result的±值對應(yīng):Result : 1056.677 ±(99.9%) 30.809 ns/op

基準(zhǔn)測試對比

將自定義洗牌算法和JDK原生的洗牌算法Collections.shuffle(cardList);進(jìn)行基準(zhǔn)測試對比咆贬,結(jié)果如下:

- ops/ms ns/op
JDK原生洗牌算法 807.470 1149.900
自定義洗牌算法(for循環(huán)外面new Random) 943.437 1056.677
自定義洗牌算法(for循環(huán)里面new Random) 300.467 3346.509

Random在for循環(huán)里面的源碼如下:

for (int i=0; i<cardCount; i++) {
    Random random = new Random();
    int rand = random.nextInt(cardCount);
    Collections.swap(cardList, i, rand);
}

說明败徊,自定義洗牌算法事實上就是JDK自帶洗牌算法中集合的size少于SHUFFLE_THRESHOLD(這個值為5)時的實現(xiàn)。另外掏缎,由基準(zhǔn)測試對比可知皱蹦,for循環(huán)里面不斷new Random的性能相比只在for循環(huán)外面new Random一次的性能要差好3倍左右。

另外眷蜈,在集合的size超過SHUFFLE_THRESHOLD即5后JDK原生洗牌算法沪哺,相比size少于該值得洗牌算法性能并沒有提高,兩者性能差在10%左右酌儒,基本可以忽略辜妓。這里想不明白,JDK原生洗牌算法在集合的size超過SHUFFLE_THRESHOLD的優(yōu)化的意思,當(dāng)然也可能跟筆者基準(zhǔn)測試樣本有關(guān)(畢竟筆者只測試了size為54的集合)籍滴。

JMH和jMeter的不同

JMH和jMeter的使用場景還是有很大的不同的酪夷,jMeter更多的是對rest api進(jìn)行壓測,而JMH關(guān)注的粒度更細(xì)异逐,它更多的是發(fā)現(xiàn)某塊性能槽點代碼捶索,然后對優(yōu)化方案進(jìn)行基準(zhǔn)測試對比。比如json序列化方案對比灰瞻,bean copy方案對比腥例,文中提高的洗牌算法對比等。

案例參考

官方給了很多樣例代碼酝润,有興趣的同學(xué)可以自己查詢并學(xué)習(xí)JMH:http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末燎竖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子要销,更是在濱河造成了極大的恐慌构回,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疏咐,死亡現(xiàn)場離奇詭異纤掸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)浑塞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門借跪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酌壕,你說我怎么就攤上這事掏愁。” “怎么了卵牍?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵果港,是天一觀的道長。 經(jīng)常有香客問我糊昙,道長辛掠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任释牺,我火速辦了婚禮萝衩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘船侧。我一直安慰自己欠气,他們只是感情好厅各,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布镜撩。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪袁梗。 梳的紋絲不亂的頭發(fā)上宜鸯,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機(jī)與錄音遮怜,去河邊找鬼淋袖。 笑死,一個胖子當(dāng)著我的面吹牛锯梁,可吹牛的內(nèi)容都是我干的即碗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼陌凳,長吁一口氣:“原來是場噩夢啊……” “哼剥懒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起合敦,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤初橘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后充岛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體保檐,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年崔梗,在試婚紗的時候發(fā)現(xiàn)自己被綠了夜只。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡炒俱,死狀恐怖盐肃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情权悟,我是刑警寧澤砸王,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站峦阁,受9級特大地震影響谦铃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜榔昔,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一驹闰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撒会,春花似錦嘹朗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春褪秀,著一層夾襖步出監(jiān)牢的瞬間蓄诽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工媒吗, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留仑氛,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓闸英,卻偏偏與公主長得像锯岖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子甫何,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理嚎莉,服務(wù)發(fā)現(xiàn),斷路器沛豌,智...
    卡卡羅2017閱讀 134,704評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,302評論 25 707
  • 1.炒股 不能追漲殺跌趋箩,一追漲就失去先手,買入成本價就比較高加派,沒有成本優(yōu)勢叫确。 一般來說追高買入,買入價會比較高芍锦,而...
    shanshukeng閱讀 364評論 0 0
  • 困啦竹勉,睡吧,又玩一晚上娄琉,花了28 大餐額 最得意的說 永紅要走了次乓,他們都要支教啦, 對了我居然問報教師資格證的人要...
    宋長金j閱讀 82評論 0 0
  • 有些人活成了自己生命的旁觀者。 成長的路上有一條彎路女气,叫活成了自己生命的旁觀者杏慰。 學(xué)習(xí)相同的心理學(xué)課程,有人飛快的...
    梓茗森林閱讀 279評論 0 0