我想知道用2次乘法替换分支是否更快(由于高速缓存未命中罚分)?
这是我的情况:
float dot = rib1.x*-dir.y + rib1.y*dir.x;
if(dot<0){
dir.x = -dir.x;
dir.y = -dir.y;
}
我正试图用以下内容替换它:
float dot = rib1.x*-dir.y + rib1.y*dir.x;
int sgn = (dot < 0.0) - (0.0 < dot ); //returns -1 or 1 (no branching here, tested)
dir.x *= sgn;
dir.y *= sgn;
答案 0 :(得分:2)
分支并不意味着缓存未命中:只有指令预取/流水线操作受到干扰,因此您可以在编译时使用它来阻止某些SSE优化。
另一方面,如果仅使用x86指令,speculative execution将让处理器正确地开始执行最常用的分支。
另一方面,如果你在50%的情况下输入if,那么你处于最糟糕的状态:在这种情况下,我会尝试寻找SSE流水线并使用SSE优化执行,可能会得到来自this post的一些提示,与第二段代码一致。
但是,对代码进行基准测试,检查生成的汇编程序,以便为此优化找到最佳解决方案,并获得正确的见解。并最终让我们更新:)
答案 1 :(得分:1)
乘法的成本取决于几个因素,无论是使用32位还是64位浮点数,以及是否启用SSE。根据此来源,两次浮点乘法的成本为10个周期:http://www.agner.org/optimize/instruction_tables.pdf
分支机构的成本也取决于几个因素。根据经验,不要担心代码中的分支。 CPU上的分支预测器的确切行为将定义性能,但在这种情况下,您应该预期分支最多是不可预测的,因此这可能会导致很多分支误预测。根据此来源,分支错误预测的成本为10-30个周期:http://valgrind.org/docs/manual/cg-manual.html
任何人都可以给出的最佳建议是分析和测试。我猜想在现代Core i7上,两次乘法应该比分支if the range of input varies sufficiently as to cause sufficient branch mispredictions as to outweigh the cost of the additional multiplication
快。
假设50%的未命中率,分支的成本平均为15个周期(30 * 0.5),浮动mul的成本为10个周期。
编辑:添加了链接,更新了估算的指令费用。