我举了以下例子来说明我的问题:
void fun(int i, float *pt)
{
// do something based on i
std::cout<<*(pt+i)<<std::endl;
}
const unsigned int LOOP = 2000000007;
void fun_without_optmization()
{
float *example;
example = new float [LOOP];
for(unsigned int i=0; i<LOOP; i++)
{
fun(i,example);
}
delete []example;
}
void fun_with_optimization()
{
float *example;
example = new float [LOOP];
unsigned int unit_loop = LOOP/10;
unsigned int left_loop = LOOP%10;
pt = example;
for(unsigend int i=0; i<unit_loop; i++)
{
fun(0,pt);
fun(1,pt);
fun(2,pt);
fun(3,pt);
fun(4,pt);
fun(5,pt);
fun(6,pt);
fun(7,pt);
fun(8,pt);
fun(9,pt);
pt=pt+10;
}
delete []example;
}
据我了解,函数fun_without_optimization
()和函数fun_with_optimization
()应该执行相同的操作。第二个函数优于第一个函数的唯一论据是fun
中的指针计算变得简单。任何其他论点为什么第二个功能更好?
答案 0 :(得分:6)
展开执行I / O的循环就像在伦敦JFK向东移动一英里的B747着陆带。
答案 1 :(得分:5)
回复:“为什么第二个功能更好?” - 你会接受答案解释为什么不更好吗?
left_loop
。底线是:如果您知道编译器没有的东西(运行时数据的特定模式,目标执行环境的详细信息等),并且您知道自己在做什么 - 您可以尝试手动循环展开。但即便如此 - 简介。
答案 2 :(得分:3)
您描述的技术称为loop unrolling;这可能会提高性能,因为评估控制结构的时间(更新循环变量和检查终止条件)变得更小。但是,正确的编译器可以为您完成此操作,并且如果手动完成,代码的可维护性会降低。
答案 3 :(得分:1)
这是一种用于并行体系结构的优化技术(支持VLIW指令的体系结构)。根据架构支持的DALU(最常见的4)和ALU(最常见的2)单元的数量,以及代码支持的“并行化”级别,可以在一个周期内执行多条指令。
所以这段代码:
for (int i=0; i<n;i++) //n multiple of 4, for simplicity
a+=temp; //just a random instruction
如果重写如下,那么在并行体系结构上实际执行速度会更快:
for (int i=0;i<n ;i+=4)
{
temp0 = temp0 +temp1; //reads and additions can be executed in parallel
temp1 = temp2 +temp3;
a=temp0+temp1+a;
}
您可以并行化代码的数量是有限的,这是CPU拥有的物理ALU / DALU所施加的限制。这就是为什么在尝试(正确)优化代码之前了解您的架构很重要。
它不会停在这里:你想要优化的代码必须是一个连续的代码块,这意味着没有跳转(没有函数调用,没有流程指令的机会),以实现最高效率。
编写代码,例如:
for(unsigend int i=0; i<unit_loop; i++)
{
fun(0,pt);
fun(1,pt);
fun(2,pt);
fun(3,pt);
fun(4,pt);
fun(5,pt);
fun(6,pt);
fun(7,pt);
fun(8,pt);
fun(9,pt);
pt=pt+10;
}
除非编译器内联函数调用,否则不会做太多事情;无论如何它看起来很多指示......
另一方面注意:虽然在优化代码时总是必须使用编译器,但是当你从代码中获得最大优化时,你绝不应该只依赖它。请记住,当您可能对特定情况感兴趣时,编译器会处理“一般情况” - 这就是为什么某些编译具有特殊指令来帮助优化过程的原因。