我有两个功能:
unsigned long long getLineAsRow(unsigned long long board, int col) {
unsigned long long column = (board >> (7-(col - 1))) & col_mask_right;
column *= magicLineToRow;
return (column >> 56) & row_mask_bottom;
}
unsigned long long getDiagBLTR_asRow(unsigned long long board, int line, int row) {
unsigned long long result = board & diagBottomLeftToTopRightPatterns[line][row];
result = result << diagBLTR_shiftUp[line][row];
result = (result * col_mask_right) >> 56;
return result;
}
我看到的唯一重大区别是访问2-dim-array。定义如
int diagBRTL_shiftUp[9][9] = {};
我将这两个函数称为10.000.000次:
getLineAsRow ... time used: 1.14237s
getDiagBLTR_asRow ... time used: 2.18997s
我用cl(vc ++)和g ++测试了它。几乎没有区别。 这是一个非常巨大的差异,你有什么建议吗?
答案 0 :(得分:0)
这些功能完全不同,但我认为这与问题无关。
有时这些测试不会显示某个功能的实际成本。
在这种情况下,主要成本是数组在内存中的访问。第一次访问后,它将在缓存中,之后您的功能将会很快。所以你不能真正衡量这个特征。即使在测试中有10.000.000次迭代,您只需支付一次价格。
现在,如果您批量执行此功能,批量调用多次,那么它就不会发生问题。缓存会很温暖。
如果偶尔访问它,在具有高内存需求并经常刷新CPU内存的应用程序中,可能会出现性能问题。但这当然取决于背景:它被调用的频率等等。
答案 1 :(得分:0)
如果不知道生成的汇编程序代码或者您正在访问的全局变量实际上是可以编译到代码中的常量,那么在两个函数的执行时间之间产生差异的问题实际上是无法回答的。无论如何,分析你的功能,我们看到了
功能1
7-(col-1)
中的两个减值可以折叠成一个减法)功能2
请注意,对2D阵列的访问实际上归结为单个内存访问。当您编写diagBottomLeftToTopRightPatterns[line][row]
时,编译器会将其转换为diagBottomLeftToTopRightPatterns[line*9 + row]
之类的内容。这是两个额外的算术指令,但只有一个内存访问。更重要的是,计算结果line*9 + row
可以循环用于第二次2D阵列访问。
算术运算很快(在单个CPU周期的顺序),从内存中读取可能需要四到二十个CPU周期。所以我猜你在函数1中访问的三个全局变量都是编译器在汇编代码中构建的常量。这使得函数2具有更多的内存访问,使其变慢。
然而,有一件事困扰着我:如果我假设您拥有一个至少具有2 GHz时钟频率的正常CPU,则您的时间表明您的功能分别消耗超过200或400个周期。这远远超出预期。即使您的CPU在缓存中没有值,您的功能也不应超过大约100个周期。因此,我建议您再次了解一下如何为代码计时,我假设您在测量循环中有更多代码会破坏您的结果。