【问题标题】:Microoptimization: iterating with local variable vs. class member微优化:局部变量与类成员的迭代
【发布时间】:2015-05-08 23:30:48
【问题描述】:

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

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

不过,这似乎快了 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 上运行许多简单的并行“进程”,这样的微优化会产生影响。)

【问题讨论】:

  • “如果我将迭代变量声明为类成员一次,将节省一些时间”。一个很奇怪的想法,那个。每次都是this-&gt;i。
  • 我会冒昧地猜测本地计数器变量只存储在寄存器中,但要知道这些东西,请使用 @987654325 进行编译@ 并查看程序集。 A 和 B 是否小于 256?然后编译器可能能够在本地情况下使用 8 位 int(在 8 位 MCU 上更快)。一切都是猜测。
  • 这个想法不是分配额外的堆栈空间并在每次调用时保存一条指令。 ... 做了很多不同的事情,但 i 用作低于 256(字节大小)的数组索引。

标签: c++ micro-optimization


【解决方案1】:

您能解释一下性能差异吗?

对于这种性能差异,我能想到的最合理的解释是:

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

@DarioOO 补充道:

此外,编译器不能随意将其临时存储在 注册,因为method3() 可能会抛出异常离开对象 处于不想要的状态(因为理论上没有人阻止你 写 int k=this-&gt;i; for(k=0;k&lt;A;k++)method3(); this-&gt;i=k;。那个代码 几乎和局部变量一样快,但你必须坚持 method3()抛出时的帐户(我相信当有保证时它 不抛出编译器将使用-O3 或-O4 进行优化 已验证)

【讨论】:

  • 此外,编译器不能随意将其临时存储在寄存器中,因为method3() 可能会引发异常,使对象处于不需要的状态(因为理论上没有人阻止您编写int k=this-&gt;i; for(k=0;k&lt;A;k++)method3(); this-&gt;i=k;该代码几乎与局部变量一样快,但您必须考虑到何时抛出 method3(我相信当有保证它不会抛出时,编译器将使用 -O3 或 -O4 对其进行优化。待验证
  • 哦,对不起 :) 我不想纠正你。我习惯于将我的想法添加到答案中,只是因为我喜欢写关于编程的文章。顺便说一下 +1 以便快速响应:D
【解决方案2】:

当你在循环中声明你的循环变量时,它的作用域非常狭窄。编译器可以一直将它保存在寄存器中,因此它甚至不会被提交到内存中。

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

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

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

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

【讨论】:

  • 那么声明for(register int i=0; ... ) 是个好主意吗?假设未弃用 register 说明符的 C++11 前标准。
  • 它被弃用是有原因的,原因是它今天完全没用了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 2012-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-21
相关资源
最近更新 更多