我正在检查Celero git repository DoNotOptimizeAway
的含义。但是我还是不明白。请您能帮我用外行的术语理解它。尽你所能。
提供了celero :: DoNotOptimizeAway模板,以确保 优化编译器不会消除您的功能或代码。以来 所有示例基准及其测试中都使用了此功能 基线,它的时间开销在比较中被抵消了。
答案 0 :(得分:1)
您没有包括定义,仅包括文档。我想您是在寻求帮助来了解为什么它甚至存在,而不是定义。
它使编译器无法进行CSE处理,也可以使工作脱离重复循环,因此您可以重复进行相同的工作足够多次,以便进行测量。例如将简短的内容放入运行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
也许看一下实际的定义也会有所帮助。
此问答(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 volatile("" :: "r"(my_var));
可能会有所帮助进行内联。检查编译器的asm输出,以查看它已提升了多少设置。)
BTW是GNU C / C ++的一个很好的定义,通常零附加成本为:
my_var
编译为0条asm指令,但要求编译器在其选择的寄存器中具有asm volatile
的值。 (并且由于for(i=0;i<n;i++) sum+=a[i];
,必须在C ++抽象机中“运行”多次)。
仅当编译器可以将一部分计算转换为其他内容时,这才会影响优化。 (例如,在循环计数器上使用此函数将阻止编译器仅使用指针增量,并与端点指针进行比较以进行正确的asm volatile("" :"+r"(my_var));
使用类似42
的读-修改-写操作数将迫使编译器忘记它所知道的所有范围限制或常量传播信息,并将其视为传入函数arg。例如是DoNotOptimizeAway
,还是非负数。这可能会影响优化。
当他们说“开销在比较中被抵消”时,他们希望不是在谈论从单个计时结果中明确减去任何东西,也不是在谈论基准volatile T sink = input;
本身。
那是行不通的。通过累加每条指令的成本,现代CPU的性能分析不会起作用。无序流水线执行意味着,如果前端(总指令吞吐量)不是瓶颈,而所需的执行单元也不是瓶颈,那么一条额外的asm指令就可以轻松实现零额外成本。
如果它们的可移植定义类似于DoNotOptimizeAway
,则仅当您的代码在要缓存的存储吞吐量上遇到瓶颈时,额外的asm存储才会产生成本。
所以关于取消的说法听起来有些乐观。正如我上面解释的,加上以上上下文/优化相关因素。 ?
)