【发布时间】:2017-02-28 13:08:47
【问题描述】:
我最近看到了这个精彩的 cpp2015 演讲 CppCon 2015: Chandler Carruth "Tuning C++: Benchmarks, and CPUs, and Compilers! Oh My!"
提到的防止编译器优化代码的技术之一是使用以下函数。
static void escape(void *p) {
asm volatile("" : : "g"(p) : "memory");
}
static void clobber() {
asm volatile("" : : : "memory");
}
void benchmark()
{
vector<int> v;
v.reserve(1);
escape(v.data());
v.push_back(10);
clobber()
}
我试图理解这一点。问题如下。
1) 逃脱比破坏者有什么优势?
2) 从上面的例子看,clobber() 阻止了之前的语句( push_back )被优化。如果是这样,为什么下面的 sn-p 不正确?
void benchmark()
{
vector<int> v;
v.reserve(1);
v.push_back(10);
clobber()
}
如果这还不够令人困惑,那么愚蠢(FB 的线程库)甚至有一个 stranger implementation
相关sn-p:
template <class T>
void doNotOptimizeAway(T&& datum) {
asm volatile("" : "+r" (datum));
}
我的理解是上面的sn-p通知编译器汇编块将写入数据。但是如果编译器发现这个数据没有消费者,它仍然可以优化实体产生数据对吗?
我认为这不是常识,感谢任何帮助!
【问题讨论】:
-
其实“+r”的意思是sn-p会读写数据。由于 (gcc) 编译器无法知道 asm 如何使用/修改数据,因此它在任何情况下都无法将其优化掉。
-
该功能现在内置于谷歌基准测试中。 benchmark::DoNotOptimize 如下所示:github.com/google/benchmark
标签: c++ gcc clang performance-testing compiler-optimization