由于x86 C编译器(即GCC和Clang)的进步,许多被认为能提高效率的编码实践不再使用,因为编译器可以比人类(例如bit shift vs. multiplication)更好地优化代码。
这些具体做法是什么?
发布于 2014-06-05 20:57:55
在通常推荐的优化中,对于现代编译器来说,一些基本上从未取得成果的优化包括:
数学变换
现代编译器理解数学,并在适当的情况下对数学表达式进行转换。
优化,如乘法转换为加法,或常量乘法或除法为位移位,已经由现代编译器执行,即使在低优化水平。这些优化的例子包括:
x * 2 -> x + x
x * 2 -> x << 1请注意,某些具体情况可能有所不同。例如,x >> 1与x / 2不一样;用一个代替另一个是不合适的!
此外,这些建议中的许多优化实际上并不比它们替换的代码更快。
愚蠢的代码技巧
我甚至不知道如何称呼它,但是像XOR交换(a ^= b; b ^= a; a ^= b;)这样的技巧根本不是优化。它们只是聚会的花招--它们比显而易见的方法要慢一些,也更脆弱。别用它们。
register关键字
这个关键字被许多现代编译器忽略,因为它的意图(强制变量存储在寄存器中)在当前的寄存器分配算法中是没有意义的。
代码转换
编译器将在适当情况下自动执行各种各样的代码转换。经常推荐用于手动应用的几种此类转换(但在应用时很少有用)包括:
static,在启用优化时通常会在适当的地方内联)。发布于 2014-06-05 20:56:58
其中一种做法是使用数组指针数组来避免乘法,而不是使用真正的2D数组。
旧习俗:
int width = 1234, height = 5678;
int* buffer = malloc(width*height*sizeof(*buffer));
int** image = malloc(height*sizeof(*image));
for(int i = height; i--; ) image[i] = &buffer[i*width];
//Now do some heavy computations with image[y][x].这曾经更快,因为乘法过去非常昂贵(大约30个CPU周期),而内存访问实际上是免费的(直到20世纪90年代才增加缓存,因为内存无法跟上整个CPU的速度)。
但是乘法变得很快,一些CPU能够在一个CPU周期内完成它们,而内存访问却根本跟不上进度。因此,现在这段代码可能具有更强的性能:
int width = 1234, height = 5678;
int (*image)[width] = malloc(height*sizeof(*image));
//Now do some heavy computations with image[y][x],
//which will invoke pointer arithmetic to calculate the offset as (y*width + x)*sizeof(int).目前,仍然有一些CPU,在那里的第二个代码不是更快,但大的乘法惩罚不再与我们在一起。
发布于 2014-06-05 21:02:29
由于平台的多样性,您最多可以对给定平台(或CPU体系结构/模型)和编译器进行优化!!如果您的代码在许多平台上运行,这是浪费时间。(我说的是微选择,它总是值得考虑更好的算法)
这就是说对给定的平台进行优化,如果需要的话DSP是有意义的。那么最好的第一个助手是IMHO,如果编译器/优化器很好地支持它,那么明智地使用restrict关键字。避免涉及条件和跳变代码的算法(中断、goto、如果、时间、.)这有利于流,并避免了太多糟糕的分支预测。我同意这些暗示现在是常识。
一般说来,我想说的是:任何通过假设编译器如何优化来修改代码的操作都应该避免.。
相反,切换到程序集(对于DSP中一些非常重要的算法来说,通常的做法是编译器虽然非常优秀,但仍然忽略了CPU/Mem周期的最后几%的性能提高……)
https://stackoverflow.com/questions/24069608
复制相似问题