12.02 自己動手為 OpenJDK 加速

JIT(即時編譯)是個好東西,Java引領著整個行業。與HotSpot C2不同,JVM發行版僅針對操作系統和指令集架構優化,而C2會為特定操作系統(mac)、指令集(x86_64)和架構(Intel Broadwell)編譯和優化class文件。這種方案具備可移植性,同時減少了提交給供應商的build數量。


與Java程序一起運行的本地代碼非常重要,像C1編譯器和垃圾回收器。那麼問題來了,如果自己編譯OpenJDK,能否顯著提高提高應用程序吞吐量?答案似乎是肯定的。

自己動手為 OpenJDK 加速


構建JDK:

這裡用AdoptOpenJDKMac OpenJDK 13與自己定製的OpenJDK 13進行比較,兩者採用相同的33版本。以下是構建說明:

  • 克隆OpenJDK git鏡像
  • 檢出發行版33
  • 根據文檔運行bash configure。
bash configure --with-jvm-variants=server --with-jvm-features=link-time-opt \\
--with-extra-cflags='-Ofast -march=native -mtune=broadwell -funroll-loops -fomit-frame-pointer' \\
--with-extra-cxxflags='-Ofast -march=native -mtune=broadwell -funroll-loops -fomit-frame-pointer'

使用標準的server變量進行配置,其中包括jvm g1gc和c2功能。此外,還把link-time-opt加到構建中。關於這個功能沒有找到相關文檔,大致推測用來優化鏈接時間提高性能。現在考慮C和C++編譯優化。


-Ofast是clang和gcc支持的最高級別優化,使用時會有一些問題。二進制文件可能增大,而且浮點數語義檢查不那麼嚴格。用-O3能保持嚴格的浮點數一致性,或者用-O2保持二進制大小不變。我用Ofast和O3進行了測試,沒有遇到類似的問題,但你的情況可能不同。

-march=native和-mtune=broadwell通知編譯器針體系結構進行優化。有人根據編譯器文檔認為march代表了mtune,但是顯然並非如此。

-funroll-loops確保會執行循環展開。由於指定了march參數,循環展開效果應該非常明顯。Clang -O3選項包含循環展開,但必須為gcc手動設置。


-fomit-frame-pointer選項允許編譯器在可能的情況下忽略frame指針,進而釋放寄存器。但是這可能會給調試JVM本機代碼帶來麻煩。

  • 執行下面命令製作jdk:
make images CONF=macosx-x86_64-server-release


儘管開啟了優化,在2015年的Macbook上完成構建也只需要約15分鐘。

  • 可以在build/macosx-x86_64-server-release/images/jdk-bundled下找到jdk,加入PATH就可以開始測試了。


基準測試:

DaCapo是運行的第一個測試集。

自己動手為 OpenJDK 加速

優化後的JDK在每種情況下都表現出色,使用-Ofast後,avrora和fop測試結果獲得了極大的速度提升。很好奇為什麼會有這樣的結果!

接下來運行了計算機語言基準測試遊戲中的一些測試。

自己動手為 OpenJDK 加速

執行time for i in {1..10}; do java <class>; done,然後除以10。這一次,JDK的表示沒有明顯的差異。與DaCapo不同,這些基準不能代表正常的工作量,參考價值較低。例如,這些基準測試不會產生垃圾或者使用JVM功能(C2除外),但是我們知道優化並不會給C2和啟動帶來好處。/<class>

最後,對Netty的HttpObjectEncoder進行了若干JMH微基準測試:


自己動手為 OpenJDK 加速

在查看了Netty測試集後,我隨機選擇了這個微基準測試。當內存分配沒有用到pool且不返回void Promise時,加速效果顯著,其他情況下速度也有很大提升。當然,這些方法不太可能主導應用程序的性能。第二個基準測試似乎出現了小故障。

注意:Netty也支持Native Transport,如果可以最好也對它進行編譯!


其他編譯器和與作系統:

我還嘗試了用Intel的編譯器構建,並且完善了configure腳本提供支持。但是,這次構建神秘地失敗了。當然,我也想看看在Linux上的結果。


總結:

儘管最後還是需要用自己的應用程序進行測試,但很明顯,為JDK指定體系結構可以顯著提高應用吞吐量。既然構建JDK這麼方便(Skara項目真的很棒),性能關鍵型Java應用程序的開發者應該認真考慮構建一個優化的JDK,就像C/C++開發者優化二進制文件那樣。


測試結果:


自己動手為 OpenJDK 加速


自己動手為 OpenJDK 加速


自己動手為 OpenJDK 加速


結語:

以上就是本文的全部內容了,大家如果覺得不錯,記得點一波關注,我不確定這種方法是否有問題,有不足還請大家在評論區中不吝賜教了。


分享到:


相關文章: