1. 程式人生 > >Linux下的系統性能調優工具——Perf

Linux下的系統性能調優工具——Perf

參考以下連結文章整理:
Perf -- Linux下的系統性能調優工具,第 1 部分
Perf -- Linux下的系統性能調優工具,第 2 部分
感謝原作者,讓我知道了效能調優也是如此有趣,Linux下還有如此強大之Linux系統調優工具。

Perf——Linux下的系統性能調優工具

1. 背景知識

1.1 與效能調優相關的硬體特性

  • 硬體特性之cache

    記憶體讀寫是很快的,但還是無法和處理器的指令執行速度相比。為了從記憶體中讀取指令和資料,處理器需要等待,用處理器的時間來衡量,這種等待非常漫長。Cache 是一種 SRAM,它的讀寫速率非常快,能和處理器處理速度相匹配。因此將常用的資料儲存在 cache 中,處理器便無須等待,從而提高效能。Cache 的尺寸一般都很小,充分利用 cache 是軟體調優非常重要的部分。

  • 硬體特性之流水線,超標量體系結構,亂序執行

    提高效能最有效的方式之一就是並行。處理器在硬體設計時也儘可能地並行,比如流水線,超標量體系結構以及亂序執行。

    處理器處理一條指令需要分多個步驟完成,比如先取指令,然後完成運算,最後將計算結果輸出到總線上。第一條指令在運算時,第二條指令已經在取指了;而第一條指令輸出結果時,第二條指令則又可以運算了,而第三天指令也已經取指了。這樣從長期看來,像是三條指令在同時執行。在處理器內部,這可以看作一個三級流水線。

    超標量(superscalar)指一個時鐘週期發射多條指令的流水線機器架構,比如 Intel 的 Pentium 處理器,內部有兩個執行單元,在一個時鐘週期內允許執行兩條指令。

    在處理器內部,不同指令所需要的處理步驟和時鐘週期是不同的,如果嚴格按照程式的執行順序執行,那麼就無法充分利用處理器的流水線。因此指令有可能被亂序執行。

    上述三種並行技術對所執行的指令有一個基本要求,即相鄰的指令相互沒有依賴關係。假如某條指令需要依賴前面一條指令的執行結果資料,那麼 pipeline 便失去作用,因為第二條指令必須等待第一條指令完成。因此好的軟體必須儘量避免這種程式碼的生成。

  • 硬體特性之分支預測

    分支指令對軟體效能有比較大的影響。尤其是當處理器採用流水線設計之後,假設流水線有三級,當前進入流水的第一條指令為分支指令。假設處理器順序讀取指令,那麼如果分支的結果是跳轉到其他指令,那麼被處理器流水線預取的後續兩條指令都將被放棄,從而影響效能。為此,很多處理器都提供了分支預測功能,根據同一條指令的歷史執行記錄進行預測,讀取最可能的下一條指令,而並非順序讀取指令。

    分支預測對軟體結構有一些要求,對於重複性的分支指令序列,分支預測硬體能得到較好的預測結果,而對於類似 switch case 一類的程式結構,則往往無法得到理想的預測結果。

    上面介紹的幾種處理器特性對軟體的效能有很大的影響,然而依賴時鐘進行定期取樣的 profiler 模式無法揭示程式對這些處理器硬體特性的使用情況。處理器廠商針對這種情況,在硬體中加入了 PMU 單元,即 performance monitor unit。PMU 允許軟體針對某種硬體事件設定 counter,此後處理器便開始統計該事件的發生次數,當發生的次數超過 counter 內設定的值後,便產生中斷。比如 cache miss 達到某個值後,PMU 便能產生相應的中斷。

    捕獲這些中斷,便可以考察程式對這些硬體特性的利用效率了。

1.2 Tracepoints

Tracepoint 是散落在核心原始碼中的一些 hook,一旦使能,它們便可以在特定的程式碼被執行到時被觸發,這一特性可以被各種 trace/debug 工具所使用。Perf 就是該特性的使用者之一。

假如您想知道在應用程式執行期間,核心記憶體管理模組的行為,便可以利用潛伏在 slab 分配器中的 tracepoint。當核心執行到這些 tracepoint 時,便會通知 perf。Perf 將 tracepoint 產生的事件記錄下來,生成報告,通過分析這些報告,調優人員便可以瞭解程式執行時期核心的種種細節,對效能症狀作出更準確的診斷。


2.Perf簡介

  • Perf是Linux核心自帶的系統性能優化工具,原理是:

    CPU的PMU registers中Get/Set performance counters來獲得諸如instructions executed, cache-missed suffered, branches mispredicted等資訊。Linux kernel對這些registers進行了一系列抽象,所以你可以按程序,按CPU或者按counter group等不同類別來檢視Sample資訊。

  • 通過Perf,應用程式可以利用 PMU,tracepoint 和核心中的特殊計數器來進行效能統計。它不但可以分析指定應用程式的效能問題 (per thread),也可以用來分析核心的效能問題,當然也可以同時分析應用程式碼和核心,從而全面理解應用程式中的效能瓶頸。

  • Perf 不僅可以用於應用程式的效能統計分析,也可以應用於核心程式碼的效能統計和分析。得益於其優秀的體系結構設計,越來越多的新功能被加入 Perf,使其已經成為一個多功能的效能統計工具集 。

3.perf 的基本使用

效能調優工具如 perf,Oprofile 等的基本原理都是對被監測物件進行取樣,最簡單的情形是根據 tick 中斷進行取樣,即在 tick 中斷內觸發取樣點,在取樣點裡判斷程式當時的上下文。假如一個程式 90% 的時間都花費在函式 foo() 上,那麼 90% 的取樣點都應該落在函式 foo() 的上下文中。運氣不可捉摸,但我想只要取樣頻率足夠高,取樣時間足夠長,那麼以上推論就比較可靠。因此,通過 tick 觸發取樣,我們便可以瞭解程式中哪些地方最耗時間,從而重點分析。稍微擴充套件一下思路,就可以發現改變取樣的觸發條件使得我們可以獲得不同的統計資料:以時間點 ( 如 tick) 作為事件觸發取樣便可以獲知程式執行時間的分佈。以 cache miss 事件觸發取樣便可以知道 cache miss 的分佈,即 cache 失效經常發生在哪些程式程式碼中。如此等等。

因此讓我們先來了解一下 perf 中能夠觸發取樣的事件有哪些。

3.1 Perf list,perf 事件

 
  1. 使用 perf list 命令可以列出所有能夠觸發 perf 取樣點的事件。比如

  2.  
  3. # perf list

  4. List of pre-defined events (to be used in -e):

  5. cpu-cycles OR cycles [Hardware event]

  6. instructions [Hardware event]

  7. cpu-clock [Software event]

  8. task-clock [Software event]

  9. context-switches OR cs [Software event]

  10. ext4:ext4_allocate_inode [Tracepoint event]

  11. kmem:kmalloc [Tracepoint event]

  12. module:module_load [Tracepoint event]

  13. workqueue:workqueue_execution [Tracepoint event]

  14. sched:sched_{wakeup,switch} [Tracepoint event]

  15. syscalls:sys_{enter,exit}_epoll_wait [Tracepoint event]

  16.  
  17. 不同的系統會列出不同的結果,在 2.6.35 版本的核心中,該列表已經相當的長,但無論有多少,我們可以將它們劃分為三類:

  • Hardware Event 是由 PMU 硬體產生的事件,比如 cache 命中,當您需要了解程式對硬體特性的使用情況時,便需要對這些事件進行取樣;
  • Software Event 是核心軟體產生的事件,比如程序切換,tick 數等 ;
  • Tracepoint event 是核心中的靜態 tracepoint 所觸發的事件,這些 tracepoint 用來判斷程式執行期間核心的行為細節,比如 slab 分配器的分配次數等。

上述每一個事件都可以用於取樣,並生成一項統計資料,時至今日,尚沒有文件對每一個 event 的含義進行詳細解釋。

3.2 Perf stat

面對一個問題程式,最好採用自頂向下的策略。先整體看看該程式執行時各種統計事件的大概,再針對某些方向深入細節。而不要一下子扎進瑣碎細節,會一葉障目的。

有些程式慢是因為計算量太大,其多數時間都應該在使用 CPU 進行計算,這叫做 CPU bound 型;有些程式慢是因為過多的 IO,這種時候其 CPU 利用率應該不高,這叫做 IO bound 型;對於 CPU bound 程式的調優和 IO bound 的調優是不同的。

如果您認同這些說法的話,Perf stat 應該是您最先使用的一個工具。它通過概括精簡的方式提供被除錯程式執行的整體情況和彙總資料。

下面演示了 perf stat 針對程式 t1 的輸出:

$perf stat ./t1 Performance counter stats for './t1':

 
  1. 262.738415 task-clock-msecs # 0.991 CPUs

  2. 2 context-switches # 0.000 M/sec

  3. 1 CPU-migrations # 0.000 M/sec

  4. 81 page-faults # 0.000 M/sec

  5. 9478851 cycles # 36.077 M/sec (scaled from 98.24%)

  6. 6771 instructions # 0.001 IPC (scaled from 98.99%)

  7. 111114049 branches # 422.908 M/sec (scaled from 99.37%)

  8. 8495 branch-misses # 0.008 % (scaled from 95.91%)

  9. 12152161 cache-references # 46.252 M/sec (scaled from 96.16%)

  10. 7245338 cache-misses # 27.576 M/sec (scaled from 95.49%)

  11.  
  12. 0.265238069 seconds time elapsed

上面告訴我們,程式 t1 是一個 CPU bound 型,因為 task-clock-msecs 接近 1。

對 t1 進行調優應該要找到熱點 ( 即最耗時的程式碼片段 ),再看看是否能夠提高熱點程式碼的效率。

預設情況下,除了 task-clock-msecs 之外,perf stat 還給出了其他幾個最常用的統計資訊:

 
  1. Task-clock-msecs:CPU 利用率,該值高,說明程式的多數時間花費在 CPU 計算上而非 IO。

  2. Context-switches:程序切換次數,記錄了程式執行過程中發生了多少次程序切換,頻繁的程序切換是應該避免的。

  3. Cache-misses:程式執行過程中總體的 cache 利用情況,如果該值過高,說明程式的 cache 利用不好

  4. CPU-migrations:表示程序 t1 執行過程中發生了多少次 CPU 遷移,即被排程器從一個 CPU 轉移到另外一個 CPU 上執行。

  5. Cycles:處理器時鐘,一條機器指令可能需要多個 cycles,

  6. Instructions: 機器指令數目。

  7. IPC:是 Instructions/Cycles 的比值,該值越大越好,說明程式充分利用了處理器的特性。

  8. Cache-references: cache 命中的次數

  9. Cache-misses: cache 失效的次數。

通過指定 -e 選項,您可以改變 perf stat 的預設事件 ( 關於事件,在上一小節已經說明,可以通過 perf list 來檢視 )。假如您已經有很多的調優經驗,可能會使用 -e 選項來檢視您所感興趣的特殊的事件。

3.3perf Top

Perf top 用於實時顯示當前系統的效能統計資訊。該命令主要用來觀察整個系統當前的狀態,比如可以通過檢視該命令的輸出來檢視當前系統最耗時的核心函式或某個使用者程序。

下面是 perf top 的可能輸出:

 
  1. PerfTop: 705 irqs/sec kernel:60.4% [1000Hz cycles]

  2. --------------------------------------------------

  3. sampl pcnt function DSO

  4. 1503.00 49.2% t2

  5. 72.00 2.2% pthread_mutex_lock /lib/libpthread-2.12.so

  6. 68.00 2.1% delay_tsc [kernel.kallsyms]

  7. 55.00 1.7% aes_dec_blk [aes_i586]

  8. 55.00 1.7% drm_clflush_pages [drm]

  9. 52.00 1.6% system_call [kernel.kallsyms]

  10. 49.00 1.5% __memcpy_ssse3 /lib/libc-2.12.so

  11. 48.00 1.4% __strstr_ia32 /lib/libc-2.12.so

  12. 46.00 1.4% unix_poll [kernel.kallsyms]

  13. 42.00 1.3% __ieee754_pow /lib/libm-2.12.so

  14. 41.00 1.2% do_select [kernel.kallsyms]

  15. 40.00 1.2% pixman_rasterize_edges libpixman-1.so.0.18.0

  16. 37.00 1.1% _raw_spin_lock_irqsave [kernel.kallsyms]

  17. 36.00 1.1% _int_malloc /lib/libc-2.12.so

  18. ^C

很容易便發現 t2 是需要關注的可疑程式。不過其作案手法太簡單:肆無忌憚地浪費著 CPU。所以我們不用再做什麼其他的事情便可以找到問題所在。但現實生活中,影響效能的程式一般都不會如此愚蠢,所以我們往往還需要使用其他的 perf 工具進一步分析。

通過新增 -e 選項,您可以列出造成其他事件的 TopN 個程序 / 函式。比如 -e cache-miss,用來看看誰造成的 cache miss 最多。

3.4 使用 perf record, 解讀 report

 
  1. [email protected]:~/test$ perf record ./a.out

  2. [ perf record: Woken up 1 times to write data ]

  3. [ perf record: Captured and wrote 0.015 MB perf.data (~656 samples) ]

  4. [email protected]:~/test$ perf report

  5. Events: 12 cycles

  6. 62.29% a.out a.out [.] longa

  7. 35.17% a.out [kernel.kallsyms] [k] unmap_vmas

  8. 1.76% a.out [kernel.kallsyms] [k] __schedule

  9. 0.75% a.out [kernel.kallsyms] [k] ____cache_alloc

  10. 0.03% a.out [kernel.kallsyms] [k] native_write_msr_safe

perf record時加上-g選項,可以記錄函式的呼叫關係,顯示類似下面這樣:

 
  1. [email protected]:~/test$ perf record -g ./a.out

  2. [ perf record: Woken up 1 times to write data ]

  3. [ perf record: Captured and wrote 0.016 MB perf.data (~701 samples) ]

  4. [email protected]:~/test$ perf report

  5. Events: 14 cycles

  6. - 87.12% a.out a.out [.] longa

  7. - longa

  8. - 52.91% fun1

  9. main

  10. __libc_start_main

  11. - 47.09% fun2

  12. main

  13. __libc_start_main

  14. + 9.12% a.out [kernel.kallsyms] [k] vm_normal_page

  15. + 3.48% a.out [kernel.kallsyms] [k] _cond_resched

  16. + 0.28% a.out [kernel.kallsyms] [k] native_write_msr_safe

***使用 PMU 的例子下面這個例子 t3 參考了文章“Branch and Loop Reorganization to Prevent Mispredicts”該例子考察程式對奔騰處理器分支預測的利用率,如前所述,分支預測能夠顯著提高處理器的效能,而分支預測失敗則顯著降低處理器的效能。首先給出一個存在 BTB 失效的例子:

清單 3. 存在 BTB 失效的例子程式

 
  1. //test.c

  2. #include <stdio.h>

  3. #include <stdlib.h>

  4.  
  5. void foo()

  6. {

  7. int i,j;

  8. for(i=0; i< 10; i++)

  9. j+=2;

  10. }

  11. int main(void)

  12. {

  13. int i;

  14. for(i = 0; i< 100000000; i++)

  15. foo();

  16. return 0;

  17. }

用 gcc 編譯生成測試程式 t3: gcc – o t3 – O0 test.c

用 perf stat 考察分支預測的使用情況: [[email protected] perf]$ ./perf stat ./t3

 
  1. Performance counter stats for './t3':

  2.  
  3. 6240.758394 task-clock-msecs # 0.995 CPUs

  4. 126 context-switches # 0.000 M/sec

  5. 12 CPU-migrations # 0.000 M/sec

  6. 80 page-faults # 0.000 M/sec

  7. 17683221 cycles # 2.834 M/sec (scaled from 99.78%)

  8. 10218147 instructions # 0.578 IPC (scaled from 99.83%)

  9. 2491317951 branches # 399.201 M/sec (scaled from 99.88%)

  10. 636140932 branch-misses # 25.534 % (scaled from 99.63%)

  11. 126383570 cache-references # 20.251 M/sec (scaled from 99.68%)

  12. 942937348 cache-misses # 151.093 M/sec (scaled from 99.58%)

  13.  
  14. 6.271917679 seconds time elapsed

可以看到 branche-misses 的情況比較嚴重,25% 左右。我測試使用的機器的處理器為 Pentium4,其 BTB 的大小為 16。而 test.c 中的迴圈迭代為 20 次,BTB 溢位,所以處理器的分支預測將不準確。對於上面這句話我將簡要說明一下,但關於 BTB 的細節,請閱讀參考文獻 [6]。for 迴圈編譯成為 IA 彙編後如下:

清單 4. 迴圈的彙編

 
  1. // C code

  2. for ( i=0; i < 20; i++ )

  3. { … }

  4.  
  5. //Assembly code;

  6. mov esi, data

  7. mov ecx, 0

  8. ForLoop:

  9. cmp ecx, 20

  10. jge

  11. EndForLoop

  12. add ecx, 1

  13. jmp ForLoop

  14. EndForLoop:

可以看到,每次迴圈迭代中都有一個分支語句 jge,因此在執行過程中將有 20 次分支判斷。每次分支判斷都將寫入 BTB,但 BTB 是一個 ring buffer,16 個 slot 寫滿後便開始覆蓋。假如迭代次數正好為 16,或者小於 16,則完整的迴圈將全部寫入 BTB。

清單 5. 沒有 BTB 失效的程式碼

 
  1. #include <stdio.h>

  2. #include <stdlib.h>

  3.  
  4. void foo()

  5. {

  6. int i,j;

  7. for(i=0; i< 10; i++)

  8. j+=2;

  9. }

  10. int main(void)

  11. {

  12. int i;

  13. for(i = 0; i< 100000000; i++)

  14. foo();

  15. return 0;

  16. }

此時再次用 perf stat 取樣得到如下結果: [[email protected] perf]$ ./perf stat ./t3

 
  1. Performance counter stats for './t3:

  2.  
  3. 2784.004851 task-clock-msecs # 0.927 CPUs

  4. 90 context-switches # 0.000 M/sec

  5. 8 CPU-migrations # 0.000 M/sec

  6. 81 page-faults # 0.000 M/sec

  7. 33632545 cycles # 12.081 M/sec (scaled from 99.63%)

  8. 42996 instructions # 0.001 IPC (scaled from 99.71%)

  9. 1474321780 branches # 529.569 M/sec (scaled from 99.78%)

  10. 49733 branch-misses # 0.003 % (scaled from 99.35%)

  11. 7073107 cache-references # 2.541 M/sec (scaled from 99.42%)

  12. 47958540 cache-misses # 17.226 M/sec (scaled from 99.33%)

  13.  
  14. 3.002673524 seconds time elapsed

Branch-misses 減少了。本例只是為了演示 perf 對 PMU 的使用,本身並無意義,關於充分利用 processor 進行調優可以參考 Intel 公司出品的調優手冊,其他的處理器可能有不同的方法,還希望讀者明鑑。

3.5 使用 tracepoint

當 perf 根據 tick 時間點進行取樣後,人們便能夠得到核心程式碼中的 hot spot。那什麼時候需要使用 tracepoint 來取樣呢?我想人們使用 tracepoint 的基本需求是對核心的執行時行為的關心,如前所述,有些核心開發人員需要專注於特定的子系統,比如記憶體管理模組。這便需要統計相關核心函式的執行情況。另外,核心行為對應用程式效能的影響也是不容忽視的:以之前的遺憾為例,假如時光倒流,我想我要做的是統計該應用程式執行期間究竟發生了多少次系統呼叫。在哪裡發生的?下面我用 ls 命令來演示 sys_enter 這個 tracepoint 的使用: [[email protected] /]# perf stat -e raw_syscalls:sys_enter ls bin dbg etc lib media opt root selinux sys usr boot dev home lost+found mnt proc sbin srv tmp var

Performance counter stats for 'ls':

101 raw_syscalls:sys_enter

0.003434730 seconds time elapsed

[[email protected] /]# perf record -e raw_syscalls:sys_enter ls

[[email protected] /]# perf report Failed to open .lib/ld-2.12.so, continuing without symbols # Samples: 70 # # Overhead Command Shared Object Symbol # ........ ............... ............... ...... # 97.14% ls ld-2.12.so [.] 0x0000000001629d 2.86% ls [vdso] [.] 0x00000000421424 # # (For a higher level overview, try: perf report --sort comm,dso) #

這個報告詳細說明了在 ls 執行期間發生了多少次系統呼叫 ( 上例中有 101 次 ),多數系統呼叫都發生在哪些地方 (97% 都發生在 ld-2.12.so 中 )。有了這個報告,或許我能夠發現更多可以調優的地方。比如函式 foo() 中發生了過多的系統呼叫,那麼我就可以思考是否有辦法減少其中有些不必要的系統呼叫。您可能會說 strace 也可以做同樣事情啊,的確,統計系統呼叫這件事完全可以用 strace 完成,但 perf 還可以幹些別的,您所需要的就是修改 -e 選項後的字串。羅列 tracepoint 實在是不太地道,本文當然不會這麼做。但學習每一個 tracepoint 是有意義的,類似背單詞之於學習英語一樣,是一項緩慢痛苦卻不得不做的事情。

3.6 perf probe

tracepoint 是靜態檢查點,意思是一旦它在哪裡,便一直在那裡了,您想讓它移動一步也是不可能的。核心程式碼有多少行?我不知道,100 萬行是至少的吧,但目前 tracepoint 有多少呢?我最大膽的想象是不超過 1000 個。所以能夠動態地在想檢視的地方插入動態監測點的意義是不言而喻的。

Perf 並不是第一個提供這個功能的軟體,systemTap 早就實現了。但假若您不選擇 RedHat 的發行版的話,安裝 systemTap 並不是件輕鬆愉快的事情。perf 是核心程式碼包的一部分,所以使用和維護都非常方便。

我使用的 Linux 版本為 2.6.33。因此您自己做實驗時命令引數有可能不同。

 
  1. [[email protected] perftest]# perf probe schedule:12 cpu

  2. Added new event:

  3. probe:schedule (on schedule+52 with cpu)

  4.  
  5. You can now use it on all perf tools, such as:

  6.  
  7. perf record -e probe:schedule -a sleep 1

  8.  
  9. [[email protected] perftest]# perf record -e probe:schedule -a sleep 1

  10. Error, output file perf.data exists, use -A to append or -f to overwrite.

  11.  
  12. [[email protected] perftest]# perf record -f -e probe:schedule -a sleep 1

  13. [ perf record: Woken up 1 times to write data ]

  14. [ perf record: Captured and wrote 0.270 MB perf.data (~11811 samples) ]

  15. [[email protected] perftest]# perf report

  16. # Samples: 40

  17. #

  18. # Overhead Command Shared Object Symbol

  19. # ........ ............... ................. ......

  20. #

  21. 57.50% init 0 [k] 0000000000000000

  22. 30.00% firefox [vdso] [.] 0x0000000029c424

  23. 5.00% sleep [vdso] [.] 0x00000000ca7424

  24. 5.00% perf.2.6.33.3-8 [vdso] [.] 0x00000000ca7424

  25. 2.50% ksoftirqd/0 [kernel] [k] 0000000000000000

  26. #

  27. # (For a higher level overview, try: perf report --sort comm,dso)

  28. #

上例利用 probe 命令在核心函式 schedule() 的第 12 行處加入了一個動態 probe 點,和 tracepoint 的功能一樣,核心一旦執行到該 probe 點時,便會通知 perf。可以理解為動態增加了一個新的 tracepoint。此後便可以用 record 命令的 -e 選項選擇該 probe 點,最後用 perf report 檢視報表。如何解讀該報表便是見仁見智了,既然您在 shcedule() 的第 12 行加入了 probe 點,想必您知道自己為什麼要統計它吧?

3.7 Perf sched

排程器的好壞直接影響一個系統的整體執行效率。在這個領域,核心黑客們常會發生爭執,一個重要原因是對於不同的排程器,每個人給出的評測報告都各不相同,甚至常常有相反的結論。因此一個權威的統一的評測工具將對結束這種爭論有益。Perf sched 便是這種嘗試。

Perf sched 有五個子命令:

 
  1. perf sched record # low-overhead recording of arbitrary workloads

  2. perf sched latency # output per task latency metrics

  3. perf sched map # show summary/map of context-switching

  4. perf sched trace # output finegrained trace

  5. perf sched replay # replay a captured workload using simlated threads

使用者一般使用’ perf sched record ’收集排程相關的資料,然後就可以用’ perf sched latency ’檢視諸如排程延遲等和排程器相關的統計資料。其他三個命令也同樣讀取 record 收集到的資料並從其他不同的角度來展示這些資料。下面一一進行演示。

 
  1. perf sched record sleep 10 # record full system activity for 10 seconds

  2. perf sched latency --sort max # report latencies sorted by max

  3. -------------------------------------------------------------------------------------

  4. Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |

  5. -------------------------------------------------------------------------------------

  6. :14086:14086 | 0.095 ms | 2 | avg: 3.445 ms | max: 6.891 ms |

  7. gnome-session:13792 | 31.713 ms | 102 | avg: 0.160 ms | max: 5.992 ms |

  8. metacity:14038 | 49.220 ms | 637 | avg: 0.066 ms | max: 5.942 ms |

  9. gconfd-2:13971 | 48.587 ms | 777 | avg: 0.047 ms | max: 5.793 ms |

  10. gnome-power-man:14050 | 140.601 ms | 434 | avg: 0.097 ms | max: 5.367 ms |

  11. python:14049 | 114.694 ms | 125 | avg: 0.120 ms | max: 5.343 ms |

  12. kblockd/1:236 | 3.458 ms | 498 | avg: 0.179 ms | max: 5.271 ms |

  13. Xorg:3122 | 1073.107 ms | 2920 | avg: 0.030 ms | max: 5.265 ms |

  14. dbus-daemon:2063 | 64.593 ms | 665 | avg: 0.103 ms | max: 4.730 ms |

  15. :14040:14040 | 30.786 ms | 255 | avg: 0.095 ms | max: 4.155 ms |

  16. events/1:8 | 0.105 ms | 13 | avg: 0.598 ms | max: 3.775 ms |

  17. console-kit-dae:2080 | 14.867 ms | 152 | avg: 0.142 ms | max: 3.760 ms |

  18. gnome-settings-:14023 | 572.653 ms | 979 | avg: 0.056 ms | max: 3.627 ms |

  19. ...

  20. -----------------------------------------------------------------------------------

  21. TOTAL: | 3144.817 ms | 11654 |

  22. ---------------------------------------------------

  23.  

上面的例子展示了一個 Gnome 啟動時的統計資訊。

各個 column 的含義如下: Task: 程序的名字和 pid Runtime: 實際執行時間 Switches: 程序切換的次數 Average delay: 平均的排程延遲 Maximum delay: 最大延遲

這裡最值得人們關注的是 Maximum delay,一般從這裡可以看到對互動性影響最大的特性:排程延遲,如果排程延遲比較大,那麼使用者就會感受到視訊或者音訊斷斷續續的。

其他的三個子命令提供了不同的檢視,一般是由排程器的開發人員或者對排程器內部實現感興趣的人們所使用。

首先是 map:

$ perf sched map ...

 
  1. N1 O1 . . . S1 . . . B0 . *I0 C1 . M1 . 23002.773423 secs

  2. N1 O1 . *Q0 . S1 . . . B0 . I0 C1 . M1 . 23002.773423 secs

  3. N1 O1 . Q0 . S1 . . . B0 . *R1 C1 . M1 . 23002.773485 secs

  4. N1 O1 . Q0 . S1 . *S0 . B0 . R1 C1 . M1 . 23002.773478 secs

  5. *L0 O1 . Q0 . S1 . S0 . B0 . R1 C1 . M1 . 23002.773523 secs

  6. L0 O1 . *. . S1 . S0 . B0 . R1 C1 . M1 . 23002.773531 secs

  7. L0 O1 . . . S1 . S0 . B0 . R1 C1 *T1 M1 . 23002.773547 secs

  8. T1 => irqbalance:2089

  9. L0 O1 . . . S1 . S0 . *P0 . R1 C1 T1 M1 . 23002.773549 secs

  10. *N1 O1 . . . S1 . S0 . P0 . R1 C1 T1 M1 . 23002.773566 secs

  11. N1 O1 . . . *J0 . S0 . P0 . R1 C1 T1 M1 . 23002.773571 secs

  12. N1 O1 . . . J0 . S0 *B0 P0 . R1 C1 T1 M1 . 23002.773592 secs

  13. N1 O1 . . . J0 . *U0 B0 P0 . R1 C1 T1 M1 . 23002.773582 secs

  14. N1 O1 . . . *S1 . U0 B0 P0 . R1 C1 T1 M1 . 23002.773604 secs

星號表示排程事件發生所在的 CPU。

點號表示該 CPU 正在 IDLE。

Map 的好處在於提供了一個的總的檢視,將成百上千的排程事件進行總結,顯示了系統任務在 CPU 之間的分佈,假如有不好的排程遷移,比如一個任務沒有被及時遷移到 idle 的 CPU 卻被遷移到其他忙碌的 CPU,類似這種排程器的問題可以從 map 的報告中一眼看出來。如果說 map 提供了高度概括的總體的報告,那麼 trace 就提供了最詳細,最底層的細節報告。

Perf replay 這個工具更是專門為排程器開發人員所設計,它試圖重放 perf.data 檔案中所記錄的排程場景。很多情況下,一般使用者假如發現排程器的奇怪行為,他們也無法準確說明發生該情形的場景,或者一些測試場景不容易再次重現,或者僅僅是出於“偷懶”的目的,使用 perf replay,perf 將模擬 perf.data 中的場景,無需開發人員花費很多的時間去重現過去,這尤其利於除錯過程,因為需要一而再,再而三地重複新的修改是否能改善原始的排程場景所發現的問題。

下面是 replay 執行的示例: $ perf sched replay run measurement overhead: 3771 nsecs sleep measurement overhead: 66617 nsecs the run test took 999708 nsecs the sleep test took 1097207 nsecs nr_run_events: 200221 nr_sleep_events: 200235 nr_wakeup_events: 100130 task 0 ( perf: 13519), nr_events: 148 task 1 ( perf: 13520), nr_events: 200037 task 2 ( pipe-test-100k: 13521), nr_events: 300090 task 3 ( ksoftirqd/0: 4), nr_events: 8 task 4 ( swapper: 0), nr_events: 170 task 5 ( gnome-power-man: 3192), nr_events: 3 task 6 ( gdm-simple-gree: 3234), nr_events: 3 task 7 ( Xorg: 3122), nr_events: 5 task 8 ( hald-addon-stor: 2234), nr_events: 27 task 9 ( ata/0: 321), nr_events: 29 task 10 ( scsi_eh_4: 704), nr_events: 37 task 11 ( events/1: 8), nr_events: 3 task 12 ( events/0: 7), nr_events: 6 task 13 ( flush-8:0: 6980), nr_events: 20 ------------------------------------------------------------ #1 : 2038.157, ravg: 2038.16, cpu: 0.09 / 0.09 #2 : 2042.153, ravg: 2038.56, cpu: 0.11 / 0.09 ^C

3.8 perf bench

除了排程器之外,很多時候人們都需要衡量自己的工作對系統性能的影響。benchmark 是衡量效能的標準方法,對於同一個目標,如果能夠有一個大家都承認的 benchmark,將非常有助於”提高核心效能”這項工作。

目前,就我所知,perf bench 提供了 3 個 benchmark:

  1. Sched message

sched message 是從經典的測試程式 hackbench 移植而來,用來衡量排程器的效能,overhead 以及可擴充套件性。該 benchmark 啟動 N 個 reader/sender 程序或執行緒對,通過 IPC(socket 或者 pipe) 進行併發的讀寫。一般人們將 N 不斷加大來衡量排程器的可擴充套件性。Sched message 的用法及用途和 hackbench 一樣。

  1. Sched Pipe

Sched pipe 從 Ingo Molnar 的 pipe-test-1m.c 移植而來。當初 Ingo 的原始程式是為了測試不同的排程器的效能和公平性的。其工作原理很簡單,兩個程序互相通過 pipe 拼命地發 1000000 個整數,程序 A 發給 B,同時 B 發給 A。。。因為 A 和 B 互相依賴,因此假如排程器不公平,對 A 比 B 好,那麼 A 和 B 整體所需要的時間就會更長。

  1. Mem memcpy

這個是 perf bench 的作者 Hitoshi Mitake 自己寫的一個執行 memcpy 的 benchmark。該測試衡量一個拷貝 1M 資料的 memcpy() 函式所花費的時間。我尚不明白該 benchmark 的使用場景。。。或許是一個例子,告訴人們如何利用 perf bench 框架開發更多的 benchmark 吧。

這三個 benchmark 給我們展示了一個可能的未來:不同語言,不同膚色,來自不同背景的人們將來會採用同樣的 benchmark,只要有一份 Linux 核心程式碼即可。

3.9 perf lock

鎖是核心同步的方法,一旦加了鎖,其他準備加鎖的核心執行路徑就必須等待,降低了並行。因此對於鎖進行專門分析應該是調優的一項重要工作。

3.10 perf Kmem

Perf Kmem 專門收集核心 slab 分配器的相關事件。比如記憶體分配,釋放等。可以用來研究程式在哪裡分配了大量記憶體,或者在什麼地方產生碎片之類的和記憶體管理相關的問題。

Perf kmem 和 perf lock 實際上都是 perf tracepoint 的特例,您也完全可以用 Perf record – e kmem: 或者 perf record – e lock: 來完成同樣的功能。但重要的是,這些工具在內部對原始資料進行了彙總和分析,因而能夠產生資訊更加明確更加有用的統計報表。

3.11 Perf timechart

很多 perf 命令都是為除錯單個程式或者單個目的而設計。有些時候,效能問題並非由單個原因所引起,需要從各個角度一一檢視。為此,人們常需要綜合利用各種工具,比如 top,vmstat,oprofile 或者 perf。這非常麻煩。

此外,前面介紹的所有工具都是基於命令列的,報告不夠直觀。更令人氣餒的是,一些報告中的引數令人費解。所以人們更願意擁有一個“傻瓜式”的工具。

以上種種就是 perf timechart 的夢想,其靈感來源於 bootchart。採用“簡單”的圖形“一目瞭然”地揭示問題所在。

Timechart 可以顯示更詳細的資訊,實際上是一個向量圖形 SVG 格式,用 SVG viewer 的放大功能,我們可以將該圖的細節部分放大,timechart 的設計理念叫做”infinitely zoomable”。放大之後便可以看到一些更詳細的資訊,類似網上的 google 地圖,找到國家之後,可以放大,看城市的分佈,再放大,可以看到某個城市的街道分佈,還可以放大以便得到更加詳細的資訊。完整的 timechart 圖形和顏色解讀超出了本文的範圍,感興趣的讀者可以到作者 Arjan 的部落格上檢視。

--------------------- 本文來自 窮遊的兔子 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/dreamcoding/article/details/7782415?utm_source=copy