记一次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功能通过抓取的数据验证,也是正确的,值得庆祝下。

 

 

 

 

posted @ 2020-04-30 21:30  haoxing990  阅读(3233)  评论(0编辑  收藏  举报