0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

gprofng如何幫助我們深入研究Java應(yīng)用程序的動(dòng)態(tài)行為?

安晟培半導(dǎo)體 ? 來(lái)源:安晟培半導(dǎo)體 ? 2024-02-21 16:06 ? 次閱讀

首先編寫(xiě)一個(gè)矩陣乘法程序(matrix multiplication program)。我寫(xiě)了一個(gè)完整的矩陣乘法程序,這比矩陣向量乘法(matrix-times-vector)要簡(jiǎn)單。主要有三種操作:

1

計(jì)算最內(nèi)層乘加操作(the inner-most multiply-add)

2

將乘加操作合并為結(jié)果中的單個(gè)元素

3

對(duì)最終結(jié)果的每個(gè)元素進(jìn)行迭代計(jì)算

我將矩陣乘法的計(jì)算過(guò)程放入一個(gè)簡(jiǎn)單的框架中,以便能夠重復(fù)地計(jì)算矩陣乘積,從而確保測(cè)量是可多次重復(fù)的(見(jiàn)附注 1)。該程序會(huì)在每次矩陣相乘開(kāi)始時(shí)(相對(duì)于 Java 虛擬機(jī)的啟動(dòng)時(shí)間)打印出信息,包括每次矩陣相乘所需的時(shí)間。我還運(yùn)行了一個(gè)測(cè)試,將兩個(gè) 8000x8000 的矩陣相乘,該框架會(huì)重復(fù)計(jì)算 11 次,并為了使后續(xù)不同行為的特征更突出,在每次重復(fù)之間設(shè)置休眠 920 毫秒:

$ numactl --cpunodebind=0 --membind=0 -- 
   java -XX:+UseParallelGC -Xms31g -Xmx31g -Xlog:gc -XX:-UsePerfData 
    MxV -m 8000 -n 8000 -r 11 -s 920

e6861e92-d08f-11ee-a297-92fbcf53809c.jpg

圖 1:矩陣乘法程序的運(yùn)行情況

第二次重復(fù)運(yùn)行的用時(shí)是第一次的 92%;到最后一次重復(fù)運(yùn)行時(shí),用時(shí)僅為第一次的 89%。執(zhí)行時(shí)間的變化證明了Java 程序需要一段預(yù)熱的時(shí)間。

那么問(wèn)題來(lái)了:能否用 gprofng 來(lái)分析第一次與最后一次重復(fù)運(yùn)行之間的差異,從而促進(jìn)性能提升?

為了回答這個(gè)問(wèn)題,我們可以運(yùn)行程序并讓 gprofng 收集有關(guān)運(yùn)行的信息。方法非常簡(jiǎn)單,只需在命令行中添加 gprofng 命令前綴,即可收集 gprofng 稱之為 “experiment” 的信息。

$ numactl --cpunodebind=0 --membind=0 -- 
   gprofng collect app 
     java -XX:+UseParallelGC -Xms31g -Xmx31g -Xlog:gc --XX:-UsePerfData 
       MxV -m 8000 -n 8000 -r 11 -s 920

e6abb47c-d08f-11ee-a297-92fbcf53809c.jpg

圖 2:在 gprofng 下運(yùn)行矩陣乘法程序

首先需要注意的是,與其它 profiling 工具一樣,gprofng 在收集 profiling 信息時(shí)也會(huì)為應(yīng)用程序帶來(lái)開(kāi)銷(overhead),好消息是,與不加 profiling 信息運(yùn)行相比,gprofng 所帶來(lái)的開(kāi)銷看起來(lái)并不顯著。

隨后,可以通過(guò) gprofng 深入了解整個(gè)應(yīng)用程序的時(shí)間消耗情況(見(jiàn)附注 2)。對(duì)于整個(gè)運(yùn)行過(guò)程,gprofng 顯示了24 個(gè)最耗時(shí)的函數(shù)調(diào)用,具體如下:

$ gprofng display text test.1.er -viewmode expert -limit 24 -functions

e6bed8e0-d08f-11ee-a297-92fbcf53809c.jpg

圖 3:Gprofng 展示了 24 個(gè)最耗時(shí)的函數(shù)調(diào)用

上面的函數(shù)視圖展示了每種方法的獨(dú)占 CPU 時(shí)間和總體 CPU 時(shí)間,均以秒為單位,并以總 CPU 時(shí)間的百分比表示。被命名的的函數(shù)是由 gprofng 生成的偽函數(shù)(pseudo function),其值為各種指標(biāo)的總和。從數(shù)據(jù)中可以看出,整個(gè)應(yīng)用程序消耗的總 CPU 時(shí)間為 1.201 秒。

其中,應(yīng)用程序中屬于 Matrix times Vector(MxV)類的方法占用了大部分 CPU 時(shí)間,但除此之外還有其它方法,如 JVM 的運(yùn)行時(shí)編譯器(Compilation::Compilation)和不屬于矩陣乘法的其他函數(shù)。此外,圖表在展示整體程序執(zhí)行情況的同時(shí),還捕捉到了分配(MxV.allocate)和初始化(MxV.initialize)的代碼。不過(guò),我對(duì)這些代碼不太感興趣,因?yàn)樗鼈兪菧y(cè)試框架的一部分,僅在啟動(dòng)期間使用,與矩陣乘法本身關(guān)聯(lián)不大。

gprofng 可以讓我專注在感興趣的應(yīng)用程序部分上。它有一個(gè)奇妙之處是,在收集實(shí)驗(yàn)之后,我可以使用過(guò)濾器來(lái)處理收集到的數(shù)據(jù)。例如,查看在特定時(shí)間間隔內(nèi)發(fā)生了什么,或者查看特定方法在調(diào)用棧(call stack)上的情況。為了演示和方便進(jìn)行過(guò)濾,我在程序中添加了 Thread.sleep(ms)的策略性調(diào)用,這樣可以更容易地基于相隔一秒的程序階段編寫(xiě)過(guò)濾器。這就是為什么在圖 1 的程序輸出中,即使每個(gè)矩陣相乘只花費(fèi)約 0.1 秒,但每次重復(fù)之間仍相隔約 1 秒的原因。

gprofng 支持編寫(xiě)腳本。我用它編寫(xiě)了一個(gè)腳本,用于從 gprofng 實(shí)驗(yàn)中提取不同秒數(shù)的數(shù)據(jù)。第一秒主要與 Java 虛擬機(jī)的啟動(dòng)相關(guān):

e6eef8d6-d08f-11ee-a297-92fbcf53809c.jpg

圖 4:篩選出第 1 秒內(nèi)最耗時(shí)的函數(shù)調(diào)用。為了能夠清楚地展示 JVM 的啟動(dòng)過(guò)程,我特意在矩陣乘法上制造了一些延遲。

即使應(yīng)用程序中的所有函數(shù)調(diào)用都尚未開(kāi)始運(yùn)行,運(yùn)行時(shí)編譯器(例如 Compilation::compile_java_method,占用了約 16% 的 CPU 時(shí)間)就已經(jīng)啟動(dòng)。(由于我插入了 sleep 調(diào)用,矩陣乘法調(diào)用被延遲了。)

第 1 秒之后,第 2 秒主要是分配函數(shù)和初始化函數(shù)的運(yùn)行,以及各種 JVM 函數(shù)的執(zhí)行。但此時(shí),矩陣乘法的任何代碼都尚未開(kāi)始執(zhí)行:

e707b010-d08f-11ee-a297-92fbcf53809c.jpg

圖 5:展示了第 2 秒內(nèi)最耗時(shí)的函數(shù)。矩陣的分配和初始化與 JVM 的啟動(dòng)互相競(jìng)爭(zhēng)。

此時(shí) JVM 啟動(dòng)以及數(shù)組的分配和初始化已完成。如圖 6 所示,第 3 秒是矩陣乘法代碼的第一次重復(fù)。但請(qǐng)注意,矩陣乘法代碼正在與 Java 運(yùn)行時(shí)編譯器爭(zhēng)奪機(jī)器資源(例如,圖 6 中的CompileBroker::invoke_compiler_on_method 占比 8%),這是由于矩陣乘法代碼耗時(shí)較多,這時(shí)仍在進(jìn)行編譯。

即便如此,矩陣乘法代碼(例如,在 MxV.main 方法中的“包含”時(shí)間占比 91%)占用了大部分 CPU 時(shí)間。包含時(shí)間顯示矩陣乘法(如 MxV.multiply)需要 0.100 CPU 秒,這與圖 2 中應(yīng)用程序報(bào)告的墻上時(shí)鐘一致。(收集和報(bào)告墻上時(shí)鐘需要一定的時(shí)間,但這不包括 gprofng 計(jì)算 MxV.multiply 方法所占用的 CPU 時(shí)間)。

e71dcefe-d08f-11ee-a297-92fbcf53809c.jpg

圖 6:第 3 秒內(nèi)最耗時(shí)的函數(shù),顯示了運(yùn)行時(shí)編譯器與矩陣乘法方法之間的資源競(jìng)爭(zhēng)。

在這個(gè)特定的示例中,矩陣乘法實(shí)際上并沒(méi)有參與爭(zhēng)奪 CPU 時(shí)間,因?yàn)闇y(cè)試是在具有大量空閑周期的多處理器系統(tǒng)上運(yùn)行,而運(yùn)行時(shí)編譯器則作為單獨(dú)的線程運(yùn)行。在某些特定的、受到限制的情況下,例如在負(fù)載較重的共享機(jī)器上,運(yùn)行時(shí)編譯器占用 8% 的時(shí)間可能會(huì)對(duì)整體性能造成影響。但另一方面,在運(yùn)行時(shí)編譯器上花費(fèi)時(shí)間會(huì)使得方法能夠更高效地執(zhí)行,因此,如果要計(jì)算多個(gè)矩陣乘法,我比較傾向于采取這種方法。

第 5 秒時(shí),矩陣乘法代碼就獨(dú)占了 Java 虛擬機(jī)的執(zhí)行時(shí)間:

e73f7cd4-d08f-11ee-a297-92fbcf53809c.jpg

圖 7:在第 5 秒內(nèi)運(yùn)行的所有函數(shù),只有矩陣乘法函數(shù)是活躍的。

請(qǐng)注意,MxV.oneCell、MxV.multiplyAdd 和 MxV.multiply 之間獨(dú)占 CPU 秒數(shù)的占比分別為60%、30% 和 10%。MxV.multiplyAdd 方法僅計(jì)算乘法和加法,但它是矩陣乘法中最內(nèi)層的方法。MxV.oneCell 方法有一個(gè)調(diào)用 MxV.multiplyAdd 的循環(huán),循環(huán)的開(kāi)銷和調(diào)用(評(píng)估條件和控制轉(zhuǎn)移)比 MxV.multiplyAdd 中的直接算術(shù)更加繁重(這種差異反映在兩者的獨(dú)占時(shí)間中,MxV.oneCell 為 0.060 CPU 秒,而 MxV.multiplyAdd 為 0.030 CPU 秒)。MxV.multiply 中的外層循環(huán)執(zhí)行頻率不夠高,以至于運(yùn)行時(shí)編譯器尚未對(duì)其進(jìn)行編譯,但該方法僅用了 0.010 CPU 秒。

矩陣乘法持續(xù)進(jìn)行到第 9 秒,此時(shí) JVM 運(yùn)行時(shí)編譯器再次啟動(dòng),我們發(fā)現(xiàn) MxV.multiply 已頻繁執(zhí)行,占用了較多的執(zhí)行時(shí)間:

e756b732-d08f-11ee-a297-92fbcf53809c.jpg

圖 8:第 9 秒內(nèi)最耗時(shí)的函數(shù),顯示運(yùn)行時(shí)編譯器已再次啟動(dòng)。

到最后一次重復(fù)之前,矩陣乘法代碼完全占用了Java 虛擬機(jī)的執(zhí)行資源:

e76cdd32-d08f-11ee-a297-92fbcf53809c.jpg

圖 9:矩陣相乘程序的最后一次重復(fù),展示了代碼在整個(gè)程序執(zhí)行結(jié)束時(shí)的最終配置。

結(jié) 論

我通過(guò)對(duì)運(yùn)行時(shí)的 Java 程序使用 gprong 進(jìn)行深入分析了解到了它的易用性。利用 gprofng 的過(guò)濾功能,我可以進(jìn)行時(shí)間片段檢查實(shí)驗(yàn),從而專注于自己感興趣的程序階段。例如,通過(guò)排除應(yīng)用程序的分配和初始化階段,并在運(yùn)行時(shí)編譯器工作時(shí)僅顯示一次程序重復(fù),我能夠清晰地觀察到熱代碼在編譯過(guò)程中性能不斷提升的情況。

附注

程序命令行的各個(gè)組成部分的原因解釋:

(1) numactl --cpunodebind=0 --membind=0 --

將 Java 虛擬機(jī)使用的內(nèi)存限制為一個(gè) NUMA 節(jié)點(diǎn)的內(nèi)核和內(nèi)存。將 JVM 限制在一個(gè)節(jié)點(diǎn),可以減少程序在運(yùn)行過(guò)程中的變化,使程序在運(yùn)行中的表現(xiàn)更加穩(wěn)定。

(2) java

所使用的是適用于 aarch64 架構(gòu)的 OpenJDK 版本 jdk-17.0.4.1。

(3)-XX:+UseParallelGC

啟用并行垃圾回收器(parallel garbage collector),它在所有可用回收器中執(zhí)行的后臺(tái)工作最少。

(4)-Xms31g -Xmx31g

提供足夠的 Java 對(duì)象內(nèi)存溢出(heap space),以確保不需要進(jìn)行垃圾回收。

(5)-Xlog:gc

記錄 GC 活動(dòng),以核實(shí)確實(shí)不需要進(jìn)行收集。(正如那句名言所說(shuō):“信任是必須的,但核實(shí)也是必要的?!保?/p>

(6)-XX:-UsePerfData

降低 Java 虛擬機(jī)的開(kāi)銷。

②gprofng 選項(xiàng)的原因:

(1) limit 24

僅顯示占用 CPU 時(shí)間最多的 24 個(gè)函數(shù)(并按獨(dú)占 CPU 時(shí)間進(jìn)行排序)。這使我能夠了解哪些函數(shù)幾乎不花費(fèi)時(shí)間,從而集中關(guān)注那些在程序執(zhí)行期間占用最多 CPU 時(shí)間的函數(shù)。后續(xù),我還將在某些情況下使用 limit 16,以便掌握哪些函數(shù)占用極少 CPU 時(shí)間。有時(shí) gprofng 工具本身也可能限制顯示的數(shù)量,因?yàn)椴⒉皇撬械暮瘮?shù)都能累計(jì)出大量的時(shí)間。

(2) viewmode expert

顯示所有累計(jì) CPU 時(shí)間的函數(shù),而不僅僅是 Java 函數(shù),還包括 JVM 本身固有的函數(shù),使用此標(biāo)記可以讓我查看運(yùn)行時(shí)編譯器函數(shù)等。




審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 多處理器
    +關(guān)注

    關(guān)注

    0

    文章

    22

    瀏覽量

    9034
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2982

    瀏覽量

    106316
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    159

    瀏覽量

    12420
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    954

    瀏覽量

    28792

原文標(biāo)題:技術(shù)文章 | Java 虛擬機(jī)的一天

文章出處:【微信號(hào):AmpereComputing,微信公眾號(hào):安晟培半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 0人收藏

    評(píng)論

    相關(guān)推薦

    [分享]超級(jí)經(jīng)典的JAVA基礎(chǔ)視頻推薦,還有很多牛人寫(xiě)的學(xué)習(xí)感受!值得深入研究

    超級(jí)經(jīng)典的JAVA基礎(chǔ)視頻推薦,還有很多牛人寫(xiě)的學(xué)習(xí)感受!值得深入研究 最近在網(wǎng)上看了一個(gè)視頻,從基礎(chǔ)入門(mén)開(kāi)始的,講得相當(dāng)不錯(cuò),很多牛人都把學(xué)習(xí)的感想發(fā)在那里了,對(duì)于初學(xué)JAVA
    發(fā)表于 08-28 17:36

    【Landzo C1試用體驗(yàn)】+第六篇 超聲波之深入研究

    看到Landzo C1自帶的超聲波模塊,研究了下 ,發(fā)現(xiàn)超聲波的發(fā)射芯片不知為何物,于是深入研究下,根據(jù)測(cè)試情況來(lái)看,初步斷定是個(gè)與非門(mén),因?yàn)樵诎l(fā)射的時(shí)候,電壓只有5V。既然不知道所用哪個(gè)芯片,網(wǎng)上
    發(fā)表于 07-12 19:13

    使用Eclipse WTP開(kāi)發(fā)Java Web應(yīng)用程序

    使用Eclipse WTP開(kāi)發(fā)Java Web應(yīng)用程序時(shí),我們需要在計(jì)算機(jī)中安裝tomcat才能執(zhí)行該應(yīng)用程序。如果在項(xiàng)目上使用Maven,則可以使用tomcat插件運(yùn)行嵌入式tomc
    發(fā)表于 12-16 07:00

    深入研究USBType-C技術(shù)的細(xì)節(jié)

    “USBType-C”并不是電子產(chǎn)品的新術(shù)語(yǔ),它已經(jīng)上市超過(guò)四年,你可能每天都在使用它。但是,這項(xiàng)技術(shù)對(duì)于工業(yè)自動(dòng)化領(lǐng)域來(lái)說(shuō),仍然是全新的解決方案。讓我們深入研究USB-C技術(shù)的細(xì)節(jié),優(yōu)勢(shì)和工業(yè)
    發(fā)表于 12-16 08:07

    深入研究徹底掌握設(shè)備樹(shù)

    這節(jié)主要講只想使用設(shè)備樹(shù)但是不想深入研究怎么辦,簡(jiǎn)單記錄一下,因?yàn)?b class='flag-5'>我們還是要深入研究徹底掌握設(shè)備樹(shù)的。如果沒(méi)有深入研究設(shè)備樹(shù),那么只能希望寫(xiě)驅(qū)動(dòng)程序
    發(fā)表于 02-17 07:05

    你能用任何測(cè)試代碼或其他步驟來(lái)幫助我測(cè)試我的應(yīng)用程序軟件嗎?

    我想通過(guò)重現(xiàn)導(dǎo)致 PLL 鎖定重置的場(chǎng)景來(lái)測(cè)試我的代碼。 我不確定如何重現(xiàn) PLL 鎖定重置。 你能用任何測(cè)試代碼或其他步驟來(lái)幫助我測(cè)試我的應(yīng)用程序軟件嗎?
    發(fā)表于 05-18 08:08

    linux的深入研究

    linux的深入研究
    發(fā)表于 03-28 09:46 ?17次下載

    java小應(yīng)用,java應(yīng)用程序下載

    Java小應(yīng)用: 2.1 所有小應(yīng)用程序的根源 2.2 小試身手 2.3 圖形操作 2.4 URL類 2.5 載入現(xiàn)有圖像文件 2.6 動(dòng)畫(huà)效果 2.7  播放聲音 2.8 小 
    發(fā)表于 04-28 14:20 ?0次下載

    模式匹配算法的深入研究

    模式匹配算法的深入研究:模式匹配算法的應(yīng)用較為廣泛, KMP算法是一種性能較高的算法,所以對(duì)KMP算法的深入研究能夠使模式匹配問(wèn)題得到較大的改善. 在匹配的過(guò)程中,從模式匹配算
    發(fā)表于 10-25 12:21 ?13次下載

    深入研究Servlet線程安全性問(wèn)題

    Servlet是Java Servlet的簡(jiǎn)稱,稱為小服務(wù)程序或服務(wù)連接器,用Java編寫(xiě)的服務(wù)器端程序,主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動(dòng)
    發(fā)表于 12-01 14:03 ?1979次閱讀
    <b class='flag-5'>深入研究</b>Servlet線程安全性問(wèn)題

    如何用Java代碼來(lái)創(chuàng)建iOS和Android應(yīng)用程序

    了解Multi-OS Engine(beta)如何幫助Java開(kāi)發(fā)人員快速創(chuàng)建iOS和Android應(yīng)用程序。
    的頭像 發(fā)表于 11-08 06:42 ?4314次閱讀

    深入研究電池的荷電狀態(tài)(SOC)和健康狀態(tài)(SOH)估計(jì)技術(shù)

    深入研究電池的荷電狀態(tài)(SOC)和健康狀態(tài)(SOH)估計(jì)技術(shù)
    發(fā)表于 06-02 15:09 ?12次下載
    <b class='flag-5'>深入研究</b>電池的荷電狀態(tài)(SOC)和健康狀態(tài)(SOH)估計(jì)技術(shù)

    1.6設(shè)備樹(shù)的引進(jìn)與體驗(yàn)——只想使用設(shè)備樹(shù)不想深入研究怎么辦

    這節(jié)主要講只想使用設(shè)備樹(shù)但是不想深入研究怎么辦,簡(jiǎn)單記錄一下,因?yàn)?b class='flag-5'>我們還是要深入研究徹底掌握設(shè)備樹(shù)的。如果沒(méi)有深入研究設(shè)備樹(shù),那么只能希望寫(xiě)驅(qū)動(dòng)程序
    發(fā)表于 12-22 19:00 ?5次下載
    1.6設(shè)備樹(shù)的引進(jìn)與體驗(yàn)——只想使用設(shè)備樹(shù)不想<b class='flag-5'>深入研究</b>怎么辦

    如何使用Tokio 和 Tracing模塊構(gòu)建異步的網(wǎng)絡(luò)應(yīng)用程序

    在 Rust 語(yǔ)言中,Tokio 是一個(gè)非常流行的異步運(yùn)行時(shí),它提供了高效的異步 I/O 操作和任務(wù)調(diào)度。而 Tracing 則是一個(gè)用于應(yīng)用程序跟蹤的框架,它可以幫助我們理解應(yīng)用程序行為
    的頭像 發(fā)表于 09-19 15:29 ?888次閱讀

    開(kāi)發(fā)java應(yīng)用程序的基本步驟是

    ava是一種面向?qū)ο蟮木幊陶Z(yǔ)言,廣泛用于開(kāi)發(fā)各種類型的應(yīng)用程序。在開(kāi)發(fā)Java應(yīng)用程序時(shí),有一些基本步驟需要遵循,以確保應(yīng)用程序的正確性和可靠性。 1.確定需求:這是開(kāi)發(fā)任何
    的頭像 發(fā)表于 11-28 16:52 ?1886次閱讀

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品