記一次perf branch-misses 100%的調試經歷


 

背景

在公司arm64平台上增加了spe功能,是個用於性能分析的利器,目前只是該功能實現了,但是該功能是否正確,就有待驗證了。

因為spe支持分支預測檢測功能,這個功能對優化我們系統性能來說實在太重要了,所以首當其沖的就是驗證該分支預測的准確性了。

什么是分支預測(branch prediction)

直白的說,分支預測就是指令存在多個if else判定的情況下,cpu去預測下一步即將執行哪一調指令,通過預測,優化指令執行效率,達到提高系統性能的目的。

if { 
...
} else  if {
...
} else if { 
....
}else
...

但是若程序中出現較多這樣的指令,分支預測的准確率就會降低,當然系統性能也會受到影響,所以通常不建議程序中存在存在過多的跳轉或者判定指令,倘若通過某種手段檢測分支預測

失敗的次數,對改進程序設計,優化程序執行效率,會有很大的借鑒意義。

怎么構造分支預測模型呢?

去構造分支預測模型不是一件容易的事,尤其是不了解代碼下指令執行的意圖,筆者思考痛苦的很久,都沒有找到較為合理的針對分支預測檢測方法,夜思冥想最后再師兄的點播下,終於有了點路子。

既然我的需要驗證分支預測的正確性,我只要構造一個程序,其分支預測永遠為100%,什么樣的程序分支預測永遠為100%,答案是順序執行的,但是順序執行還遠遠不夠,你還需要抓取其分支預測情況,所以你還需要讓程序長時間運行,有了這兩點后,我寫出了個100%的分支預測命中的程序。

int main()
{
    while (1);    
    return 0
}

代碼很簡單,可是你能否想象,要說服自己構造這么個東西,可整整耗費了本人一下午。

黎明前的黑暗

gcc -O0 main.c,輕輕送編譯完成,開始測試,測試branch-misses還是挺簡單的,perf  stat -e branch-misses  ./a.out

 Performance counter stats for './a.out':

             25791      branch-misses

       3.307213447 seconds time elapsed

       3.303546000 seconds user
       0.003999000 seconds sys

出來的結果永遠是亮瞎人的狗眼,很顯然,分支預測100%是不可能了,我再次陷入了絕望,開始懷疑自己這么構造的分支預測模型是否正確了,只能進行各對比測試了,例如把鍋甩給

arm,到x86平台上去試試,發現還是一樣,哎,又是郁悶的一下午,我有點想放棄,很偶然的一次想法突然給了我思路,為啥我死循環沒有導致系統卡死?,因為我沒有指定CPU上運行,系統很有可能為了均衡,進行了調度,有了思路,我開始綁核測試。

taskset -c 1 ./a.out

可能現實總喜歡啪啪打臉.

 

 看着運行百分之百的cpu,我再次陷入了沉思,我想放棄了。

Performance counter stats for 'CPU(s) 1':

             21473      branch-misses

       2.059929220 seconds time elapsed

branch-misses有增無減少,看樣子,我真的不知道該怎么處理了。

艱難的值守總會迎來希望

又事一次很隨意的操作,讓我思路徹底挖開,我在perf的時候加了一個-g指令,看看其函數調用流程。

Samples: 11K of event 'branch-misses', Event count (approx.): 2031156
  Children      Self  Command          Shared Object               Symbol
+   35.56%     0.00%  swapper          [kernel.vmlinux]            [k] cpu_startup_entry                                         ◆
+   35.56%     0.02%  swapper          [kernel.vmlinux]            [k] do_idle                                                   ▒
+   35.01%     0.00%  swapper          [kernel.vmlinux]            [k] secondary_start_kernel                                    ▒
+   32.89%    10.08%  swapper          [kernel.vmlinux]            [k] arch_cpu_idle                                             ▒
+   22.85%     0.00%  swapper          [kernel.vmlinux]            [k] el1_irq                                                   ▒
+   22.85%     0.00%  swapper          [kernel.vmlinux]            [k] gic_handle_irq                                            ▒
+   22.85%     0.00%  swapper          [kernel.vmlinux]            [k] __handle_domain_irq                                       ▒
+   22.85%     0.00%  swapper          [kernel.vmlinux]            [k] irq_exit                                                  ▒
+   22.68%     7.16%  swapper          [kernel.vmlinux]            [k] __do_softirq                                              ▒
+   20.93%     0.00%  /home/staragent  libc-2.30.so                [.] thread_start     

好像這些都和我執行的死循環無關,看樣子,我抓取的branch-misses都不是我應用程序產生的,為了確定我的判定,我再次單獨perf抓取了死循環的調用情況。

 Children      Self  Command    Shared Object     Symbol
-  100.00%    27.56%  a.out       a.out           [.] main                                                                      ◆
   - 91.49% main                                                                                                                 ▒
      - 65.31% el0_irq                                                                                                       ▒
           gic_handle_irq                                                                                                        ▒
           __handle_domain_irq                                                                                                   ▒
           irq_exit                                                                                                              ▒
         + __do_softirq                                                                                                          ▒
      - 7.13% work_pending                                                                                                       ▒
         - do_notify_resume                                                                                                      ▒
            + 3.00% task_work_run                                                                                                ▒
   - 8.51% _start                                                                                                                ▒
        main                                  

看樣子思路明晰起來,這些都不是我代碼執行導致,是中斷導致,因為cpu產生了中斷,去處理別的事情,進入內核態或者別的,導致出現了branch-misses的情況。

那程序運行在用戶態,按照我這么理解,那用戶態branch-misses肯定為0咯,我們試試看。

./perf record -g  -e branch-misses:u ./a.out

                                               ┌─Error:───────────────────────────┐
                                               │The perf.data file has no samples!│
                                               │                                  │
                                               │                                  │
                                               │Press any key...                  │
                                               └──────────────────────────────────┘

看樣子還真是系統中斷導致cpu去執行其他任務出現的branch-misses, 值得高興的我合入的spe功能通過抓取的數據驗證,也是正確的,值得慶祝下。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM