【发布时间】:2015-11-24 06:51:10
【问题描述】:
我的代码频繁调用具有多个(不可预测的)分支的函数。当我进行分析时,我发现这是一个小瓶颈,大部分 CPU 时间都用于条件 JMP。
考虑以下两个函数,其中原始函数有多个显式分支。
void branch_example_original(void* mem, size_t s)
{
if(!(s & 7)) {
/* logic in _process_mem_64 inlined */
}
else if(!(s & 3)) {
/* logic in _process_mem_32 inlined */
}
else if(!(s & 1)) {
/* logic in _process_mem_16 inlined */
}
else {
/* logic in _process_mem_8 inlined */
}
}
这是新功能,我试图删除导致瓶颈的分支。
void branch_example_new(void* mem, size_t s)
{
const fprocess_mem mem_funcs[] = {_process_mem_8, _process_mem_16, _process_mem_32, _process_mem_64};
const uint32_t magic = 3 - !!(s & 7) - !!(s & 3) - !!(s & 1);
mem_funcs[magic](mem, size >> magic);
}
但是,当我分析新代码时,性能仅提高了约 20%,而且 CALL 本身(到 mem_funcs 数组中的一个 func)花费了很长时间。
第二个变体是否只是一个更隐含的条件,因为 CPU 仍然无法预测将被调用的函数?我是否正确假设这与分支目标预测有关?
为什么会发生这种情况,还有其他解决方案吗?
编辑:
感谢您的想法,但我也想解释一下为什么会发生这种情况。
【问题讨论】:
-
这看起来像是一个处理对齐/未对齐内存地址的函数。你能做些什么来保证对齐吗?你知道最常走哪条路吗?你能预测调用点的对齐方式吗(例如,如果你知道你的内存块是 64 字节对齐的)?
-
它确实处理对齐/未对齐的内存,但在这种情况下我无法保证大小或对齐。
-
@nneonneo:即使您不能保证对齐或大小,您通常也可以进行一次字节介绍,直到对齐,然后向量直到您在 15B 以内最后,然后是一个字节的清理。所以你大部分时间都在做大的对齐块,使用标量设置/清理。
-
达夫的设备?或其衍生物。
标签: c++ c optimization x86 branch-prediction