我在论文中看到了一句话"将分支转换为数据依赖关系以避免错误预测的分支。" (第6页)
我想知道如何将代码从分支更改为数据依赖。
这是论文:http://www.adms-conf.org/p1-SCHLEGEL.pdf
更新:如何在二进制搜索中转换分支?
答案 0 :(得分:11)
基本思想(我认为)将改变:
if (a>b)
return "A is greater than B";
else
return "A is less than or equal to B";
成:
static char const *strings[] = {
"A is less than or equal to B",
"A is greater than B"
};
return strings[a>b];
对于二进制搜索中的分支,让我们考虑“正常”二进制搜索的基本思想,通常看起来(至少含糊地)如下:
while (left < right) {
middle = (left + right)/2;
if (search_for < array[middle])
right = middle;
else
left = middle;
}
我们可以用几乎相同的方式摆脱分支:
size_t positions[] = {left, right};
while (left < right) {
size_t middle = (left + right)/2;
positions[search_for >= array[middle]] = middle;
}
[对于通用代码,请使用left + (right-left)/2
代替(left+right)/2
。]
答案 1 :(得分:0)
删除分支并不总是最佳的,甚至(特别是)使用这样的简单二进制条件。在以前的各种情况下,我已经考虑过以类似的方式删除分支。在运行到循环中具有条件分支的代码比等效的无分支代码运行得更快的实例之后,我对处理器执行策略进行了一些研究。
我知道ARM指令集有条件指令,它可以使条件分支比文中的无分支代码更快,但我正在研究一个英特尔(并且分支不是那个可以照顾)。事实证明,包括英特尔在内的现代CPU有时会将普通指令转变为条件指令:如果分支的两个端点足够短,它们会使用急切的执行。也就是说,CPU将在管道中放置两个可能的路径并执行它们,并且只有在条件已知时才保持正确的结果。这避免了在不必索引数组的情况下进行错误预测的可能性。有关详细信息,请参阅https://en.wikipedia.org/wiki/Speculative_execution#Variants。
处理器需要大量详细的知识才能为其编写最佳代码,即使在汇编中也是如此。这使得“天真”实现有时可能比忽略某些CPU特性的手动优化实现更快。优化编译器也会发生同样的事情:有时编写更复杂的“优化”代码会破坏编译器的一些优化,导致可执行文件比编译器可以完全优化的简单实现更慢。
如果有疑问并且性能至关重要并且有时间,通常最好同时尝试两种方式,看哪哪种更快!