使用volatile防止基准测试代码中的编译器优化?

问题描述

| 我正在创建一个小程序来测量
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 [intro.execution] / 6)。我相信,这保证了无法优化分配给易失数据的工作。另一种可观察到的行为是对I / O函数的调用。 在这方面,C ++ 11标准甚至更加明确:在1.9 / 8中,它明确指出:   符合标准的实现的最低要求是:   —严格根据抽象机的规则评估对易失对象的访问。 如果编译器可以证明代码不会产生可观察到的行为,那么它可以优化代码。在更新中(不使用volatile的情况),复制构造函数和其他函数调用以及重载的运算符可能会避免任何I / O调用和对易失性数据的访问,并且编译器可能会很好地理解它。但是,如果
gNumCopies
是稍后在具有可观察到的行为(例如打印)的表达式中使用的全局变量,则不会删除此代码。     ,对于非POD类型,Volatile不太可能达到您的期望。我建议将别名为
char *
void *
的容器传递给其他翻译单元中的空函数。由于编译器无法分析指针的使用情况,因此这将充当编译器内存屏障,至少将对象强制移出处理器高速缓存,并阻止大多数死值消除优化。     ,为什么要这样最好的解决方案是以某种方式使用容器,例如将其大小添加到全局变量中。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...