关于代码性能,我很好奇这种情况,因为它一次又一次出现。
int val; //can be 0 or 1
if (val)
global_var += val
OR:
int val; //can be 0 or 1
global_var += val
基本上,在性能,分支错误预测或不必要的递增0方面,哪些更昂贵?这里有一般规则,还是个案有关?
答案 0 :(得分:8)
对于C代码(或几乎任何其他语言中的代码,就此而言)的性能,人们无法有意义地说出来。或许可以有意义地谈论使用一个特定版本的一个编译器编译的代码的性能,在针对特定体系结构的特定优化级别上执行并在该体系结构的特定实现上执行,但即使这样,您也会留下许多事情(I例如,当可执行文件的名称发生变化时,某人经过仔细手动调整的代码会遭受50%的性能回归。
除此之外,在大多数现代架构中,比较,条件分支和添加指令都是单周期操作(并且在分支上经常存在执行端口限制)。在这样的体系结构中(除非你的目标是非常奇特的东西,否则你可能会遇到的所有体系结构),单个添加总是至少与条件添加一样快,从而产生非常不寻常的性能假象。
分支误预测成本根本不会进入。当你进行条件分支(甚至忽略错误预测成本)时,你可以简单地完成添加。
在这个快速和肮脏的分析中有一些极端情况:例如,如果许多工作线程以相同的方式使用global_var
,并且几乎所有工作线程都使用val
global_var
为零,可以构造一些示例,其中使用条件增量确实更快,因为它减轻了global_var
所驻留的高速缓存行的大部分争用。或者,val
实际上可能是一种内存映射方式,用于访问具有极慢读取或写入速度的某些外来硬件;再次,如果global_var
通常为零,则有条件地进行增量可能是一个胜利。然而,所有这些例外都是相当专业的案例,大多数程序员都不会遇到这些例外(而那些遇到过他们的人希望能够充分了解他们自己在做这项分析时所做的工作)。还要注意,在所有这些极端情况下,分支预测的成本都不是问题;相反,访问{{1}}的成本会增加问题的兴趣。
答案 1 :(得分:1)
其中任何一个的代码都是如此之快,以至于实际上并不重要......
有人可以猜测你的架构以及从哪种存储类型中提取哪个值以及它在缓存中的可能性有多快,如果你的架构中有这个值的话......他们都有自己的利弊......但总的来说,避免分支更为可取。
避免使用分支是优选的,不仅因为许多体系结构中的跳转速度较慢......而且因为它们允许编译器执行更多优化,并降低复杂性......
较小的复杂性是好的。
错误存在于复杂性中。