在基准测试代码中使用volatile来阻止编译器优化
Using volatile to prevent compiler optimization in benchmarking code?
我正在创建一个小程序来测量类型为boost::shared_ptr
和boost::intrusive_ptr
的容器之间的性能差异。为了防止编译器优化副本,我将变量声明为volatile。循环如下:
// TestCopy measures the time required to create n copies of the given container.
// Returns time in milliseconds.
template<class Container>
time_t TestCopy(const Container & inContainer, std::size_t n) {
Poco::Stopwatch stopwatch;
stopwatch.start();
for (std::size_t idx = 0; idx < n; ++idx)
{
volatile Container copy = inContainer; // Volatile!
}
// convert microseconds to milliseconds
return static_cast<time_t>(0.5 + (double(stopwatch.elapsed()) / 1000.0));
}
其余的代码可以在这里找到:main.cpp.
- 在这里使用volatile会阻止编译器优化副本吗
- 是否存在可能使结果无效的陷阱
更新
回应@Neil Butterworth。即使在使用副本的时候,在我看来编译器仍然可以很容易地避免副本:
for (std::size_t idx = 0; idx < n; ++idx)
{
// gcc won't remove this copy?
Container copy = inContainer;
gNumCopies += copy.size();
}
C++03标准规定,对易失性数据的读取和写入是可观察的行为(C++2003,1.9[interro.execution]/6(。我相信这保证了对易失性数据的分配不会被优化掉。另一种可观察的行为是对I/O函数的调用。C++11标准在这方面更加明确:在1.9/8中,它明确表示
对一致性实施的最低要求是:
--对易失性对象的访问严格按照抽象机器的规则进行评估。
如果编译器能够证明代码没有产生可观察的行为,那么它就可以优化代码。在更新中(不使用volatile(,复制构造函数和其他函数调用&重载运算符可能会避免任何I/O调用和对易失性数据的访问,编译器可能会很好地理解这一点。但是,如果gNumCopies
是一个全局变量,后来在具有可观察行为的表达式(例如打印(中使用,则不会删除此代码。
Volatile不太可能达到您对非POD类型的期望。我建议将容器的char *
或void *
别名传递给另一个转换单元中的空函数。由于编译器无法分析指针的使用情况,这将充当编译器内存屏障,迫使对象至少进入处理器缓存,并阻止大多数死值消除优化。
为什么要这样做?最好的解决方案是以某种方式使用容器,比如将容器的大小添加到全局变量中。
相关文章:
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- VS2017调试器:没有地址,可能是由于编译器优化
- 何时允许编译器优化复制构造函数
- 如何使用 GCC 编译器优化创建静态库?
- 为什么 std::chrono 在测量循环和编译器优化的并行 OpenMP 的执行时间时不起作用?
- 是否允许编译器优化掉局部易失性变量
- 删除编译器优化并在发布中启用 pdb 文件
- 静态 constexpr 的编译器优化
- 如何让MSVC编译器优化多步POD初始化?
- 按位不操作的编译器优化
- 模板专用化与编译器优化
- 编译器优化:G 比英特尔慢
- 运算符重载关联性编译器优化
- Intel OpenCL编译器:优化结构使用情况
- C 中编译器优化的影响
- 视觉C++ 2017 错误?编译器优化表达式
- 虚拟功能编译器优化C
- 未定义的行为确实有助于现代编译器优化生成的代码