amd吧 关注:782,082贴子:17,932,468

【娱乐贴】关于分支预测写点什么吧

只看楼主收藏回复

看到前段时间有人搞混了分支预测和乱序执行,我想我还是写点关于分支预测的东西吧,乱序执行下次有时间再写,希望A黑们看了后下次能黑到点子上。这也不算是什么科普文,纯粹就是个人的心得体会,所以算是娱乐贴吧。

据说A吧不带动图的帖子秒沉……


IP属地:浙江1楼2020-08-18 13:55回复
    分支预测干什么的这种基本的知识我这里就不讲了,讲讲一些大家容易混淆的概念和一些分支预测技术的实现方法好了。由于我的知识体系都是10年前自学的,所以有些内容可能现在已经发生变化了,如有纰漏还请提醒我。


    IP属地:浙江2楼2020-08-18 14:00
    回复
      第一个,分支预测单元是干什么的?上面不是刚讲分支预测干什么的这种基本的知识我这里就不讲了,怎么又开始要讲了。好吧,因为我发现好多人这个概念上有问题,所以还是讲一下吧,从具体的作为逻辑单元的分支预测单元讲开去。
      分支预测单元主要解决两个问题,一是大家所熟悉的预测跳转指令是否需要跳转,二是大家经常忽视的预测跳转后的地址。
      前面那个大家可能已经很熟悉了,我先讲讲后面这个。为什么要预测预测跳转后的地址?跳转指令不是都带跳转后的地址的吗?主要是因为一般要到解码阶段才能知道这个指令是跳转指令以及跳转后的地址,而解码前还有一个取指阶段。在长流水线/超长流水线的CPU上,取指阶段可能需要3-6个时钟,而解码也可能需要2-4个时钟,如果等到完成解码再确定跳转后的地址,然后再根据该地址取下一条指令,就会产生5-10个时钟的流水线空泡。还有可能因为跳转的跨度比较大,跳转后的地址不在L1I中,需要从L2、L3甚至内从中载入,导致流水线中断,产生巨大的延时损失性能。所以相比是否跳转预测失败损失10-30个时钟,跳转地址未能预测可能会导致更大的性能损失。为此分支预测单元中有个专门的缓冲区,被称为Branch Target Buffers,简称BTB,这个缓冲运作方式类似cache,将近期的跳转指令的地址和跳转后的地址存储在其中,当取指到的指令地址与BTB中的某条记录一致时,就当取到的是一个跳转指令,如果预测跳转的结果为跳转,则根据BTB中同条记录的跳转地址继续取指,以此实现连续取指。并且可根据BTB的内容,将跳转地址所指向的指令预取到L1I中,以提高L1I的命中率。超出BTB容量的跳转指令信息会被丢弃,如果此时改跳转指令再次被取指,就需要等待解码完成才能知道其为跳转指令以及其跳转后的地址,导致流水线产生空泡,无法获得BTB命中的性能提升。所以当代CPU都有一个不小的BTB,以容纳足够多的跳转指令信息,例如K10的BTB为2048项,能存储近期2048个跳转指令的地址及其跳转地址。但BTB既然本质上是个cache,那也得遵循cache的规则,容量越大延时越高。BTB的延时要是太高了,就没存在意义了,等BTB检索到对应的数据时,如果解码都完成了,还要BTB里的数据干什么。所以CPU中的BTB也学cache一样分级,例如推土机的BTB为512项L1和5120项L2,使得推土机可以缓存的跳转地址是K10的2.75倍,而延时大多数情况下与K10相当甚至更好。而到了ZEN,BTB为16项L0、512项L1、4096项L2的结构,新增的L0估计是为了配合op cache,预测跳转后地址从op cache直接发射,使得op cache中可以缓存多个循环体。


      IP属地:浙江5楼2020-08-18 14:47
      回复
        顺手解答下Zen系列SuperPi差点,症结是否在此


        IP属地:广东来自Android客户端6楼2020-08-18 14:54
        回复
          坐上板凳,认真听讲。


          IP属地:湖北来自Android客户端7楼2020-08-18 15:03
          回复
            然后在回到预测跳转指令是否需要跳转上。关于这个技术上一直在推陈出新,但其实各种不同的分支预测技术下预测成功率提升的绝对值已经是微乎其微了。之前看到的一个评论就很有意思:某新的分支预测技术将预测失败率下降的50%——其实只是把成功率从98%提升到了99%而已。好了这些无聊的东西就不扯了,还说说说我所了解到的一些分支预测技术。
            最简单的就是不预测,所有跳转指令都当成需要跳转来执行,错了再清空流水线重来。非常憨的一个策略,但实际成功率能达到50%+。这是因为一个程序中有很多跳转指令都来自于循环,如果一个循环体循环了100次,前99次的跳转指令都是需要跳转的。
            然后就是静态预测,就是根据一个固定的规则来预测是否跳转。例如所有向后跳转的都跳转,所有向前的跳转都不跳转。这是因为向后跳转的基本是循环,而向前跳转的基本都是判断。静态预测的成功率能达到70%+,大量应用在一些对于性能无所有,但对功耗比较敏感的场景,例如某些嵌入式CPU。同时静态预测也作为大型复杂CPU动态预测因为没有足够信息无法预测时的预测结果。


            IP属地:浙江8楼2020-08-18 15:31
            收起回复
              接下来就是在大家的讨论中经常出现所谓的分支预测,也就是动态预测。
              动态预测最简单的就是2bit计数器,其原理就是每当某个跳转指令跳转时,该指令对应的计数器+1,而当跳转指令没有跳转时,该指令对应的计数器-1。最终计数器会有11、10、01、00四个值,预测时根据首位判断,如果是1预测为跳转,如果是0则预测为不跳转。这么设计是因为代码的分支流向总是具有倾向性,一些经常跳转,而另一些基本不跳转,通过计数器就能将2者区分开来。某个分支如果要从经常跳转翻转为不跳转,需要连续2次不跳转才行,这样就能避免因为偶尔的不跳转或跳转(例如循环结尾),导致预测状态的变化。2bit计数器的成功率一般能达到90%+,因为其结构简单,可以附加载BTB上,每项BTB的数据后面,扩展2bit来记录和表示是否跳转,在命中BTB时,同时预测是否跳转和预测跳转后的地址。


              IP属地:浙江9楼2020-08-18 16:01
              回复
                但2bit计数器遇见一些反复横跳的分支时,就无能为力了。例如跳转2次后又不跳转2次,之后又继续跳转2次,这种欠打的分支使用2bit计数器时预测成功率几乎为0。这时候就需要超级飞……咳咳,串台了……这时候就需要两级预测了,需要分支历史表(BHT)和模式历史表了(PHT)。具体原理就是记录一段跳转的历史,例如将跳转记为1,不跳转记为0,则前面提到这个熊孩子跳转指令的分支历史为11001100……将这个记录保存在BHT中,假设BHT每项为4bit,那就可以为某个跳转指令记录近4次的跳转记录,对应上面的例子,某个时刻BHT中的记录为1100。假设PHT每项为2bit,则对应有4种模式,即11、10、01、00。然后将BHT中对应的模式映射到PHT中,例如刚才的例子,BHT为1100,能分解的模式有11、10、00,分别映射到PHT的11、10、00三项中,因为01没有数据就先不管。然后将BHT中对应的后续跳转结果作为预测结果存储到对应的项中,例如BHT中1100的11后面是0,所以PHT中11项的预测结果为0,即不跳转。如果此时记录到该跳转指令已经连续2次跳转,按2bit计数器应该预测为继续跳转,而按两级预测则为不跳转。当BHT和PHT足够大的时候,两级预测的成功率可以达到95%+。


                IP属地:浙江10楼2020-08-18 17:02
                回复
                  但是两级预测非常消耗晶体管,2bit计数器一个跳转指令只需要2bit,两级预测,即便是上面假设的4bit BHT×2bit PHT,也需要16bit,规模大了8倍。而两级预测要想发挥出效能,一般需要10bit以上的BHT,如果再增加PHT,那规模就是指数级增长了。因此两级预测陷入2难境地,同等规模下,要不为了提高成功率加大BHT的长度而减少BHT的项数,但这样能够预测的跳转指令就少了;要不为了覆盖面增加BHT的项数而减少BHT的长度,但这样预测的成功率又下降了。为此两级预测又发展出了全局与本地分离的策略,每个CPU具有一个全局BHT,其不对应具体的跳转指令,一般会做的非常长,能够记录很长一段时间内所有的跳转指令的跳转情况。另外还有一个本地BHT,就是我们上面介绍的那样,每项对应一个跳转指令,只记录该跳转指令的跳转情况,但每项都比较小,只能记录某个具体跳转指令短期的跳转情况。然后增加一个选择器,根据全局BHT和本地BHT的成功率,选择最高的那个作为本次的预测结果。这就是局部/全局复合预测器了,也被称作锦标赛式预测器,其成功率一般会比单纯的两级预测器高1-2个点。


                  IP属地:浙江11楼2020-08-18 17:08
                  回复
                    在复合预测器中,还有一种奇葩被称为Agree预测器。其原理就是一个全局两级预测器加上一个结果计数器,结果计数器结构和原理和2bit计数器类似,预测成功-1,预测失败+1,然后取首位,1为失败,0为成功。最后将两者的结果做异或运算,1xor1=0、1xor0=1、0xor1=1、0xor0=0四种结果,分别对应预测器跳转,计数器失败,结果为不跳转;预测器跳转,计数器成功,结果为跳转;预测器不跳转,计数器失败,结果为跳转;预测器不跳转,计数器成功,结果为不跳转。这种预测器被仅被应用在NetBurst架构上,因为其结构简单搞笑,正好可以适应NetBurst高主频的要求。


                    IP属地:浙江12楼2020-08-18 17:30
                    回复
                      上面说了这么多,具体举个例子。就拿K10作为实例吧。
                      K10的分支预测单元主要由BTB、GHBC、RAS和ITP组成。
                      BTB为目标地址缓冲,大小为2048项,每项存储一个跳转指令地址和跳转后地址。
                      GHBC为全局双模计数器,大小为16384项,每项为一个2bit计数器,用于记录对应跳转指令的跳转情况。
                      RAS为返回地址堆栈,大小为24项,堆栈结构,配合BTB预测调用的返回地址。
                      ITP为间接目标预测,大小为512项,每项存储一个间接跳转指令指向的寄存器,用于预测多个动态目标的间接分支。
                      K10的预解码信息存储于L1I,每条指令前都有一个2bit跳转标记,0为不跳转、1为总是跳转、2为动态预测、3为使用返回地址堆栈。当某个指令首次解码后发现是跳转指令时,程序计数器均按跳转地址继续取指,并将该指令的地址和跳转后的地址存储于BTB,同时将L1I中该指令的跳转标记为1,如果该指令后续结果为不跳转,则将L1I中该指令的跳转标记为2,同时为该指令分配1项GHBC,初始化结果为01。当某个指令被取指时,根据其地址判断是否是跳转指令,如果BTB中保存有对应的地址,则判断其为跳转指令,并调整程序计数器按BTB中的跳转后地址继续取指,如果L1I未缓存该地址,则将该地址整行预取到L1I中。如果该指令的跳转标记为2,则检索对应的GHBC项,当该项计数器首位为1时给出跳转的预测,首位为0时给出不跳转的预测。该指令后续结果为跳转,则该项计数器+1,结果为不跳转,则该项计数器-1。如果BTB或GHBC已满,则删除最久远的记录给新的跳转指令使用。


                      IP属地:浙江13楼2020-08-18 18:48
                      回复
                        技术贴需要加精


                        IP属地:上海来自iPhone客户端14楼2020-08-18 18:58
                        回复
                          我们可以看到K10的分支预测主要采用了2bit计数器的技术,再举个采用锦标赛式预测器技术的例子。本想以牙膏厂的CPU为例,但因为具体缺少具体参数,还是作罢了,最后还是拿龙芯的GS464E做例子。
                          GS464E的分支预测单元主要由BTB、GBHT、LBHT、GSEL、RAS和JBTAC组成。
                          BTB为目标地址缓冲,大小为128项,每项存储一个跳转指令地址和跳转后地址。
                          GBHT为全局分支历史表,大小为16384项,猜测其历史长度为14bit。
                          LBHT为局部分支历史表,大小为16384项,猜测其能为128个分支指令按8bit的历史长度提供预测。
                          GSEL为全局选择表,大小为16384项,能存储GBHT和LBHT预测的成功情况,为使用GBHT还是LBHT的预测结果提供选择依据。
                          RAS为返回地址堆栈,大小为16项,堆栈结构,配合BTB预测调用的返回地址。
                          JBTAC大小为1024项,用于预测多个动态目标的间接分支。
                          某个指令在首次解码发现是跳转指令时,将其地址和跳转地址记录到BTB中,同时按跳转地址继续取指,并将其跳转结果存储到GBHT中。GBHT会为所有跳转指令构建一个16384种模式的历史表,每次根据近期14次不区分跳转指令的跳转情况,对照模式历史表给出GBHT的预测结果。如果某个跳转指令在GBHT的近期14次跳转历史中占8次时,LBHT会为其构建一个256种模式的局部模式历史表,每次根据该跳转指令近期8次的跳转历史,对照模式历史表给出LBHT的预测结果。如果该跳转指令没有被LBHT所记录,则按静态预测规则作为LBHT的预测结果。GSEL记录近期16384个跳转指令GBHT和LBHT的预测成功情况,然后根据GBHT和LBHT的成功情况选择成功率高的那个的作为当前实际的预测结果。


                          IP属地:浙江16楼2020-08-19 01:31
                          回复
                            问问楼主是看那本书,我也想看


                            IP属地:天津17楼2020-08-19 01:32
                            收起回复