如何不优化远离 - 愚蠢功能的机制

时间:2015-02-02 21:26:06

标签: c++ c++11 assembly benchmarking c++14

我正在寻找一种编程技术,确保用于基准测试的变量(没有可观察到的副作用)不会被编译器优化掉

This提供了一些信息,但我最终使用folly和以下函数

/**
 * Call doNotOptimizeAway(var) against variables that you use for
 * benchmarking but otherwise are useless. The compiler tends to do a
 * good job at eliminating unused variables, and this function fools
 * it into thinking var is in fact needed.
 */
#ifdef _MSC_VER

#pragma optimize("", off)

template <class T>
void doNotOptimizeAway(T&& datum) {
  datum = datum;
}

#pragma optimize("", on)

#else
template <class T>
void doNotOptimizeAway(T&& datum) {
  asm volatile("" : "+r" (datum));
}
#endif

我想使用上述内容,但我对其工作方式了解不多。我最感兴趣的是非VC ++部分和为什么/如何行

asm volatile("" : "+r" (datum));

创建一个不可优化的上下文或为什么这会选择实现这样的东西。另外两种方法之间的比较会很有趣(我不知道pragma optimize是如何工作的,但它看起来像一个更清洁的解决方案 - 虽然不便携)

1 个答案:

答案 0 :(得分:19)

没有标准方法可以禁用优化,因此如果您需要禁用优化,则仅限于您提供的实现。除非您找到支持它们的编译器,否则比较这两种方法是没有意义的。

无论如何,在海湾合作委员会中,

asm volatile("" : "+r" (datum));

表示用户提供的未验证汇编代码嵌入到GCC生成的汇编中。第一个字符串文字("")包含要注入的汇编代码。它是空的,所以根本没有任何代码可以发出。

:之后的部分通知GCC有关汇编代码的影响。 "+r" (datum)表示GCC应该假定汇编代码读取并修改datum。尽管它没有。这样做的原因是任何最终在datum中存储值的早期计算都不能作为不必要的丢弃。同时,由于对datum的潜在修改,汇编代码本身不能作为不必要的丢弃。 volatile还将汇编代码标记为不得优化的代码,as documented here

  

如果GCC的优化器确定不需要输出变量,它们有时会丢弃asm语句。此外,如果优化器认为代码将始终返回相同的结果(即,其调用之间的输入值都没有变化),则优化器可以将代码移出循环。使用volatile限定符可禁用这些优化。 [...]

使用两种不同的方法防止汇编代码被删除似乎有点太多了,但我想最好确定一下。

r约束意味着代码并不关心GCC使汇编代码可以使用哪个寄存器,is documented here

  

“R”
  只要它在通用寄存器中,就允许使用寄存器操作数。

+修饰符表示代码可以读取和写入datumis documented here

  

“+”
  表示该操作数由指令读取和写入。 [...]