perf-應用程序的調優與使用

  
    Perf 是用來進行軟件性能分析的工具。    通過它,應用程序可以利用 PMU,tracepoint 和內核中的特殊計數器來進行性能統計。它不但可以分析指定應用程序的性能問題 (per thread),也可以用來分析內核的性能問題,當然也可以同時分析應用代碼和內核,從而全面理解應用程序中的性能瓶頸。
    使用 perf,您可以分析程序運行期間發生的硬件事件,比如 instructions retired ,processor clock cycles 等;您也可以分析
軟件事件,比如 Page Fault 和進程切換。
    這使得 Perf 擁有了衆多的性能分析能力,舉例來說,使用 Perf 可以計算每個時鐘週期內的指令數,稱爲 IPC,IPC 偏低表明代碼沒有很好地利用 CPU。Perf 還可以對程序進行函數級別的採樣,從而瞭解程序的性能瓶頸究竟在哪裏等等。Perf 還可以替代 strace,可以添加動態內核 probe 點,還可以做 benchmark 衡量調度器的好壞。。。
2.perf 的基本使用
    1)使用 perf list 命令可以列出所有能夠觸發perf採樣點的事件。
     $ perf list 
             List of pre-defined events (to be used in -e): 
             cpu-cycles OR cycles [Hardware event] 
             instructions [Hardware event] 
            …
             cpu-clock [Software event] 
             task-clock [Software event] 
             context-switches OR cs [Software event] 
            …
             ext4:ext4_allocate_inode [Tracepoint event] 
             kmem:kmalloc [Tracepoint event] 
             module:module_load [Tracepoint event] 
             workqueue:workqueue_execution [Tracepoint event] 
             sched:sched_{wakeup,switch} [Tracepoint event] 
             syscalls:sys_{enter,exit}_epoll_wait [Tracepoint event] 
    不同的系統會列出不同的結果,在 2.6.35 版本的內核中,該列表已經相當的長,但無論有多少,我們可以將它們劃分爲三類:
    Hardware Event 是由 PMU 硬件產生的事件,比如 cache 命中,當您需要了解程序對硬件特性的使用情況時,便需要對這些事件進行採樣;
    Software Event 是內核軟件產生的事件,比如進程切換,tick 數等 ;
    Tracepoint event 是內核中的靜態 tracepoint 所觸發的事件,這些 tracepoint 用來判斷程序運行期間內核的行爲細節,比如 
slab分配器的分配次數等。上述每一個事件都可以用於採樣,並生成一項統計數據。

     2)perf stat的使用 
    有些程序慢是因爲計算量太大,其多數時間都應該在使用 CPU 進行計算,這叫做 CPU bound 型;有些程序慢是因爲過多的 IO,這種時候其CPU 利用率應該不高,這叫做 IO bound 型;對於 CPU bound 程序的調優和 IO bound 的調優是不同的。
    Perf stat 應該是您最先使用的一個工具。它通過概括精簡的方式提供被調試程序運行的整體情況和彙總數據。
    現在將源碼編譯爲可執行文件 t1
        gcc – o t1 – g test.c
    下面演示了 perf stat 針對程序 t1 的輸出:
         $perf stat ./t1 
         Performance counter stats for './t1': 

         262.738415 task-clock-msecs # 0.991 CPUs 
         2 context-switches # 0.000 M/sec 
         1 CPU-migrations # 0.000 M/sec 
         81 page-faults # 0.000 M/sec 
         9478851 cycles # 36.077 M/sec (scaled from 98.24%) 
         6771 instructions # 0.001 IPC (scaled from 98.99%) 
         111114049 branches # 422.908 M/sec (scaled from 99.37%) 
         8495 branch-misses # 0.008 % (scaled from 95.91%) 
         12152161 cache-references # 46.252 M/sec (scaled from 96.16%) 
         7245338 cache-misses # 27.576 M/sec (scaled from 95.49%) 

          0.265238069 seconds time elapsed 

    上面告訴我們,程序 t1 是一個 CPU bound 型,因爲 task-clock-msecs 接近 1。
    對 t1 進行調優應該要找到熱點 ( 即最耗時的代碼片段 ),再看看是否能夠提高熱點代碼的效率。
    缺省情況下,除了 task-clock-msecs 之外,perf stat 還給出了其他幾個最常用的統計信息:
    Task-clock-msecs:CPU 利用率,該值高,說明程序的多數時間花費在 CPU 計算上而非 IO。
    Context-switches:進程切換次數,記錄了程序運行過程中發生了多少次進程切換,頻繁的進程切換是應該避免的。
    Cache-misses:程序運行過程中總體的 cache 利用情況,如果該值過高,說明程序的 cache 利用不好
    CPU-migrations:表示進程 t1 運行過程中發生了多少次 CPU 遷移,即被調度器從一個 CPU 轉移到另外一個 CPU 上運行
    Cycles:處理器時鐘,一條機器指令可能需要多個 cycles,
    Instructions: 機器指令數目。
    IPC:是 Instructions/Cycles 的比值,該值越大越好,說明程序充分利用了處理器的特性。
    Cache-references: cache 命中的次數
    Cache-misses: cache 失效的次數。
    通過指定 -e 選項,您可以改變 perf stat 的缺省事件 ( 關於事件,在上一小節已經說明,可以通過 perf list 來查看 )。
假如您已經有很多的調優經驗,可能會使用 -e 選項來查看您所感興趣的特殊的事件。

    3)Perf top 
    用於實時顯示當前系統的性能統計信息。該命令主要用來觀察整個系統當前的狀態,比如可以通過查看該命令的輸出來查看當前
系統最耗時的內核函數或某個用戶進程。
        舉例說明: 一個死循環
            while (1) i++;
    我叫他 t2。啓動 t2,然後用 perf top 來觀察:
        下面是 perf top 的可能輸出:
         PerfTop: 705 irqs/sec kernel:60.4% [1000Hz cycles] 
         -------------------------------------------------- 
         sampl pcnt function DSO 
         1503.00 49.2% t2 
         72.00 2.2% pthread_mutex_lock /lib/libpthread-2.12.so 
         68.00 2.1% delay_tsc [kernel.kallsyms] 
         55.00 1.7% aes_dec_blk [aes_i586] 
         55.00 1.7% drm_clflush_pages [drm] 
         52.00 1.6% system_call [kernel.kallsyms] 
         49.00 1.5% __memcpy_ssse3 /lib/libc-2.12.so 
         48.00 1.4% __strstr_ia32 /lib/libc-2.12.so 
         46.00 1.4% unix_poll [kernel.kallsyms] 
         42.00 1.3% __ieee754_pow /lib/libm-2.12.so 
         41.00 1.2% do_select [kernel.kallsyms] 
         40.00 1.2% pixman_rasterize_edges libpixman-1.so.0.18.0 
         37.00 1.1% _raw_spin_lock_irqsave [kernel.kallsyms] 
         36.00 1.1% _int_malloc /lib/libc-2.12.so 
         ^C
        很容易便發現 t2 是需要關注的可疑程序。不過其作案手法太簡單:肆無忌憚地浪費着 CPU。所以我們不用再做什麼其他的事情便可以找到問題所在。但現實生活中,影響性能的程序一般都不會如此愚蠢,所以我們往往還需要使用其他的 perf 工具進一步分析。
      通過添加 -e 選項,您可以列出造成其他事件的 TopN 個進程 / 函數。比如 -e cache-miss,用來看看誰造成的 cache miss 最多。
    4)使用 perf record, 解讀 report
    使用 top 和 stat 之後,您可能已經大致有數了。要進一步分析,便需要一些粒度更細的信息。比如說您已經斷定目標程序計算
量較大,也許是因爲有些代碼寫的不夠精簡。那麼面對長長的代碼文件,究竟哪幾行代碼需要進一步修改呢?這便需要使用 perf 
record 記錄單個函數級別的統計信息,並使用 perf report 來顯示統計結果。
    調優應該將注意力集中到百分比高的熱點代碼片段上,假如一段代碼只佔用整個程序運行時間的 0.1%,即使您將其優化到僅剩一條機器指令,恐怕也只能將整體的程序性能提高 0.1%。俗話說,好鋼用在刀刃上,不必我多說了。
        仍以 t1 爲例。
         perf record – e cpu-clock ./t1 
         perf report
    不出所料,hot spot 是xxx函數。但,代碼是非常複雜難說的。自己寫的一個程序居然有近一半的時間花費在 string 類的幾個
方法上,string 是 C++ 標準,我絕不可能寫出比 STL 更好的代碼了。因此我只有找到自己程序中過多使用 string 的地方。因此我很需要按照調用關係(調用樹)進行顯示的統計信息。
        使用 perf 的 -g 選項便可以得到需要的信息:
         perf record – e cpu-clock – g ./t1 
         perf report
    通過對 calling graph 的分析,能很方便地看到時間都花費在那個函數中,從而針對函數進行相關優化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章