<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 業(yè)界動(dòng)態(tài) > Tencent JDK 國產(chǎn)化CPU架構支持分享

Tencent JDK 國產(chǎn)化CPU架構支持分享

作者: 時(shí)間:2020-09-09 來(lái)源:騰訊技術(shù)工程 收藏

GIAC(GLOBAL INTERNET ARCHITECTURE CONFERENCE)是長(cháng)期關(guān)注互聯(lián)網(wǎng)技術(shù)與架構的高可用架構技術(shù)社區和msup推出的,面向架構師、技術(shù)負責人及高端技術(shù)從業(yè)人員的年度技術(shù)架構大會(huì ),是中國地區規模最大的技術(shù)會(huì )議之一。

本文引用地址:http://dyxdggzs.com/article/202009/418153.htm

今年的第六屆GIAC大會(huì )上,在大數據架構進(jìn)化中的JAVA專(zhuān)題,騰訊高級工程師傅杰博士發(fā)表了《 支持分享》的主題演講。以下為嘉賓演講實(shí)錄:

尊敬的各位來(lái)賓,大家下午好!很高興有機會(huì )跟大家一起分享Tencent JDK 支持的話(huà)題。我是來(lái)自騰訊JVM團隊的jiefu(傅杰),在中科院計算所碩博連讀期間開(kāi)始從事OpenJDK的研發(fā)工作,目前是OpenJDK社區的committer。我曾就職于龍芯,是OpenJDK mips分支的核心開(kāi)發(fā)者,在龍芯上開(kāi)拓并實(shí)現了OpenJDK的C2編譯器。加入騰訊后,主要致力于KonaJDK在大數據和機器學(xué)習等領(lǐng)域的探索和實(shí)踐。

今天,我首先向大家簡(jiǎn)單介紹一下Tencent Kona JDK;隨后,詳細闡述JVM對國產(chǎn)CPU體系結構的支持;最后,和大家一起探討處理器內存模型對JVM實(shí)現的影響。

Tencent Kona JDK簡(jiǎn)介

99bfeaeddffa47608daf082a27e77188.png

Tencent Kona是騰訊基于OpenJDK研發(fā)的一款JDK產(chǎn)品,于2019年免費對外開(kāi)源,并提供長(cháng)期支持(LTS)。Kona的每個(gè)發(fā)布版本都經(jīng)過(guò)了騰訊云和內部實(shí)際生產(chǎn)環(huán)境的測試驗證,歡迎大家下載使用。

6a42bb6be9cc45b79d66526e78a34d1e.png

2020年3月JDK14發(fā)布時(shí),我司是國內有限的若干公司,進(jìn)入全球突出貢獻者/組織名單。OpenJDK全球貢獻者榜單是對全世界各個(gè)公司或個(gè)人對OpenJDK貢獻的權威統計,由Oracle在新版本JDK發(fā)布時(shí)對外公布。

騰訊的JVM團隊(含多位OpenJDK社區的 author/committer),專(zhuān)門(mén)負責Kona的研發(fā)和維護。僅最近半年時(shí)間,團隊已向OpenJDK社區貢獻了幾十個(gè)修復Bug的patch。同時(shí)鵝廠(chǎng)也將自身海量生產(chǎn)負載經(jīng)驗和前沿實(shí)踐,貢獻給OpenJDK社區。未來(lái),我們將以更加開(kāi)放的姿態(tài)積極擁抱開(kāi)源,并持續貢獻開(kāi)源。

JVM對國產(chǎn)CPU體系結構的支持

1d2fd924593b486da994fae3190b17e5.png

下面跟大家分享JVM對國產(chǎn)CPU體系結構支持的相關(guān)內容。國產(chǎn)處理器是我國發(fā)展信創(chuàng )產(chǎn)業(yè)的根基。目前,進(jìn)入官方名錄的國產(chǎn)處理器按架構可分為ARM、MIPS、Alpha和X86四大架構。其中,ARM以鯤鵬和飛騰為代表,MIPS以龍芯為代表,Alpha以申威為代表,X86則以兆芯和海光為代表。上述四種架構,除ARM和X86有OpenJDK社區支持外,MIPS和Alpha均無(wú)社區支持,全部需要自行開(kāi)發(fā)和維護。因此,掌握JVM對處理器支持的技術(shù),對于打破外國壟斷、促進(jìn)國產(chǎn)處理器持續健康發(fā)展具有十分重要的意義。

ac505c6b57fa4abfb5d7d21abb2cb5ad.png

OpenJDK的HotSpot虛擬機是全世界應用最廣的高性能Java虛擬機。從宏觀(guān)設計層面,HotSpot虛擬機可分為類(lèi)加載器、運行時(shí)、執行引擎和垃圾收集器四個(gè)模塊。其中,只有執行引擎和處理器體系結構密切相關(guān),其它三個(gè)模塊幾乎平臺無(wú)關(guān)(或僅部分與操作系統相關(guān),如運行時(shí)模塊)。JVM的執行引擎負責將Java字節碼轉換為處理器硬件支持的機器指令,故該模塊絕大部分與CPU相關(guān)。因此,JVM對處理器體系結構的支持,本質(zhì)上是要實(shí)現國產(chǎn)化處理器上的JVM執行引擎。那么,JVM的執行引擎在代碼層面又該如何落地實(shí)現呢?

a341c5b56a774e29893703ce97758c6f.png

這頁(yè)PPT的左邊部分展示了HotSpot虛擬機源代碼組織結構。按與底層硬件和操作系統的相關(guān)性,HotSpot源代碼分為cpu(處理器相關(guān))、os(操作系統相關(guān))、os_cpu(處理器和操作系統同時(shí)相關(guān))和share(平臺無(wú)關(guān))四個(gè)子目錄。PPT中間部分列舉了各個(gè)子目錄實(shí)現的主要功能,其中標黃色的部分為CPU體系結構相關(guān)部分。PPT右側以ARM的aarch64處理器架構為例,量化分析了JVM支持一款處理器架構所需的代碼量,其中CPU體系結構相關(guān)的代碼量約為64000行,剩余部分的代碼量約為70萬(wàn)行。故處理器體系結構支持所需的代碼占比小于8%。體系結構相關(guān)代碼主要包括匯編器、解釋器和編譯器后端。此外,由于Java語(yǔ)言原生支持多線(xiàn)程,故還需要處理器提供原子操作和內存屏障,以保證并發(fā)程序的正確性。下面我們將從匯編器、解釋器、編譯器、CPU原子操作和內存屏障這幾個(gè)方面逐一展開(kāi)。

匯編器是第一個(gè)需要實(shí)現的模塊,因為解釋器和編譯器的構造均依賴(lài)于匯編器提供接口。匯編器主要對處理器硬件進(jìn)行抽象和封裝,向上提供編程所需的寄存器和指令。匯編器是幾個(gè)模塊中功能最簡(jiǎn)單的。但從工程實(shí)現上看,由于現代處理器動(dòng)則支持幾千條指令,故匯編器的實(shí)現任務(wù)繁重,且指令格式和編碼稍有不慎很容易引入錯誤。因此,要求開(kāi)發(fā)人員熟悉處理器指令集,并且在編碼過(guò)程中務(wù)必小心謹慎。

匯編器完成后,緊接著(zhù)需要實(shí)現解釋器。問(wèn)大家一個(gè)問(wèn)題:能不能跳過(guò)解釋器,直接實(shí)現HotSpot虛擬機的編譯器?有人覺(jué)得解釋器性能太低,想剔除解釋器模塊,以減少JVM對支持的工作量。答案是否定的。HotSpot虛擬機必須依賴(lài)解釋器的功能。首先,對部分特殊的Java方法(如體積超大),編譯器會(huì )拒絕編譯,只能由解釋器解釋執行。其次,HotSpot的編譯器,尤其是C2編譯器,大量使用基于某些假設的激進(jìn)編譯優(yōu)化。但這些假設并不總是成立的,一旦失效,虛擬機需要由編譯執行回退到解釋器繼續執行。最后,在某些要求快速啟動(dòng)和響應的場(chǎng)景,直接解釋執行的可能會(huì )更優(yōu)于先編譯再執行。因此,對解釋器的構建和支持是必須的。

e645c5d94fee4517929040f82a601a5c.png

HotSpot的解釋器為基于模板的高性能解釋器。所謂的“模板”,即一段用于實(shí)現Java字節碼語(yǔ)義功能的匯編指令序列。這頁(yè)PPT展示了add方法被javac編譯為四條字節碼,然后再被解釋執行的過(guò)程。解釋執行,其實(shí)就是按程序的控制流,逐一執行字節碼對應模板中指令序列的過(guò)程。PPT的右邊展示了整數加法iadd字節碼的解釋器模板。上面黃色虛線(xiàn)框中的機器指令用于取操作數。下面黃色虛線(xiàn)框中的機器指令用于跳轉到下一個(gè)字節碼對應的模板繼續執行。中間的一條add加法指令用于實(shí)現iadd字節碼的語(yǔ)義。解釋器的模板都遵循一個(gè)固定模式,即先取操作數,然后執行,最后跳轉到下一個(gè)模板繼續運行。

解釋器調試成功之后,就可以開(kāi)始編譯器的支持了。編譯器支持難度最大,調試周期也最長(cháng)。HotSpot中設計了C1和C2兩款編譯器。C1編譯器編譯速度快,但生成的代碼質(zhì)量不高,適用于要求快速啟動(dòng)和響應的場(chǎng)景,因此又被稱(chēng)為client版編譯器。C2編譯器生成的代碼質(zhì)量高,但編譯速度慢,適用于需要長(cháng)期反復執行的服務(wù)類(lèi)應用,因此又被稱(chēng)為server版編譯器。相對于C1,C2采用了更多和更激進(jìn)的編譯優(yōu)化算法,故C2比C1更復雜。C1和C2的構造有許多相通之處,下面我們以復雜度更高的C2為例,向大家展示如何在JVM上實(shí)現一款支持新CPU架構的編譯器。

9c1bc2d1c86d4b338aa3df673deb78f2.png

這頁(yè)PPT展示了C2編譯器構造的原理。為了降低編譯器移植難度,C2被劃分為平臺無(wú)關(guān)和平臺相關(guān)兩個(gè)部分。平臺無(wú)關(guān)的代碼對所有處理器架構都適用,僅平臺相關(guān)部分的代碼需要對處理器架構進(jìn)行移植適配。進(jìn)一步地,為了減少人工編寫(xiě)平臺相關(guān)部分代碼的工作量,C2借助ADL編譯器來(lái)自動(dòng)生成處理器體系結構相關(guān)的代碼。ADL是Architecture Description Language的英文縮寫(xiě),是內嵌于OpenJDK開(kāi)源代碼中的體系結構描述語(yǔ)言。ADL編譯器通過(guò)解析體系結構描述文件(以*.ad為后綴的文件,例如aarch64.ad)來(lái)生成C2代碼。故在新處理器架構上支持C2的大部分工作,是正確編寫(xiě)處理器的體系結構描述文件。體系結構描述文件主要涉及寄存器描述、操作數描述和指令集描述三大方面的內容。

8caa070690244fc9a1d261d386e9b2d9.png

這頁(yè)PPT以Aarch64為例展示了寄存器描述的實(shí)例。寄存器描述通常包括通用寄存器、浮點(diǎn)寄存器和向量寄存器。為了兼容32位操作系統,寄存器描述時(shí)以32位長(cháng)度為基本描述單元。例如,PPT上半部分的R1和R1_H聯(lián)合起來(lái)表示64位的R1寄存器。PPT下半部分的V0、V_H、V_J和V_K聯(lián)合起來(lái)表示128位長(cháng)度的V0浮點(diǎn)寄存器。

c747d6acfad243348a77c3a6a41d6fb9.png

這頁(yè)PPT展示了操作數描述的實(shí)例。操作數描述處理器直接支持的數據種類(lèi),包括立即數操作數、寄存器操作數和存儲器操作數三大類(lèi)別。在每個(gè)大的類(lèi)別中,又會(huì )進(jìn)一步細分為字符型、整型、浮點(diǎn)型和指針等具體的子類(lèi)型。

42b009c9926646c18ac15ff186838c76.png

這頁(yè)PPT展示了指令描述的實(shí)例。需要提醒大家注意的是,指令描述不光描述處理器硬件支持哪些指令,同時(shí)還會(huì )影響C2編譯器的指令選擇和生成,從而影響編譯器性能。實(shí)際上,體系結構文件中的指令描述規定了如何用CPU的機器指令去匹配編譯器的中間代碼表示。PPT左側addI_reg_reg的指令描述,會(huì )匹配編譯器中間代碼表示的AddI節點(diǎn)及其操作數src1/src2,如PPT右圖所示。

寄存器、操作數和指令描述都完成后,JVM對CPU架構的支持已接近尾聲了。此時(shí),大家千萬(wàn)不要忘記了還有之前提到的CPU原子操作和內存屏障。如下頁(yè)PPT所示,HotSpot中定義了非常清晰的原子操作和內存屏障接口,大家只需根據處理器特性逐一實(shí)現即可。原子操作大家都很熟悉,那什么是內存屏障呢?下一節我會(huì )為大家詳細介紹。

處理器內存模型與JVM實(shí)現

下面跟大家一起探討處理器內存模型對JVM設計的影響。為什么將這個(gè)話(huà)題單列出來(lái)呢?多年的實(shí)踐經(jīng)驗告訴我們,JVM實(shí)現最考驗工程師水平的就是處理器內存模型與JVM的適配。這部分工作決定了虛擬機能否在處理器上穩定運行。希望能引起大家的重視。

處理器內存模型存在強弱之分。強內存模型以X86為代表;弱內存模型以ARM和PowerPC架構為代表。那么處理器內存模型的強弱是如何定義的呢?下面這張PPT展示了內存模型強弱劃分的依據:按處理器允許訪(fǎng)存指令重排序的多少來(lái)劃分。一般地,允許訪(fǎng)存指令重排序的情形越多,處理器內存模型越弱,反之越強。訪(fǎng)存指令分為讀(Load)和寫(xiě)(Store)兩種操作。因此,可能的重排序情形包括讀讀(Load/Load)、讀寫(xiě)(Load/Store)、寫(xiě)讀(Store/Load)和寫(xiě)寫(xiě)(Store/Store)重排序。X86架構處理器僅允許寫(xiě)讀(Store/Load)重排序,而ARM和PowerPC對上述四種重排序均允許。故X86通常被認為是強內存模型,而ARM和PowerPC被認為是弱內存模型。

7c81dc8ace5642f9b5f27c069f37dced.png

然而,我們在編程時(shí),尤其是a62ccc44a4944c72a4d74cd7dfd79d34.png在并發(fā)程序設計時(shí),可能需要禁止處理器的重排序行為。這時(shí)就需要借助處內存屏障來(lái)完成。所謂的“內存屏障”,是指處理器硬件支持的、專(zhuān)門(mén)用于禁止特定訪(fǎng)存指令重排序的機器指令。如下頁(yè)PPT所示,HotSpot虛擬機針對四種可能的重排序情形,提供了對應的內存屏障接口。例如,如果希望禁止X86處理器的寫(xiě)讀重排序,只需要調用OrderAccess::storeload()這個(gè)內存屏障接口即可。除了上述四種基本的接口外,虛擬機中還定義了acquire、release和fence接口。其中,acquire可禁止讀讀和讀寫(xiě)重排序,release可以禁止讀寫(xiě)和寫(xiě)寫(xiě)重排序,fence則禁止所有重排序。

9771ff11e33740e18c640d8564dc060b.png

編譯器在指令生成階段需充分適配處理器的內存模型特性。下面的PPT展示的是C2編譯器MemBarStoreStore中間節點(diǎn),在X86架構和Aarch64架構上目標代碼的生成情況。MemBarStoreStore中間節點(diǎn)的語(yǔ)義是禁止處理器的寫(xiě)寫(xiě)重排序。由于X86的內存模型不允許寫(xiě)寫(xiě)重排序,故該中間節點(diǎn)在X86架構上無(wú)需生成額外機器指令即可保證語(yǔ)義正確。而Aarch64架構處理器本身允許寫(xiě)寫(xiě)重排序,故需要額外生成一條寫(xiě)寫(xiě)的內存屏障才能正確實(shí)現該節點(diǎn)語(yǔ)義。一般地,弱內存模型架構通常需要生成更多的內存屏障。

cc71a65fe2744acfa7f7d13b0f0172d6.png

如果JVM對處理器訪(fǎng)存模型適配不當會(huì )發(fā)生什么呢?肯定會(huì )引起Bug。此類(lèi)Bug通常具有隨機性、位置發(fā)散和表象多樣等特點(diǎn),分析和調試難度很高。下面跟大家分享一個(gè)自己解決的OpenJDK訪(fǎng)存模型適配不正確的Bug(JDK-8229169)。這個(gè)Bug在jdk14中首先被修復,隨后也被backport到了jdk8和jdk11等LTS版本。

b3d3c2957da94a32842267dd7d092210.png

該Bug位于HotSpot垃圾收集框架的任務(wù)竊?。╳ork stealing)階段,影響除串行GC以外的所有垃圾收集器。Bug的機理是處理器在執行GenericTaskQueue::pop方法時(shí),對_age的兩次讀操作(見(jiàn)下頁(yè)PPT中黃色字體所示)被處理器亂序了。解決方法是在兩個(gè)讀操作之間添加讀讀內存屏障(PPT中綠色字體所示),以禁止處理器的讀讀亂序??赡苡腥藭?huì )問(wèn):由于X86處理器不允許讀讀亂序,故在X86上可以不用添加這個(gè)內存屏障,為何不采用PPT右下角的修改方式呢?這個(gè)問(wèn)題的正確答案是X86也需要添加OrderAccess::loadload()進(jìn)行修復。這是因為雖然X86在執行時(shí)不會(huì )對讀讀操作重排序,但是編譯器在編譯這段代碼時(shí)可能會(huì )發(fā)生重排。為了禁止代碼在編譯階段被重排序,X86也需要這個(gè)patch。從上述分析不難看出,JVM中的OrderAccess訪(fǎng)存屏障同時(shí)具備禁止處理器和編譯器重排序的功能。這一點(diǎn)請大家在今后的開(kāi)發(fā)過(guò)程中多多注意。

8b8e3b29354149a4b5b797b8ef04a604.png

以上就是我今天跟大家分享的內容。謝謝大家!另外,歡迎大家關(guān)注和star Tencent Kona JDK 8



關(guān)鍵詞: Tencent JDK 國產(chǎn)化 CPU架構

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>