微优化:使用局部变量与类成员进行迭代

时间:2015-03-07 11:28:51

标签: c++ micro-optimization

如果我将一次迭代变量声明为类成员,我想我会节省一些时间:

struct Foo {
  int i;
  void method1() {
    for(i=0; i<A; ++i) ...
  }
  void method2() {
    for(i=0; i<B; ++i) ...
  }
} foo;
然而,这似乎比cca快了20%

struct Foo {
  void method1() {
    for(int i=0; i<A; ++i) ...
  }
  void method2() {
    for(int i=0; i<B; ++i) ...
  }
} foo;

在此代码中

void loop() { // Arduino loops
  foo.method1();
  foo.method2();
}

你能解释性能差异吗?

(我需要在Arduino上运行许多简单的paralel“进程”,这样的微优化会产生影响。)

2 个答案:

答案 0 :(得分:8)

当你在循环中声明你的循环变量时,它的范围很窄。编译器可以随时将它保存在寄存器中,因此它甚至不会被提交到内存中。

当您将循环变量声明为实例变量时,编译器没有这种灵活性。它必须将变量保存在内存中,以防某些方法需要检查其状态。例如,如果您在第一个代码示例中执行此操作

void method2() {
    for(i=0; i<B; ++i) { method3(); }
}
void method3() {
    printf("%d\n", i);
}

imethod3的值必须随着循环的进行而改变。编译器无法将所有副作用提交到内存。此外,当你从i回来时,它不能假设method3保持不变,这进一步增加了内存访问次数。

处理内存中的更新比执行基于寄存器的变量更新需要更多的CPU周期。这就是为什么将循环变量限定为循环级别总是一个好主意。

答案 1 :(得分:2)

  

你能解释性能差异吗?

对于这种性能差异我可以得出的最合理的解释是:

数据成员 i在全局内存中声明,不能一直保存在寄存器中,因此对它的操作比循环上的操作要慢变量 i由于范围非常广泛(数据成员i必须满足该类的所有成员函数)。

@DarioOO补充道:

  

此外,编译器不能将其临时存储在a中   注册因为method3()可能抛出一个异常离开对象   在一个不需要的状态(因为理论上没有人阻止你   写   int k=this->i; for(k=0;k<A;k++)method3(); this->i=k;。那段代码   几乎和局部变量一样快,但你必须坚持下去   method3()抛出时的帐户(我相信当有保证时)   不抛出编译器会优化-O3-O4   验证)