perf 採樣解析調用棧

perf除了上述的採樣形式,還支持解析函數執行的完整調用棧,並得到調用棧中各個環節的cpu消耗,並對位於同一調用棧的各個環節的採樣佔比進行加總,得到佔用cpu比例最高的頂層棧。使用如下命令進行採樣

perf record -g --call-graph fp xxx  # xxx 代表具體要執行的命令
perf record -g --call-graph fp -p $(pid)  #採集特定的pid
perf record -g --call-graph fp -a #採集整個系統

perf report > perf.txt

比如我對本地一個centos系統的採集結果如下(注意採集過程可能會出現很多找不到符號的情況,此爲正常現象,可能是在系統構建時,就剔除了部分可執行文件的函數符號,用於裁剪空間)

# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 3K of event 'cycles:ppp'
# Event count (approx.): 272061843461905
#
# Children      Self  Command          Shared Object                 Symbol
# ........  ........  ...............  ............................  ..............................................
#
    19.14%     0.00%  swapper          [kernel.kallsyms]             [k] cpu_startup_entry
            |
             --19.14%--cpu_startup_entry
                       |
                        --19.14%--cpuidle_enter
                                  |
                                  |--17.53%--__irqentry_text_start
                                  |          |
                                  |           --17.53%--smp_apic_timer_interrupt
                                  |                     |
                                  |                     |--2.03%--irq_exit
                                  |                     |          |
                                  |                     |          |--1.08%--tick_nohz_irq_exit
                                  |                     |          |          __tick_nohz_idle_enter
                                  |                     |          |
                                  |                     |           --0.95%--__softirqentry_text_start
                                  |                     |                     |
                                  |                     |                      --0.95%--run_timer_softirq
                                  |                     |                                |
                                  |                     |                                 --0.95%--call_timer_fn
                                  |                     |                                           |
                                  |                     |                                            --0.95%--process_timeout
                                  |                     |                                                      wake_up_process
                                  |                     |                                                      try_to_wake_up
                                  |                     |                                                      |
                                  |                     |                                                       --0.95%--select_task_rq_fair

	...
	
    19.14%     0.00%  swapper          [kernel.kallsyms]             [k] cpuidle_enter
            |
            ---cpuidle_enter
               |
               |--17.53%--__irqentry_text_start
               |          |
               |           --17.53%--smp_apic_timer_interrupt
               |                     |
 	


其一:整體打印了函數調用的樹狀結構,並表徵了一個符號佔用的19.14%具體是由哪些採樣的符號組成的。注意即使該符號沒有被採樣到,他也可能出現在這裏,因爲可能這個符號調用鏈的下層調用函數被採樣到了,故而這個符號就會體現在這裏,而且會把他所有調用到的函數被採樣的結果加總起來,得到children這一列。

其二:其中children一列的總和,是可能大於100%的,因爲對於每一個採樣點,如果能獲取到這個採樣點完整的調用棧,就會把這個採樣點的overhead加總到他的parent symbol的children那一列,而實際的調用棧可能是 A->B->C->D。如果D被採樣到了,且比例是1.1%,而A,B,C都未被採樣到。則 A,B,C的children那一列均是1.1%,D則self那一列和children那一列都是1.1%。都會呈現在上述report中,故而加總起來會超過100%。

這其實是 perf report 默認攜帶了 --children參數的結果,在3.16版本以後的內核perf report都是默認攜帶的–children的參數,會存在children那一列,並對該結果進行計算,以得到佔用cpu比例最高的最頂層調用。

perf report --no-children > perf.txt #默認讀取perf.data

可以得到如下結果,overhead的加總爲100%,同時可以看到具體符號的調用棧

# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 3K of event 'cycles:ppp'
# Event count (approx.): 272061843461905
#
# Overhead  Command          Shared Object                 Symbol
# ........  ...............  ............................  ..........................................
#
    14.55%  swapper          [kernel.kallsyms]             [k] smp_apic_timer_interrupt
            |
            ---smp_apic_timer_interrupt
               __irqentry_text_start
               cpuidle_enter
               cpu_startup_entry
               start_secondary

    14.55%  perf             [kernel.kallsyms]             [k] flat_send_IPI_mask
    12.93%  nvralarm         [kernel.kallsyms]             [k] copy_page
            |
            ---copy_page
               |
                --12.93%--do_huge_pmd_wp_page
                          handle_mm_fault
                          __do_page_fault
                          do_page_fault
                          page_fault
                          |
                           --12.93%--__reclaim_stacks
                                     0x12fc7


總結來說:

self:self記錄的是最後一列的符號(可以理解爲函數)本身採樣數佔總採樣數的百分比

目的: 找到最底層的熱點函數

Children:記錄的是這個符號調用的其他符號(理解爲子函數,包括直接調用和間接調用)的採樣數之和佔總採樣數的百分比

目的:找到叫高層的熱點函數

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