Java FlameGraph 火焰圖

上週一個偶然的機會聽同事提到了Java FlameGraph,剛實驗了一下,效果很是好。html

1、什麼是FlameGraphjava

直接看圖說話。FlameGraph 是 SVG格式,矢量圖,能夠隨意擴大縮小,看不清的信息能夠放大看。圖中,各類紅橙黃色沒有什麼意義,僅僅作區分用;x軸橫條寬度來度量時間指標,代表每一個接口實際佔用的CPU時間;y軸表明線程棧的層次,從最底下往上表示堆棧的層層調用。經過看圖,能夠發現哪一個接口占用的CPU時間較多,從而優化;同時,能夠發現調用關係。git

 

Java火焰圖的做者是Brendan Gregg,他的博客很是有意思,不少關於性能的分析。如下連接是對每一個類別的火焰圖的詳細說明。github

什麼是Java Flame Graphs:Java Flame Graphs瀏覽器

On-CPU:CPU Flame Graphsjvm

Off-CPU:Off-CPU Flame Graphside

Memory:Memory Leak (and Growth) Flame Graphssvg

Hot/Cold:Hot/Cold Flame Graphs函數

Differential:Differential Flame Graphs工具

關於火焰圖的PPT(講解得很是詳細):Blazing Performance with Flame Graphs

 

2、如何生成

兩個步驟:1. 須要java profiler生成trace文件  2. 將trace文件轉換爲svg格式的火焰圖文件。

1. 須要java profiler生成trace文件

在使用Profiler對CPU進行採樣時,根據CPU當前執行所處棧位置以及各個函數棧在總的採樣次數所佔比例就能夠得出各個函數執行時的CPU佔用比例。經常使用的是lightweight-java-profiler。還有其餘的選擇,好比honest-profiler,lightweight-java-profiler會從java虛擬機啓動開始採樣,而有時候咱們須要在CPU飆高的時候開始,這時候honest-profiler提供的動態啓停功能就有用武之地了。也有使用perf生成火焰圖。(*perf 要研究一下)

下面以lightweight-java-profiler 舉例

(1) 從github下載軟件

(2) 編譯 make all

(3) 生成的程序存放在build-64文件夾下面

(4)(可選)能夠更改一些lightweight-java-profiler的一些選項,打開src/globals.h文件。在長時間採樣時,能夠適當地減小每秒採樣次數,否則最終生成的文件會很大,分析起來比較麻煩。

// 每秒採樣頻率
static const int kNumInterrupts = 100;
// Maximum number of stack traces線程棧個數
static const int kMaxStackTraces = 3000;
// 採樣棧深度
static const int kMaxFramesToCapture = 128;  

  kNumInterrupts: 每秒鐘抽取樣本的次數;

  kMaxStackTraces: 線程棧的最大數量   

  kMaxFramesToCapture: 線程棧的深度

 

(5)運行Java程序

  java -agentpath:path/to/liblagent.so ......

(6)java程序啓動後會在當前目錄生成一個traces.txt文件,但文件中只有一些說明信息。程序正常結束(不殺掉進程)後,纔會寫入具體採樣信息。

 

2.將trace文件轉換爲svg格式的火焰圖文件。

(1)從github下載FlameGraph

(2)轉換 

  ./stackcollapse-ljp.awk < traces.txt | ./flamegraph.pl > traces.svg
(3)瀏覽器中打開traces.svg文件
 
 
 
3、簡單討論一下Java profiler
 
關於採樣工具的選取,能夠看看文章 Evaluating the Accuracy of Java Profilers ,這裏面列舉了xprof,hprof,jprofile和yourkit四種採樣器,並經過幾個壓測場景證實了這幾種採樣器的結果是相互矛盾的。總結的緣由有兩點:
1. 採樣器採樣點不夠隨機,這幾種採樣器都只有在safe point採樣;
2. 不一樣的採樣器會注入不一樣的代碼,從而影響程序優化過程,同時也影響了safe point的分佈,進一步形成採樣差別;
honest-profiler號稱是避開了經過SUN/Oracle management agent去採樣堆棧,而是使用本身實現的使用UNIX 操做系統信號和爲Oracle Performance Studio 設計的內部API的sampling agent,從而提高了採樣準確率。
 
還有一篇文章和 Why many profilers have serous problems。
 
Java profiler 的兩個常見方式:
1.修改代碼,從而實現採樣。問題是:1. 增長開銷;2. 修改了你的代碼,致使java編譯器的優化行爲不肯定;3. 影響了代碼的層次,層次越深天然也影響 執行效率。
2.經過獲取on-cpu線程的線程棧方式。問題是:獲取系統範圍的線程棧,jvm必須處於safepoint狀態(看文章What is Java safepoint)。只有當線程處於safepoint狀態的時候,別的線程才能去獲取它的線程棧,而這個safepoint是由jvm 控制的,這對於profiler很是不利,有可能一個很熱的代碼塊,jvm不會在該代碼塊中間放置safepoint,致使profiler沒法得到該線程棧,致使錯誤的profiler結果。

幾個商用的profiler工具都存在上述問題。可是,Oracle Solaris studio利用的是jvmti的一個非標準接口AsyncGetCallTrace來實現,不存在上面問題,Jeremy Manson也利用該接口 實現了一個簡單的profiler工具:lightweight-java-profiler。

 

 
 
 
相關知識:
 部份內容摘自 http://blog.csdn.net/c395318621/article/details/55224665
 部份內容摘自 http://tacy.github.io/blog/2014/07/16/FlameGraph/
 部份內容摘自 http://www.javashuo.com/content/p-6579579.html
 部份內容摘自 http://colobu.com/2016/08/10/Java-Flame-Graphs/
 文章: Evaluating the Accuracy of Java Profilers  
 文章: Why many profilers have serous problems。
 文章: What is Java safepoint
相關文章
相關標籤/搜索