与 0 进行比较与与某个值进行比较是不是更快?
Posted
技术标签:
【中文标题】与 0 进行比较与与某个值进行比较是不是更快?【英文标题】:Is it quicker to compare against 0 vs compare against a value?与 0 进行比较与与某个值进行比较是否更快? 【发布时间】:2019-07-12 16:46:58 【问题描述】:其中一个循环是否比另一个更快? 我一直使用#2,认为与零比较比与汇编中的值比较更快,因为 CMP 指令执行起来更简单,但是查看一些 ARM 手册我看不到任何可以证实这一点的东西。它是否取决于您使用的指令集和处理器?这是真的吗?
//#1
while(1)
static uint8_t counter = 0;
counter++;
if(counter == 4)
counter = 0;
//do something
//#2
while(1)
static uint8_t counter = 4;
counter--;
if(counter == 0)
counter = 4;
//do something
【问题讨论】:
也许是的。也许没有。取决于架构、编译器、优化级别和上下文。最好编写对读者有意义的代码,不要为微优化而烦恼。 这可能比与变量进行比较要快。例如,如果执行循环的顺序无关紧要,但速度至关重要,我可能会从变量(可能从x - 1
)开始向下计数,以节省每个循环的内存访问。处理器通过递减后的处理器标志知道循环何时完成:不执行比较。
在汇编中,是的,与零比较通常更快,因为大多数处理器都有特定的指令,而与一个值比较需要从内存中加载该值。但是大多数现代编译器会注意到您实际上并没有使用索引并为您转换它。
这在 arm 上更快,因为可以使用“subs”与“sub”。我已经看到编译器在更高的优化级别上进行了这种转换。甚至可能 counter 是多余的。向上计数如何比向下计数“更有意义”?取决于问题空间,任何一种都可能更有意义,我不认为其中一种过于迟钝。
decrement 或 sub 指令通常会在结果为零时设置一个 cpu 标志(zeroflag),因此根本不需要显式比较。因此,后一个示例在许多架构上可能更快。
【参考方案1】:
很难说。专注于发布模式构建,它在很大程度上取决于上下文,并且您并没有给出所有内容,尤其是缺少循环中断条件使得无法弄清楚。
通常,如果迭代次数是立即数,只要循环内没有循环计数器依赖项,编译器就会将循环构造转换为快速倒数到零。
无论如何,在 Cortex-A 系列等现代超标量架构上,cmp
等简单的 ALU 指令将被很好地“隐藏”,因此在大多数情况下不会花费额外的周期。
实际上更损害性能的是counter
的static
声明,它会自动转换为内存RW。尽可能避免这种情况。
此外,如果您只是希望do something
每四次迭代运行一次,if ((counter & 3) == 0)
可能是更好的解决方案,可以消除计数器重置。同样,这完全取决于您未提供的上下文(“做某事”的长度)。
附带说明,局部变量最好是 32 位变量,除非您有充分的理由声明它们,否则任何更少的变量都可能转化为额外的模相关指令,例如 uxtb
、and
等。
将循环计数器倒数为零是轻而易举的事,但如果您想要获得最佳性能,还有很多事情需要考虑。
【讨论】:
你说得对,缺少上下文很重要,在阅读一些 cmets 之前没有意识到它的相关性。循环永远不会中断,因为它实际上不是一个循环,它是一个 88kHz 的定时器中断,我正在尝试启动一个 SPI 读取每个中断调用并在每 4 个中断调用(22kHz)设置一个 DAC 输出。认为这是无关紧要的,因为从未使用过循环的索引。有问题的架构是 STM32L4 系列以上是关于与 0 进行比较与与某个值进行比较是不是更快?的主要内容,如果未能解决你的问题,请参考以下文章