像这样的优化是否有意义?

时间:2012-03-05 08:15:15

标签: c optimization

你有两个数组和一个计算它们之间差异的函数:

for( i = 0; i < len; ++i ) { 
    int value1 = vector1[i];
    int value2 = vector2[i];
    if( value1 != value2 ) ++num_differences;
}

由于分支降低了性能,它可以优化为:

for( i = 0; i < len; ++i ) {
    num_differences += !!(vector1[i] != vector2[i])
}
// !!(..) is to be sure that the result is boolean 0 or 1

所以没有if条款。但它几乎有意义吗?由于GCC(和其他编译器)非常聪明,使用这种优化是否有意义?

4 个答案:

答案 0 :(得分:4)

简短的回答是:“相信你的编译器”。

一般来说,除非你正在使用非常庞大的数据集,否则你不会从这样的优化中看到太多的好处。即使这样,你真的需要对代码进行基准测试,看看是否有任何改进。

答案 1 :(得分:2)

除非len数百万大,或者你在比较很多数组,否则没有。第二个版本的可读性较差(对于有经验的程序员来说不是那么多),所以我更喜欢第一个版本,除非这是瓶颈(可疑)。

生成以下代码,并进行优化:

   for( i = 0; i < 4; ++i ) { 
    int value1 = vector1[i];
    int value2 = vector2[i];
    if( value1 != value2 ) ++num_differences;
00401000  mov         ecx,dword ptr [vector1 (40301Ch)] 
00401006  xor         eax,eax 
00401008  cmp         ecx,dword ptr [vector2 (40302Ch)] 
0040100E  je          wmain+15h (401015h) 
00401010  mov         eax,1 
00401015  mov         edx,dword ptr [vector1+4 (403020h)] 
0040101B  cmp         edx,dword ptr [vector2+4 (403030h)] 
00401021  je          wmain+26h (401026h) 
00401023  add         eax,1 
00401026  mov         ecx,dword ptr [vector1+8 (403024h)] 
0040102C  cmp         ecx,dword ptr [vector2+8 (403034h)] 
00401032  je          wmain+37h (401037h) 
00401034  add         eax,1 
00401037  mov         edx,dword ptr [vector1+0Ch (403028h)] 
0040103D  cmp         edx,dword ptr [vector2+0Ch (403038h)] 
00401043  je          wmain+48h (401048h) 
00401045  add         eax,1 
   }

   for( i = 0; i < 4; ++i ) {
    num_differences += !!(vector1[i] != vector2[i]);
00401064  mov         edx,dword ptr [vector1+0Ch (403028h)] 
0040106A  xor         eax,eax 
0040106C  cmp         edx,dword ptr [vector2+0Ch (403038h)] 
00401072  mov         edx,dword ptr [vector1+8 (403024h)] 
00401078  setne       al   
0040107B  xor         ecx,ecx 
0040107D  cmp         edx,dword ptr [vector2+8 (403034h)] 
00401083  mov         edx,dword ptr [vector1+4 (403020h)] 
00401089  setne       cl   
0040108C  add         eax,ecx 
0040108E  xor         ecx,ecx 
00401090  cmp         edx,dword ptr [vector2+4 (403030h)] 
00401096  mov         edx,dword ptr [vector1 (40301Ch)] 
0040109C  setne       cl   
0040109F  add         eax,ecx 
004010A1  xor         ecx,ecx 
004010A3  cmp         edx,dword ptr [vector2 (40302Ch)] 
004010A9  setne       cl   
004010AC  add         eax,ecx 
   }

所以,实际上,第二个版本稍慢(理论上)。第二项为19项指令,第一项为17项。

答案 2 :(得分:1)

您应该比较编译器生成的代码。它可能是等价的。

编译器非常聪明,但优秀的工程师当然可以提高程序的性能。

答案 3 :(得分:1)

我不认为你会做得更好,你的第二个例子很难读懂/理解普通程序员,这意味着两个难以理解和维护的事情,两个你可能会陷入黑暗,更少测试/支持,编译器的角落。沿着线路之间的道路行驶,不要在肩膀上或在错误的车道上徘徊。

使用此

for( i = 0; i < len; ++i ) { 
    int value1 = vector1[i];
    int value2 = vector2[i];
    if( value1 != value2 ) ++num_differences;
}

或者

for( i = 0; i < len; ++i ) { 
    if( vector1[i] != vector2[i] ) ++num_differences;
}

如果它确实困扰着你并且你已经正确地断定了这是你的性能瓶颈,那么就把它们之间的时间区分开来吧。从所示的拆卸和该平台的性质来看,很难恰当地计算这些东西并得出正确的结论。太多的缓存,以及其他因素导致错误的结果,导致错误的结论等等,并且没有两个x86实现具有相同的性能,所以如果你碰巧为你的计算机进行调整,你可能会因为x86的其他模型而失去它在具有不同I / O特性的不同主板上制作相同的产品。