-1

我想知道用 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;
4

2 回答 2

2

分支并不意味着缓存未命中:只有指令预取/流水线受到干扰,因此您可能会在编译时阻止一些 SSE 优化。

另一方面,如果只使用 x86 指令,推测执行将让处理器正确地开始执行最常用的分支。

另一方面,如果您在 50% 的情况下输入 if,那么您处于最坏的情况:在这种情况下,我会尝试寻找 SSE 流水线并使用 SSE 优化执行,可能会从这篇文章,与您的第二个代码块一致。

但是,对您的代码进行基准测试,检查生成的汇编程序以找到此优化的最佳解决方案,并获得正确的见解。并最终让我们更新:)

于 2014-03-22T23:45:32.503 回答
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 个周期。


编辑:添加链接,更新估计指令成本。

于 2014-03-22T23:45:57.513 回答