如果你想寫自己的Benchmark框架
簡介
使用過JMH的同學一定會驚歎它的神奇。JMH作為一個優秀的Benchmark框架帶給了我們無數的歡樂。作為一個有極客精神的程式設計師,那麼有沒有想過去自己實現一個Benchmark框架呢?
在實現Benchmark框架的時候有需要注意些什麼問題呢?快來一起看看吧。
八條軍規
這裡叫軍規實際上不合適,只是借用一下軍規的來彰顯一下氣勢!大家不要太介意。
第一條軍規
工欲善其事,必先利其器。想寫好一個JMH當然需要深入瞭解JVM的執行原理,包括JIT,C1,C2編譯器和他們的分層編譯原理,JIT執行時的編譯最佳化,包括Loop unrolling,Inlining,Dead Code Elimination,
Escape analysis,Intrinsics,Branch prediction等等。
當然,最好是參考一下大牛們寫過的JMH框架,找點靈感。
最後大家要了解,Benchmark框架不是萬能的。它只是在特定的環境中JVM的表現。
因為在Benchmark中我們肯定是要做迴圈的,一般來說就是某某方法執行多少次,這種比較簡單的迴圈。實際上,JVM執行的程式碼是非常複雜的。Benchmark遠遠不能代表JVM的全部。
但是,見微知著,使用Benchmark還是可以一窺JVM的秘密的。
第二條軍規
在JMH中,我們一般需要設定warmup和measurement的次數:
Warmup(iterations=10,time=1,timeUnit=TimeUnit.SECONDS)
Measurement(iterations=5,time=1,timeUnit=TimeUnit.SECONDS)
這是為什麼呢?我們知道JIT中的程式碼是動態編譯成為機器碼的,並且是需要一定的時間的。
只有JIT檢測到你這是熱點程式碼,才會對其進行最佳化。
我們檢測程式碼的效能,一般是指程式碼在穩定執行的環境中的情形。而不是指第一次或者前幾次執行的時候,因為這個時候,這些程式碼可能並沒有被編譯成機器碼。這樣的出來的結果往往是和實際不相符的。
第三條軍規
在編寫Benchmark的同時,一定要開啟JVM的日誌。例如:-XX:+PrintCompilation,-verbose:gc等。
為什麼呢?
大家想想benchmark是做什麼的呢?就是統計時間的。
我們希望在執行benchmark的時候,JVM不要做任何不屬於執行程式碼的任何事情,否則就可能會影響到benchmark的準確性。
所以開啟JVM的日誌就是為了做校驗。不要在做benchmark的時候有其他操作。
第四條軍規
注意JIT的分層編譯。
因為Client VM和Server VM的出現,所以在JIT中出現了兩種不同的編譯器,C1 for Client VM,C2 for Server VM。
因為javac的編譯只能做少量的最佳化,其實大量的動態最佳化是在JIT中做的。C2相對於C1,其最佳化的程度更深,更加激進。
為了更好的提升編譯效率,JVM在JDK7中引入了分層編譯Tiered compilation的概念。
對於JIT本身來說,動態編譯是需要佔用使用者記憶體空間的,有可能會造成較高的延遲。
對於Server伺服器來說,因為程式碼要服務很多個client,所以磨刀不誤砍柴工,短暫的延遲帶來永久的收益,聽起來是可以接受的。
Server端的JIT編譯也不是立馬進行的,它可能需要收集到足夠多的資訊之後,才進行編譯。
而對於Client來說,延遲帶來的效能影響就需要進行考慮了。和Server相比,它只進行了簡單的機器碼的編譯。
為了滿足不同層次的編譯需求,於是引入了分層編譯的概念。
大概來說分層編譯可以分為三層:
第一層就是禁用C1和C2編譯器,這個時候沒有JIT進行。
第二層就是隻開啟C1編譯器,因為C1編譯器只會進行一些簡單的JIT最佳化,所以這個可以應對常規情況。
第三層就是同時開啟C1和C2編譯器。
在JDK7中,你可以使用下面的命令來開啟分層編譯:
-XX:+TieredCompilation
而在JDK8之後,恭喜你,分層編譯已經是預設的選項了,不用再手動開啟。
Client編譯和Server編譯,甚至是OSR都是不同的。大家在寫Benchmark的時候一定要注意。
第五條軍規
注意初始化對效能的影響。
如果需要載入類,一定要在warmup的階段進行載入,除非你是想去測試載入的時間。否則會對測試結果有影響。
同時也不要計算第一次print的時間,因為print也會載入和初始化一些類。
第六條軍規
要注意反最佳化和重編譯的影響。
JIT在下面的幾個特殊的情況下,需要對程式碼進行返最佳化:
有些特殊的情況下面,確實是需要進行反最佳化的。
下面是比較常見的情況:
需要除錯的情況
如果程式碼正在進行單個步驟的除錯,那麼之前被編譯成為機器碼的程式碼需要反最佳化回來,從而能夠除錯。
程式碼廢棄的情況
當一個被編譯過的方法,因為種種原因不可用了,這個時候就需要將其反最佳化。
最佳化之前編譯的程式碼
有可能出現之前最佳化過的程式碼可能不夠完美,需要重新最佳化的情況,這種情況下同樣也需要進行反最佳化。
重編譯是指JIT可能會重新最佳化程式碼,導致重新編譯。
所以這條規則要求我們warmup的時間要儘可能的長。以便讓JIT充分最佳化。
第七條軍規
在使用benchMark得出結論之前,一定要去認真的理解JVM的底層程式碼(Assembly code),找到其現象的本質。
千萬不要衝動的下結論。最好是使用視覺化的工具來分析。比如說jitwatch。
最後一條軍規
在測試的時候一定要避免其他程式的影響。
比如說兩次測試,第一次測試是單機執行,第二次測試是在有其他服務正在執行的情況下進行的。
很顯然這兩次的結果是不能做比較的。我們需要多執行,剔除噪音結果。
總結
掌握上面幾條規則,相信大家也能夠寫出屬於自己的Benchmarks。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69976867/viewspace-2703874/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如果你想看牢騷話
- 手寫自己的MyBatis框架-SqlSessionMyBatis框架SQLSession
- 【翻譯轉載】如果你想要構建一套基於ECS的GUI框架GUI框架
- 為什麼我要寫自己的框架?框架
- 自己動手寫 PHP 框架(一)PHP框架
- 自己編寫Java Web框架:Takes框架的Web App架構JavaWeb框架APP架構
- 自己寫一個mvc框架吧(四)MVC框架
- 自己寫一個mvc框架吧(五)MVC框架
- 自己寫一個mvc框架吧(二)MVC框架
- 自己寫一個mvc框架吧(一)MVC框架
- 自己寫一個mvc框架吧(三)MVC框架
- 寫自己的CSS框架Part1:為什麼需要CSS框架CSS框架
- 如何寫一個自己的渣渣PHP框架(4)PHP框架
- PHP入門教程之編寫自己的PHP框架PHP框架
- 從零開始編寫自己的JavaScript框架(一)JavaScript框架
- 從零開始編寫自己的JavaScript框架(二)JavaScript框架
- 自己動手寫一個簡單的MVC框架MVC框架
- 自己動手寫一個持久層框架框架
- 中年黑客高考“回憶殺”:如果你想從事安全。。。黑客
- 想自己寫框架?不會寫Java註解可不行框架Java
- 自己動手寫Android資料庫框架Android資料庫框架
- 自己手寫一個SpringMVC框架(簡化)SpringMVC框架
- 自己動手寫DB資料庫框架(增)資料庫框架
- 手把手編寫自己的 PHP MVC 框架例項教程PHPMVC框架
- 嗯!我自己寫(東拼西湊)了個"框架"框架
- 自己動手寫Web自動化測試框架Web框架
- 自己動手寫Web自動化測試框架(7):框架架構的設計Web框架架構
- 淺析MyBatis(二):手寫一個自己的MyBatis簡單框架MyBatis框架
- 自己寫的面試題,自己想的答案面試題
- 自己寫的加密方式加密
- react如果你想為一個元件返回多個元素怎麼辦?React元件
- Python檢驗一個檔案是否存在,如果不在就自己填寫內容。Python
- 聽說2017你想寫前端?前端
- 構建自己的 PHP 框架PHP框架
- 自己的一個小框架框架
- 如果自學java,學多久可以自己找到工作?Java
- 模仿vue自己動手寫響應式框架(三) - dom解析Vue框架
- 自己動手寫Web自動化測試框架(1) :概述Web框架