C++ 以下钻头操作的优化机会?
你认为Haswen函数有优化的空间吗(见下文) 我认识到将参数类型从C++ 以下钻头操作的优化机会?,c++,c,optimization,64-bit,bit-manipulation,C++,C,Optimization,64 Bit,Bit Manipulation,你认为Haswen函数有优化的空间吗(见下文) 我认识到将参数类型从\uuuu int64更改为unsigned\uuuu int64会使函数更快,因此我认为可能还有优化的机会 更详细的信息: 我正在写一个游戏。最近,我很困地使用探查器,并认识到haswen函数占用了大量cpu时间。该函数使用一个播放器的连接四块板的位板表示。我在基准源代码中找到的函数本身。位板表示形式如下所示: . . . . . . . TOP 5 12 19 26 33 40 47 4 11 18 25 32
\uuuu int64
更改为unsigned\uuuu int64
会使函数更快,因此我认为可能还有优化的机会
更详细的信息:
我正在写一个游戏。最近,我很困地使用探查器,并认识到haswen函数占用了大量cpu时间。该函数使用一个播放器的连接四块板的位板表示。我在基准源代码中找到的函数本身。位板表示形式如下所示:
. . . . . . . TOP
5 12 19 26 33 40 47
4 11 18 25 32 39 46
3 10 17 24 31 38 45
2 9 16 23 30 37 44
1 8 15 22 29 36 43
0 7 14 21 28 35 42 BOTTOM
职能:
// return whether newboard includes a win
bool haswon(unsigned __int64 newboard)
{
unsigned __int64 y = newboard & (newboard >> 6);
if (y & (y >> 2 * 6)) // check \ diagonal
return true;
y = newboard & (newboard >> 7);
if (y & (y >> 2 * 7)) // check horizontal -
return true;
y = newboard & (newboard >> 8);
if (y & (y >> 2 * 8)) // check / diagonal
return true;
y = newboard & (newboard >> 1);
if (y & (y >> 2)) // check vertical |
return true;
return false;
}
谢谢
编辑:CPU是x86,32位体系结构,我使用的是Visual Studio 2008快速版的编译器。优化标志为/O2/Oi/GL
我尝试了本·杰克逊建议的haswon2函数。来自Microsoft编译器的程序集,带有发布版本(/O2/Oi/GL)的默认优化标志,显示几乎没有运行时差异。与gcc相比,VC编译器似乎不能利用不能严格按顺序计算每个条件的优势
结果:
哈斯旺原文:
本·杰克逊的哈斯旺2号:
Edit2:
哈斯旺大会:
00401A10 mov eax,dword ptr [esp+4]
00401A14 mov ecx,dword ptr [esp+8]
00401A18 push ebx
00401A19 push esi
00401A1A push edi
00401A1B mov edx,eax
00401A1D mov edi,ecx
00401A1F shrd edx,edi,6
00401A23 mov esi,edx
00401A25 shr edi,6
00401A28 and esi,eax
00401A2A and edi,ecx
00401A2C mov edx,esi
00401A2E mov ebx,edi
00401A30 shrd edx,ebx,0Ch
00401A34 shr ebx,0Ch
00401A37 and edx,esi
00401A39 and ebx,edi
00401A3B or edx,ebx
00401A3D je `anonymous namespace'::haswon+35h (401A45h)
00401A3F mov al,1
00401A41 pop edi
00401A42 pop esi
00401A43 pop ebx
00401A44 ret
00401A45 mov edx,eax
00401A47 mov edi,ecx
00401A49 shrd edx,edi,7
00401A4D mov esi,edx
00401A4F shr edi,7
00401A52 and esi,eax
00401A54 and edi,ecx
00401A56 mov edx,esi
00401A58 mov ebx,edi
00401A5A shrd edx,ebx,0Eh
00401A5E shr ebx,0Eh
00401A61 and edx,esi
00401A63 and ebx,edi
00401A65 or edx,ebx
00401A67 jne `anonymous namespace'::haswon+2Fh (401A3Fh)
00401A69 mov edx,eax
00401A6B mov edi,ecx
00401A6D shrd edx,edi,8
00401A71 mov esi,edx
00401A73 shr edi,8
00401A76 and esi,eax
00401A78 and edi,ecx
00401A7A mov edx,esi
00401A7C mov ebx,edi
00401A7E shrd edx,ebx,10h
00401A82 shr ebx,10h
00401A85 and edx,esi
00401A87 and ebx,edi
00401A89 or edx,ebx
00401A8B jne `anonymous namespace'::haswon+2Fh (401A3Fh)
00401A8D mov edx,eax
00401A8F mov esi,ecx
00401A91 shrd edx,esi,1
00401A95 shr esi,1
00401A97 and esi,ecx
00401A99 and edx,eax
00401A9B mov eax,edx
00401A9D mov ecx,esi
00401A9F shrd eax,ecx,2
00401AA3 shr ecx,2
00401AA6 and eax,edx
00401AA8 and ecx,esi
00401AAA or eax,ecx
00401AAC jne `anonymous namespace'::haswon+2Fh (401A3Fh)
00401AAE pop edi
00401AAF pop esi
00401AB0 xor al,al
00401AB2 pop ebx
00401AB3 ret
此版本背后的思想是避免严格的测试顺序(中间返回强制编译器按顺序一次计算一个条件)以及与多个if语句相关联的分支:
// return whether newboard includes a win
bool haswon2(uint64_t newboard)
{
uint64_t y = newboard & (newboard >> 6);
uint64_t z = newboard & (newboard >> 7);
uint64_t w = newboard & (newboard >> 8);
uint64_t x = newboard & (newboard >> 1);
return (y & (y >> 2 * 6)) | // check \ diagonal
(z & (z >> 2 * 7)) | // check horizontal -
(w & (w >> 2 * 8)) | // check / diagonal
(x & (x >> 2)); // check vertical |
}
通过适当的优化,您可以将w、x、y和z视为移位值的“别名”。这意味着最终的return语句将整个操作抛到一个大汤碗中,供编译器使用。在我的系统上,这个版本只占原始版本运行时间的65%(包括每次生成随机位置的开销)。如果董事会主要是非赢家,它可能会以更大的比例获胜
查看每一个的反汇编(从
gcc-O3
)原始版本实际上更短,因此很可能是紧密的内部循环中缺少分支才真正有帮助。这个函数肯定每移动一次就运行一次吗?为什么它需要1微秒或1毫秒?这几乎肯定不需要优化。该函数由alpha beta游戏树搜索中的其他两个函数调用。其他功能是测试win或zugzwang的“getMoves”,以及测试董事会是否包含win的“evaluate”。这个函数确实经常被调用。@Christian:我明白了。嗯,我不能提供关于上述函数的任何具体建议,但您是否考虑过利用这样一个事实:在每次移动之后,如果有一行4,它必须包含新的片段?@Oli如果它被AI使用,这可能很重要。有什么原因使编译器不能从原始代码执行这些优化吗?我真的看不出有什么理由(没有指针或别名问题,没有数组查找或可能禁止这种代码重新排序的副作用。那么,这只是GCC的编译器不够好的一种情况,还是原始代码的某些方面意味着它无法自动转换为与您类似的代码?@jalf不要高估它。不是这样的能够优化算法。请阅读:@Ben Jackson:我在工作时阅读了你的答案,对你的努力感到高兴。看来Microsoft编译器无法利用你的想法。我在问题中发布了结果。谢谢你的版本。我很惊讶编译器无法执行此优化自我。@Christian:如果答案不能令人满意地解决问题,那么“不接受”也没什么错。只要有一个被接受的答案,看到答案的人就会少,所以你得到的答案就会少。