关于展开循环对程序性能的影响
昨天看到了CSAPP上优化程序性能一章,印象最深的一点是关于展开循环的描述。关于展开循环,上面是这样描述的:
**展开循环是一种程序变换,通过增加每次迭代计算的元素的数量,减少循环的迭代次数。**
循环展开能从两方面改进程序的性能。
- 减少了不直接有助于程序结果的操作的数量,例如循环索引计算和分支条件。
- 提供了一些方法,可以进一步变化代码,减少整个计算中关键路径上的操作数量。
下面是一个将一个int 类型数组初始化为0的代码段:
void Init_Array(int *dest, int n)
{
int i;
for(i = 0; i < n; i++)
dest[i] = 0;
}
而如果用循环展开的话,代码如下:
void Init_Array(int *dest, int n)
{
int i;
int limit = n - 3;
for(i = 0; i < limit; i+= 4)//每次迭代处理4个元素
{
dest[i] = 0;
dest[i + 1] = 0;
dest[i + 2] = 0;
dest[i + 3] = 0;
}
for(; i < n; i++)//将剩余未处理的元素再依次初始化
dest[i] = 0;
}
将循环展开后,每次迭代将初始化4个元素,因为元素的数量不一定输4的整数倍,所以在每次处理4个元素后还要讲剩下的元素再进行初始化。
当然这里的 int limit = n - k(本例中k = 3) 中的k是根据要处理元素的个数来自己确定的。具体怎么选择这里不作描述。通常循环展开是提高程序性能的可靠方法。
根据描述给出书中优化程序性能的基本策略:
- 高级设计。为遇到的问题选择适当的算法和数据结构。要特别警觉,避免使用那些会渐进产生糟糕性能的算法和编码技术。
-
基本编码原则。避免限制优化的因素,这样编译器就能产生高效的代码。
1)消除连续的函数调用。在可能时,将计算移到循环外。考虑有选择性的妥协程序的模块性已获得更大的效率。
2)消除不必要的存储器引用。引入临时变量来保存中间结果。只有在最后的值计算出来时,才将结果放到数组或全局变量中。 - 低级优化
1)展开循环,降低开销,并且使得进一步的优化成为可能。
2)通过使用例如累积变量和重新结合等技术,找到方法提高指令级并行。
3)使用功能的风格重写条件操作,使得编译采用条件数据传送。