我正在检查Celero git repository DoNotOptimizeAway
的含义。但我仍然没有得到它。能否请你以外行的方式帮助我理解。尽你所能地。
提供celero :: DoNotOptimizeAway模板以确保优化编译器不会消除您的功能或代码。由于此功能用于所有样本基准测试及其基线,因此在比较中取消了时间开销。
您没有包含定义,只包括文档。我认为你要求帮助理解它为什么存在,而不是定义。
它可以阻止编译器进行CSEing并从重复循环中提升工作,因此您可以重复相同的工作,以便进行可测量。例如在一个运行10亿次的循环中放入一些简短的东西,然后你可以轻松地测量整个循环的时间(大约一秒左右)。有关在asm中手动执行此操作的示例,请参阅Can x86's MOV really be "free"? Why can't I reproduce this at all?。如果你想要像这样的编译器生成的代码,你需要像DoNotOptimizeAway
这样的函数/宏。
在禁用优化的情况下编译整个程序将毫无用处:在C ++语句之间存储/重新加载所有内容会产生非常不同的瓶颈(通常是存储转发延迟)。见Adding a redundant assignment speeds up code when compiled without optimization
也许看实际的定义也有帮助。
这个Q&A(Optimization barrier for microbenchmarks in MSVC: tell the optimizer you clobber memory?)描述了DoNotOptimize
宏的一个实现如何工作(并询问如何将它从GNU C ++移植到MSVC)。
escape
宏来自Chandler Carruth的CppCon2015谈话,"Tuning C++: Benchmarks, and CPUs, and Compilers! Oh My!"。这篇文章还详细介绍了编写微基准测试时为什么需要它:在启用优化的情况下编译时停止整个循环的优化。
(让编译器将事物从循环中提升而不是反复计算它们,如果它是一个问题就很难做到正确。如果函数__attribute__((noinline))
足够大而不需要内联,则可以提供帮助。检查编译器的asm输出以查看它悬挂多少设置。)
BTW,GNU C / C ++的一个很好的定义通常没有额外的成本:
asm volatile("" :: "r"(my_var));
编译为零asm指令,但要求编译器在其选择的寄存器中具有my_var
的值。 (并且由于asm volatile
,必须在C ++抽象机器中多次“运行”)。
如果编译器可以将其作为其他部分的计算转换为其他内容,则这将仅影响优化。 (例如,在循环计数器上使用它会阻止编译器仅使用指针增量并与终结指针进行比较以执行for(i=0;i<n;i++) sum+=a[i];
的正确迭代次数
使用像asm volatile("" :"+r"(my_var));
这样的读 - 修改 - 写操作数会强制编译器忘记它知道的关于值的所有范围限制或常量传播信息,并将其视为传入函数arg。例如它是42
,或者它是非负面的。这可能会更多地影响优化。
当他们说“开销在比较中被取消”时,他们希望不会谈论明确地从单个时间结果中减去任何东西,而不是谈论自己对DoNotOptimizeAway
进行基准测试。
那不行。现代CPU的性能分析不能通过累加每条指令的成本来实现。无序流水线执行意味着如果前端(总指令吞吐量)不是瓶颈,并且如果它需要的执行单元也不是,那么额外的asm指令可以很容易地实现零额外成本。
如果他们的可移植定义类似于volatile T sink = input;
,那么额外的asm存储只有在你的代码瓶颈存储吞吐量缓存时才会有成本。
所以关于取消声音的声明有点乐观。正如我上面解释的那样,加上上下文/优化相关的因素。它有可能是一个DoNotOptimizeAway
)