提升循环的性能
要提升循环的性能,减少多余的常量计算非常有用(比如,不随循环变化的计算)。
不好的代码(在for()中包含不变的if()) 推荐的代码
for( i ... )
{
if( CONSTANT0 )
{
DoWork0( i ); // 假设这里不改变CONSTANT0的值
}
else
{
DoWork1( i ); // 假设这里不改变CONSTANT0的值
}
}
if( CONSTANT0 )
{
for( i ... )
{
DoWork0( i );
}
}
else
{
for( i ... )
{
DoWork1( i );
}
}
如果已经知道if()的值,这样可以避免重复计算。虽然不好的代码中的分支可以简单地预测,但是由于推荐的代码在进入循环前分支已经确定,就可以减少对分支预测的依赖。 把本地函数声明为静态的(static)
如果一个函数在实现它的文件外未被使用的话,把它声明为静态的(static)以强制使用内部连接。否则,默认的情况下会把函数定义为外部连接。这样可能会影响某些编译器的优化——比如,自动内联。
考虑动态内存分配
动态内存分配(C++中的";new";)可能总是为长的基本类型(四字对齐)返回一个已经对齐的指针。但是如果不能保证对齐,使用以下代码来实现四字对齐。这段代码假设指针可以映射到 long 型。
例子
double* p = (double*)new BYTE[sizeof(double) * number_of_doubles+7L];
double* np = (double*)((long(p) + 7L) &; –8L);
现在,你可以使用 np 代替 p 来访问数据。注意:释放储存空间时仍然应该用delete p。
使用显式的并行代码
尽可能把长的有依赖的代码链分解成几个可以在流水线执行单元中并行执行的没有依赖的代码链。因为浮点操作有很长的潜伏期,所以不管它被映射成 x87 或 3DNow! 指令,这都很重要。很多高级语言,包括C++,并不对产生的浮点表达式重新排序,因为那是一个相当复杂的过程。需要注意的是,重排序的代码和原来的代码在代数上一致并不等价于计算结果一致,因为浮点操作缺乏精确度。在一些情况下,这些优化可能导致意料之外的结果。幸运的是,在大部分情况下,最后结果可能只有最不重要的位(即最低位)是错误的。
不好的代码 推荐的代码
double a[100], sum;
int i;
sum = 0.0f;
for (i=0; i<;100; i++)
sum += a[i];
double a[100], sum1, sum2, sum3, sum4, sum;
int i;
sum1 = sum2 = sum3 = sum4 = 0.0;
for (i = 0; i <; 100; i += 4)
{
sum1 += a[i];
sum2 += a[i+1];
sum3 += a[i+2];
sum4 += a[i+3];
}
sum = (sum4+sum3)+(sum1+sum2);
要注意的是:使用4 路分解是因为这样使用了4阶段流水线浮点加法,浮点加法的每一个阶段占用一个时钟周期,保证了最大的资源利用率。