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

     

     

  • 相关阅读:
    【Jquery系列】详解Jquery对象和Dom对象
    将博客搬至CSDN
    【工具篇】.NET开发常用工具
    【ASP.NET MVC系列】浅谈jqGrid 在ASP.NET MVC中增删改查
    【SqlServer】【问题收集】必须声明标量变量
    【SqlServer】【问题收集】删除同一张表中完全相同的记录
    【SqlServer】【问题收集】阻止保存要求重新创建表的更改
    Java多线程编程中Future模式的详解<转>
    Java后端,应该日常翻看的中文技术网站<转>
    PostgreSql 函数
  • 原文地址:https://www.cnblogs.com/haoxing990/p/12811260.html
Copyright © 2020-2023  润新知