数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 1796|回复: 7

[STM] 震惊!IT居然是鸡肋,分支消除竟是庸人自扰,旋转跳跃才是高效常态?...

[复制链接]
发表于 2020-4-12 21:03:57 | 显示全部楼层 |阅读模式
本帖最后由 la45088d1 于 2020-4-12 21:09 编辑

       现代处理器一般都是流水线结构,除了老旧的古董以外(比如STC之流),看不见没有流水线技术的处理器了。流水线把每条指令的执行过程进行不同程度的细化,使得相邻的指令可以处于不同的执行阶段进而复用运算或者控制单元,达到一时钟执行多条指令,一条指令具有很低的平均时钟周期进而提高性能。
      但是,流水线模型只对顺序执行结构有奇效,对于大量的分支结构不仅没啥用反而起了负增益,白白浪费执行时间。对于每个分支指令,要么停下来等待分支结构运算出来,再继续流水处理;要么使用分支预测器提前做准备,消除分支结构带来的气泡。对于第一种,等待对于流水线来说无疑降低了性能,并且一旦跳转成立,流水线进行清空重装依然浪费执行时间。第二种在理想的情况下,可以做到几乎无视分支结构的负增益,如果预测不跳转,那么流水线照旧向下流水即可无损耗,如果预测跳转,处理器将在跳转地址处预先取指,使得真正的跳转发生后流水线不必再经历从头开始的清空重装过程,提高了效率。但是一旦预测失败,不仅得不到效率提升,反而还要赔上错误修正的时间。具体可自行查阅资料。
      所以,对于程序来说,能够保证功能相同的情况下,尽可能地消除分支总是好的,无论分支预测器多么精确。对于ARM指令来说,所有指令均可条件执行,所以可以用条件执行消除局部的分支,或者说是微跳转。对于Thumb指令来说,1代只有B能够条件执行,其它指令均不支持;2代的Thumb指令集加入了IT指令,支持将最大4条连续的普通指令修饰成条件指令。使用条件指令一般来说有利于消除微跳转,提高效率,不是我说的,是某些编程指南说的,但事实真的如此吗?

      这是两段功能一致的代码,在真机上连接调试器从21行执行到29行并统计执行时间。结果是什么样的呢?可能还是有人觉得图一快吧,原来我也是这么认为的,但是理论和现实的血腥碰撞让你知道什么叫做绝望!!第一段代码执行时间为363ns,第二段执行时间为345ns,两者差18ns,恰好是2个时钟周期。



不知道为啥图挂了直接插入文本吧!
  1.                                         CBZ      R2,GenerationStop
  2. ;If tone generation is forbidden, do nothing but return.
  3.                                         BL       TonesGenerate
  4.                                         CBNZ     R0,BuffDataRenew
  5. ;Execute subroutine and check its return value to determine whether to refresh the buff or
  6. ;not.
  7. GenerationStop          POP      {R15}
  8. ;Directly return when no extra operation is needed.
  9. BuffDataRenew       LDR      R1,=ToneDataCurAddr
复制代码
  1.                                         MOVS     R0,R2
  2. ;If tone generation is forbidden, do nothing but return.
  3.                                         BLEQ     TonesGenerate
  4.                                         CMP      R0,#0x00
  5. ;Execute subroutine and check its return value to determine whether to refresh the buff or
  6. ;not.
  7.                         POPEQ   {R15}
  8. ;Directly return when no extra operation is needed.
  9.                           LDR      R1,=ToneDataCurAddr
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x

打赏

参与人数 1家元 +15 收起 理由
人艰不拆了 + 15

查看全部打赏

发表于 2020-4-12 21:07:58 | 显示全部楼层
说啥呢,哈哈:dizzy:
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-12 21:15:36 | 显示全部楼层
       我们看看ARM的内核手册对Cortex-M3的特性描述:



       其中提到了IT的行为:,STM32的PM0056号文件提到了一个与此特性对应的关键寄存器,如下图5所示,说明在默认的情况下IT指令应该可以做到不占用额外的时钟周期,这才是高效的关键。默认情况下SCB_ACTLR的第2位应该是0对应IT折叠开启。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-12 21:42:20 | 显示全部楼层
       我们来精密的算笔账吧!对于指令段1,21条指令毫无疑问的是16-bit形式,显然后面的BL指令之前还有一条IT,只是没写出来编译器自动补全。按照IT0周期特性,实际上从21-23行应该只花费2个周期(条件不满足时)或者一个正常的BL执行时间加上函数执行返回时间,设为Tx个周期,同样,24行依然是16-bit的CMP与之后的IT折叠,所以从24-27行应该是2个周期(条件不满足时)或者一个POP的执行时间,2周期。在观察的单次执行流程中该段代码BL总是执行,但是POP没有执行,所以总时间应该是1+Tx+1+1=3+Tx个周期达到29行;
       对于指令段2,21行CBZ不成立是一个周期,而24行的CBNZ成立,周期是1+P,这个P在arm、内核描述文件的定义如图6所示:,这个P是不固定的,但是根据我的观察,跳转指令B一般会消耗3个左右的周期,所以我一种认为P=2,导致了预估错误。实际上对于CBZ/CBNZ的P是几呢,实际上经过在线调试P=0,CBZ/CBNZ的执行时间均为单周期的,无论跳转是否成立!所以指令段2的正确执行总时间应该是1+Tx+1=2+Tx。而在错误的估计中这个时间则是1+Tx+3=4+Tx,这就导致了代码段1比较香的错误认知。
       更雪上加霜的是,经过在线调试发现,IT折叠机制根本没有起作用,也就是说IT指令固定地开销一个周期,并不是0周期的,所以代码段1的真实运行时间应该是1+1(未折叠)+Tx+1+1(未折叠)+1=5+Tx。
       所以这次的乌龙主要是CBZ/CBNZ的妖孽般的执行速度和IT折叠机制的失效,使得对于运行时间的错误估计,此外以上分析两段指令的时间差应该是3,猜想可能是这里的CBNZ开销了2个周期即P=1吧,毕竟ARM都说不固定了,可能只有分支预测器命中后才会有P=0的效果吧!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-12 21:59:47 | 显示全部楼层
本帖最后由 la45088d1 于 2020-4-12 22:22 编辑

       所以一切的一切不仅让我深思到底怎么做才是最好的呢?在今天之前我对Coretx-M3的偏见就是,跳转总是3个周期,分支指令失败总是1个周期,并可能带有流水线停顿的情况,在这个偏见下,对于两段一样的代码:
1:
          CMP  Rx,#0x00
          ITT   EQ
          OP1EQ  Ry, Rz

          OP2EQ  Rm, Rn
          OP3      Ra,Rb
          ......
2:
          CBNZ Rx,Lable
          OP1  Ry, Rz
          OP2  Rm, Rn
Lable  OP    Ra,Rb
         ......
       那么,从条件块到第3条普通指令,代码段1的执行时间无论条件成立与否总是1+2=3周期;对于代码段2,条件为假时执行周期是3,条件为真时是1+1+1=3,当真假条件概率无论如何时将得到两段代码时间一样的错误结论。而根据今天的发现我们对上述结论进行修正,代码段1的执行时间是1+1+2=4周期,无论条件成立与否;对于代码段2,条件为假时执行周期是1,条件为真时是1+1+1=3。当真假概率一致时,代码段1的平均周期是4,代码段2的平均周期是2!是不是大跌眼镜啊?分支跳转居然击败了条件执行??我们知道对于IT指令最大可以捆绑4条常规指令,所以对于代码段1的风格来说,随着条件指令越多,执行时间越长,这个时候还不如直接跳过无用的指令更好!
       那么,对于不可用CBZ/CBNZ的场合呢?请看如下两段代码:
1:
          CMP  Rx,#imn
          ITT   HI
          OP1HI  Ry, Rz
          OP2HI  Rm, Rn
          OP3HI  Ra,Rb
          OP4LS   Rc,Rd
          POP     {Ra-Rd,Rn}
2:
          CMP  Rx,#imn
          BLS   Lable
          OP1   Ry, Rz
          OP2   Rm, Rn
          OP3   Ra,Rb
          POP   {Ra-Rd,Rn}
Lable   OP4   Rc,Rd
          POP   {Ra-Rd,Rn}

       那么,从条件块到函数返回,代码段1的执行时间无论条件成立与否总是1+4=5周期;对于
代码段2,条件为假时执行周期是5,条件为真时是1+3+1=5,当真假条件概率无论如何时将得到两段代码时间一样的错误结论。而根据今天的发现我们对上述结论进行修正,代码段1的执行时间是1+1+4=6周期,无论条件成立与否;对于代码段2,条件为假时执行周期是5,条件为真时是1+1+P+1=3+P,这个P有时候可能很小,也可能等于2。当真假概率一致时,代码段1的平均周期是6,代码段2的平均周期是5,按照最一般情况下P=2,因为各种原因比如分支预测器没有命中!是不是大跌眼镜啊?分支跳转还是居然击败了条件执行??所以对于代码段1的风格来说,随着条件指令越多,执行时间越长,这个时候依然是直接跳过无用的指令更好!

       所以,IT指令到底有啥用,在强大的分支处理能力下,似乎没有太大的价值,也在很多情况下起不到原先的初衷消灭局部分支提高效率?
回复 支持 反对

使用道具 举报

发表于 2020-4-12 22:25:28 来自手机浏览器 | 显示全部楼层
UC浏览器上班的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-12 22:30:59 | 显示全部楼层

UC浏览器那些垃圾小编就算了吧,都不会用词,这个才叫真的震惊,事实与所有的官方描述都不符合,真是吓死个人。所以我一直都是我秀我自己?那还考虑啥分支消除,直接跳转完事了还省心是不是。
回复 支持 反对

使用道具 举报

发表于 2020-5-4 09:12:34 | 显示全部楼层
哈哈,我看STC8G已经有流水概念了。那些个所谓大部分指令单周期完成,大概是这样实现的。
这个STM,建议向厂商发邮件质询,我还挺好奇的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-6-30 00:36 , Processed in 0.249601 second(s), 11 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表