PHP性能檢測工具介紹----XHProf

XHProf文件(草稿)

   

翻譯:徐仁祿 <xurenlu [at] gmail.com >

原文地址:http://mirror.facebook.net/facebook/xhprof/doc.html

初次翻譯,大部分是google translate tookit工具給翻的,稍微修改了下。如遇錯誤,還請來信指出。謝謝!

目錄

  1. 導言
  2. XHProf 概況
  3. 安裝XHProf擴展
  4. 使用XHProf進行性能分析
  5. 設置XHProf用戶界面
  6. 在生產環境中使用XHProf注意事項
  7. 輕量級採樣模式
  8. 附加功能
  9. 信賴
  10. 鳴謝
  1. 導言

XHProf是一個分層PHP性能分析工具。它報告函數級別的請求次數和各種指標,包括阻塞時間,CPU時間和內存使用情況。一個函數的開銷,可細分成調用者和被調用者的開銷。原始數據收集部分是用純C實現的,是一個名叫xhprof的 Zend擴展。XHProf有一個簡單的HTML的用戶界面( PHP寫成的)。基於瀏覽器的性能分析用戶界面能更容易查看,或是與同行們分享成果。也能繪製調用關係圖。

XHProf報告往往可以有助於理解被執行的代碼的結構。的等級性質的報告可用來確定,例如,什麼鏈要求導致了所謂的特殊功能得到。

XHProf可以比較兩次運行的結果(又名“差異報告”)或是從多次運行得到的彙總數據。差異和彙總報告,就像單一運行報告一樣,也提供“平板”以及“分層”的性能分析視圖。

XHProf是一種輕量級的性能分析工具。在數據收集階段,它記錄調用次數的追蹤和包容性的指標弧在動態 callgraph的一個程序。它獨有的數據計算的報告/後處理階段。在數據收集時,XHProfd通過檢測循環來處理遞歸的函數調用,並通過給遞歸調用 中每個深度的調用一個有用的命名來避開死循環。

XHProf的輕量級性質和匯聚功能,使得它非常適合用於收集“生產環境”的性能統計數據的統計。[見用於生產環境的補充說明。 ]


例如,XHProfLive (不屬於開源的工具包),是Facebook使用的一個全系統的性能監測系統,建立在XHProf的基礎之上 。 XHProfLive不斷收集函數級別的Profiler資料,這些資料來自生產環境中運行中的示例頁面[用xhprof來收集] 。然後XHProfLive彙總指定的時候,頁面類型,來取得各個頁面的性能數據,可以幫助解決各種問題,如:特定的某個網頁的函數級的性能情況怎樣?在所有網頁中,或者對某一具體的網頁,foo 函數的開銷如何?在過去的一小時/天/週中,哪些函數返回的次數最多?某個頁面/函數的執行時間的變化趨勢如何?等等。


由Facebook最初開發的XHProf在2009年3月開放源代碼。

  1. XHProf概況

XHProf提供的功能:

  • 扁平的性能概要截圖

提供函數級別的性能信息,例如調用次數,其中包括/獨家壁時間,內存使用情況,和CPU時間。

  • 分層剖析(父/子{0視圖){/0} ( 截圖

對每一個函數,它提供了一個斷點,個崩潰的要求和時間每母公司(來電)和兒童(被調用) ,如:

    • 哪些函數調用了指定的函數,各自調了多少次?
    • 一個特定的函數調用了哪些函數?
    • 在被一個特定的函數調用時,某個函數一共耗去了多少時間 。
  • 差異報告

出於各種原因,您可能需要比較從兩個XHProf運行中得到的數據-找出是什麼造成了從一個版本到另一個版本的退步,或是評估您將要做的優化的性能提升。

阿差異報告考慮兩分,作爲輸入,並提供兩個平面功能級別差異的信息,和層次信息(細目差異的父母/兒童職能)的每個功能。

差異報告裏的“平板”視圖指出了最主要的退步或改進。

點擊差異報告平板視圖中的函數,進入“層次”(或父/子)視圖。我們可以得到的具體的父子函數的差異。

  • Callgraph視圖

性能數據也可以通過callgraph視圖來查看 。callgraph 會高亮顯示程序的關鍵路徑。

  • 內存剖析

XHProf的內存剖析模式能有助於跟蹤那些申請大量內存的函數。

值得澄清的是,XHProfu並不嚴格跟蹤所有分配/釋放內存的操作。相反,它使用了一種簡化思路。他記錄了每個函數進入和結束後的內存的增減。它還記錄每個函數分配內存的峯值的變化。

  • XHProf記錄include, include_once, require and require_once require_once操作,就像他們是函數一樣。那些被包含文件的名字被用來產生假的函數的名字。
  • 術語表

1.        Inclusive Time (或子樹執行時間) :[包括子樹執行時間的所有執行時間。]

2.        Exclusive Time/Self Time :[函數執行本身的時間花費。]不包括子樹執行時間。

3.        Wall時間 :又名經過的時間或掛鐘時間。

4.        CPU時間 : CPU時間在用戶空間+ CPU時間在內核空間

  • 特殊函數的命名約定

0.        main():一個虛構的函數,這是所有調用的根節點。

1.        load::<filename> 和 run_init::<filename>:

XHProf 跟蹤PHP的include/require操作,和跟蹤函數調用一樣。

例如, include“lib/common.php"; 操作看起來像調了兩個XHProf函數:

  • load::lib/common.php - 內核加載和編譯文件的工作。[注:如果您使用的了PHP的opcode 緩存比如APC之類的,只有當緩存失效時纔會去編譯。
  • run_init::lib/common.php -由於包含操作引起的初始化操作等。

2.        foo@<n> :意味着這是一個foo()函數的遞歸調用。<n>代表遞歸深度。遞歸可能是直接的,(比如由於foo() -->foo() ) ,也可能是間接的(如由於foo()-> goo() ->foo()。

  • 限制

真正的層次剖析器會在每一個數據採集點記錄完全的調用堆棧。接下來,能夠回答這些問題,如:第三次foo()調用的開銷是多少?或是當調用棧是a()->b()->bar()時bar()函數的開銷是多少?

XHProf只記錄一級的調用上下文,因此只能回答關於一級一級函數調用的問題。事實證明,在實踐中這是最主要的利用情況。

爲了使這個更具體,看看下面的例子。

假設你有:

 1call from a() --> c()

 1call from b() --> c()

 50calls from c() --> d()

雖然XHProf可以告訴你, d()被c()調用了50次,卻不能告訴你,有多少次分別是由a()和b()引起的。[我們可以推測,也許有25次是因爲a(),有25次是由於b(), 但未必如此。 ]

然而在實踐中,這沒什麼大不了。

  1. 安裝XHProf擴展

這個擴展在"extension"子目錄裏。


注:Windows的版本還沒有實現。目前我們已經在Linux/FreeBSD 上測試了xhprof。

0.9.2及以上版本的XHProf也正計劃着移植到Mac OS下。[我們在Mac OS 10.5下測試過。]

注: XHProf使用RDTSC指令(時間戳計數器)來實現一個真正的低資源消耗的計數器[針對elapsedtime]。因此目前xhprof還只適用於x86架構。此外,因爲RDTSC的數據不能在CPU間同步,在剖析時xhprof會將程序綁定在單個的CPU。

如果SpeedStep技術是打開的,XHProf的基於RDTSC定時器的功能就不能正常工作了。這項技術在某些英特爾處理器上是可用的。[注:蘋果臺式機和筆記本電腦一般都將SpeedStep技術預設開啓。使用XHProf,您需要禁用SpeedStep技術。 ]


下面的步驟,應該在Linux/ Unix環境下進行。

% cd<xhprof_source_directory>/extension/
% phpize
% ./configure --with-php-config=<path tophp-config >
% make
% make install
% make test


php.ini文件 :您可以更新您的php.ini文件來自動加載您的擴展。將以下內容添加到你的php.ini文件。

[xhprof]

extension=xhprof.so

;

; directory used by default implementationof the iXHProfRuns

; interface (namely, the XHProfRuns_Defaultclass) for storing

; XHProf runs.

;

xhprof.output_dir=<directory_for_storing_xhprof_runs>


  1.   使用XHProf來做性能分析

用下面的示例程序來試着產生一些原始的性能數據:

foo.php

<?php
function bar($x) {
  if($x > 0) {
     bar($x - 1);
  }
}

function foo() {
  for($idx = 0; $idx < 2; $idx++ ) {
      bar($idx);
      $x = strlen("abc");
  }
}

// start profiling

xhprof_enable();

// run program

foo();

// stop profiler

$xhprof_data = xhprof_disable();

// display raw xhprof data for the profilerrun

print_r($xhprof_data);
 

運行上面的測試程序:

% php -dextension=xhprof.so foo.php

你應該得到的輸出如下:

Array
(
   [foo==>bar] => Array
       (
           [ct] => 2         # 2 calls tobar() from foo()
           [wt] => 27        # inclusivetime in bar() when called from foo()
       )

    [foo==>strlen]=> Array
       (
           [ct] => 2
           [wt] => 2
       )

   [bar==>bar@1] => Array    #a recursive call to bar()
       (
           [ct] => 1
           [wt] => 2
       )

   [main()==>foo] => Array
       (
           [ct] => 1
           [wt] => 74
       )

   [main()==>xhprof_disable] => Array
       (
           [ct] => 1
           [wt] => 0
       )

   [main()] => Array         #fake symbol representing root
       (
           [ct] => 1
           [wt] => 83
       )
)


注:The rawdata only contains "inclusive" metrics. For example, the wall timemetric in the raw data represents inclusive time in microsecs. Exclusive timesfor any function are computed during the analysis/reporting phase.

注意:默認情況下只有調用次數和佔用時間是記錄了的。您也可以選擇同時記錄CPU時間和/或單純記錄內存使用量。將下面這一行:

xhprof_enable();

換成:

xhprof_enable(XHPROF_FLAGS_CPU +XHPROF_FLAGS_MEMORY); ;

您應該得到如下的輸出:

Array
(
   [foo==>bar] => Array
       (
           [ct] => 2        # number ofcalls to bar() from foo()
           [wt] => 37       # time inbar() when called from foo()
           [cpu] => 0       # cpu time inbar() when called from foo()
           [mu] => 2208     # change inPHP memory usage in bar() when called from foo()
           [pmu] => 0       # change in PHP peak memory usage in bar()when called from foo()
       )

   [foo==>strlen] => Array
       (
           [ct] => 2
           [wt] => 3
           [cpu] => 0
           [mu] => 624
           [pmu] => 0
       )

   [bar==>bar@1] => Array
       (
           [ct] => 1
           [wt] => 2
           [cpu] => 0
           [mu] => 856
           [pmu] => 0
       )

   [main()==>foo] => Array
       (
           [ct] => 1
           [wt] => 104
           [cpu] => 0
           [mu] => 4168
           [pmu] => 0
       )

   [main()==>xhprof_disable] => Array
       (
           [ct] => 1
           [wt] => 1
           [cpu] => 0
           [mu] => 344
           [pmu] => 0
       )

   [main()] => Array
       (
           [ct] => 1
           [wt] => 139
           [cpu] => 0
           [mu] => 5936
           [pmu] => 0
       )
)


在分析時跳過內置函數

默認情況下, PHP的內置函數(如strlen )也被分析了。如果您不希望分析內置函數(爲了進一步減少性能分析的開銷貌相或減小產生的原始數據) ,您可以使用XHPROF_FLAGS_NO_BUILTINS標 志,例如:

// do not profile builtin functionsxhprof_enable(XHPROF_FLAGS_NO_BUILTINS ) ;

在性能分析時忽略特定函數( 0.9.2或更高版本支持)

從0.9.2版本的xhprof ,你可以告訴XHProf在性能分析時忽略一些指定函數。這樣,您就可以忽略,像功能用於間接函數調用,如call_user_func和call_user_func_array的函數 。這些不必要的中間層,因爲他們亂七八糟的父-子關係和間接的互相調用,使XHProf報告難以理解。

要設定要忽略的函數列表,可以在分析時給xhprof_enable函數 指定第二個參數[是個可選參數] 。例如,

// elapsed time profiling; ignorecall_user_func* during profiling

xhprof_enable(0,
            array('ignored_functions' => array('call_user_func', 'call_user_func_array')));
or,
 
// elapsed time + memory profiling; ignorecall_user_func* during profiling
xhprof_enable(XHPROF_FLAGS_MEMORY,
              array('ignored_functions' =>array('call_user_func','call_user_func_array')));

  1. 設置XHProf用戶界面

1.        PHP源碼目錄結構

XHProf的用戶界面的由PHP實現。代碼存放在兩個子目錄中:xhprof_html/和xhprof_lib/ 。

xhprof_html目錄包含了3個頂級PHP頁面。

  • index.php :查看一個單一運行或差異報告。
  • callgraph.php :以圖片的形式查看一次XHProf運行的調用關係圖。
  • typeahead.php :在XHProf的報告中被後臺調用來進行函數的自動補全。

該xhprof_lib目錄包含進行分析和顯示的支持代碼(計算 扁平的性能信息,計算diffs,從多次運行中彙總數據等等) 。

2.        Web服務器配置:您需要確保您的Web服務器有權限讀取xhprof_html/目錄可,並且能運行PHP腳本。

3.        管理XHProf運行

客戶端能很靈活地保存他們從XHProf運行中得到的XHProf原始數據。用戶界面層 的XHProf提供了一個iXHProfRuns接口(見xhprof_lib/ utils / xhprof_runs.php ),客戶端可以利用。這使得客戶端能夠告訴用戶界面層,如何獲取XHProf運行後產生的對應數據。

XHProf的UI 庫自帶的有一個基於文件的iXHProfRUns接口實現,即“ XHProfRuns_Default”(見xhprof_lib/utils/xhprof_runs.php)。這個自帶的實現將XHProf運行結果存在ini配置的xhprof.output_dir參數指定的某個目錄下。

一次XHProf運行,必須用一個命名空間和運行編號來唯一確定。

一)XHProf數據的永久保存

假設您使用的iXHProfRuns接口的XHProfRuns_Default這個默認實現方式,一個典型的XHProf運行並保存結果的操作可能就是這樣子的:

// start profiling

xhprof_enable();

 

// run program

....

 

// stop profiler

$xhprof_data = xhprof_disable();

 

//

// Saving the XHProf run

// using the default implementation ofiXHProfRuns.

//

include_once $XHPROF_ROOT ."/xhprof_lib/utils/xhprof_lib.php";

include_once $XHPROF_ROOT ."/xhprof_lib/utils/xhprof_runs.php";

 

$xhprof_runs = new XHProfRuns_Default();

 

// Save the run under a namespace"xhprof_foo".

//

// **NOTE**:

// By default save_run() will automaticallygenerate a unique

// run id for you. [You can override thatbehavior by passing

// a run id (optional arg) to thesave_run() method instead.]

//

$run_id =$xhprof_runs->save_run($xhprof_data, "xhprof_foo");

 

echo "---------------\n".

    "Assuming you have set up the http based UI for \n".

    "XHProf at some address, you can view run at \n".

    "http://<xhprof-ui-address >/index.php?run=$run_id&source=xhprof_foo\n".

    "---------------\n";


 

上述代碼就會將運行結果保存在xhprof.output_dir ini參數指定的特定目錄下。文件的名稱可能會是49bafaa3a3f66.xhprof_foo類似的東東 ;兩部分分別是運行編號( “ 49bafaa3a3f66 ” )和命名空間( “ xhprof_foo ” )。[如果您想創建/指定自己的run ID (如數據庫中的序列號,或時間戳) ,您可以通過明確的給save_run方法指定一個run id。

b )使用自己實現的iXHProfRuns

如果您希望您的XHProf運行存儲在不同的數據庫(例如用一個壓縮格式,或者其他什麼地方比如數據庫等),您需實現一個類,這個實必須實現iXHProfRuns ( )接口。

您還需要修改“xhprof_html/"目錄中3個主要的PHP入口文件(index.php,callgraph.php ,typeahead.php ),使用新的類而不是默認的類XHProfRuns_Default。改變3個文件的這一行:

$xhprof_runs_impl = new XHProfRuns_Default();

您還需要“include”聲明瞭上述class的文件。

4.        從用戶界面中訪問各次運行

一)看單一運行報告

要查看run id是<run_id>和命名空間是<namespace>的報告,訪問URL:

http://<xhprof-ui-address>/index.php?run=<run_id>&source=<namespace>

例如,

http://<xhprof-ui-address>/index.php?run=49bafaa3a3f66&source=xhprof_foo

二)查看diff報告

要查看命名空間<namespace>下runid分別是< run_id1>和<run_id2>的兩個報告,訪問URL:

http://<xhprof-ui-address>/index.php?run1=<run_id1>&run2=<run_id2>&source=<namespace>

三)彙總報告

您也可以指定一組run id來彙總得到您想要的報告視圖。

如果你有三個XHProf運行,都在"benchmark‘命名空間下,run id分別是1,2,3。要查看這些運行的彙總報告:

http://<xhprof-ui-address>/index.php?run=1,2,3&source=benchmark

加權彙總 :進一步假設,上述3個運特分別對應三種程序,p1.php,p2.php和p3.php ,通常以20%,30%,50%概率混合:要查看彙總報告所對應的加權平均數這些運行使用:

http://<xhprof-ui-address>/index.php?run=1,2,3&wts=20,30,50&source=benchmark

  1. 在生產環境中使用XHProf的注意事 項

這裏給出一些意見和準則。您的情況可能會有所不同:

  • CPU的計時器( getrusage )在Linux上開銷很大。爲了在函數級別更有用,這個是粗粒度的(毫秒精確度,而不是微秒水平)。因此,使用XHPROF_FLAGS_CPU模式時,在報告裏,數字上的誤差往往會更高。

我們建議在生產環境中使用"佔用時間+內存" 來做性能分析。[注:內存性能分析模式的額外開銷很低。 ]

 

// elapsed time profiling (default) +memory profiling

 xhprof_enable(XHPROF_FLAGS_MEMORY);

  • 對隨機抽樣的部分page/request來做性能分析,對於獲取您的生產環境的負載情況特徵數據,其實足夠好了了。

分析萬分之一的請求,可以用下面的代碼:

if (mt_rand(1, 10000) == 1) {

  xhprof_enable(XHPROF_FLAGS_MEMORY);

  $xhprof_on = true;

 }

request結束時(或是在退出函數中) ,您可以這麼做:

 if($xhprof_on) {

   // stop profiler

  $xhprof_data = xhprof_disable();

 

   //save $xhprof_data somewhere (say a central DB)

  ...

 }


然後,您就可以用xhprof_aggregate_runs()來按時間(比如,每5分鐘/每小時/每天),或是按頁面類型/request類型來彙總。

  1. 輕量級採樣模式

Xhprof擴展還提供了一個輕量級採樣模式。採樣間隔爲0.1秒。採樣記錄了整個函數調用堆棧。如果想以增加極低的負載作代價來進行性能監控和診斷,採樣模式就是你想要的。

XHProf擴展提供的與採樣模式相關的函數有xhprof_sample_enable()xhprof_sample_disable()

[ 待定:關於採樣模式更詳細的文檔。 ]

  1. 附加功能

xhprof_lib/utils/xhprof_lib.php文件包含額外的庫函數,可用於維護/彙總XHProf運行結果。

例如:

  • xhprof_aggregate_runs() :可用於多次XHProf運行結果彙總到一個單一的運行。這可以幫助您使用XHProf來建立一個全系統“的函數級別”的性能監測工具 。 [例如,您可以在生產環境中定期抽樣XHProf的數據,產生小時/日級別的報告。 ]
  • xhprof_prune_run() :彙總大量XHProf運行結果(特別是如果它們對應不同類型的程序)將可能導致callgraph規模變得太大。您可以使用xhprof_prune_run功 能來修剪的callgraph數據中只佔總運行時間中很小比例的子樹。
依賴性
  • JQuery的Javascript :在提示和函數名稱補齊上 ,我們利用了JQuery這個JavaScript庫。JQuery是基於MIT和GPL licencse ( http://docs.jquery.com/Licensing ) 的。XHProf用到的JQuery相關代碼,在xhprof_html/jquery子 目錄。
  • dot(圖像生成工具) :調用關係視圖工具( [查看Callgraph ] )這個功能依靠dot工具實現。 “點”是一種繪製/生成有向圖的工具。
  • 鳴謝

查詢分析結果的HTML用戶界面受到了Oracle 的存儲過程語言PL/SQL裏的一個相似的小工具的啓發。但是僅僅如此,他們的內部性能分析過程是完全不同的。


來源:百度文庫http://wenku.baidu.com/view/14a5a1f7ba0d4a7302763a4e.html

發佈了26 篇原創文章 · 獲贊 0 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章