我的理解是C ++允许任何不是IO或外部函数调用的东西都可以优化重新排序。这开始使我在编写RAII样式函数时间戳方面的努力受挫。
修改
这是一个自包含的示例
VS 2012的代码,带有优化
#include <chrono>
#include <iostream>
#include <atomic>
#include <string>
using namespace std;
class TimeSlice
{
public:
TimeSlice(std::string myname): name(myname), start(timestamp())
{
fency();//don't optomize me out!
}
~TimeSlice()
{
fency();
auto elapsed = timestamp()-start;
cout << name<<(int) elapsed << endl;
}
static inline long long timestamp()
{
return chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
}
private:
const long long start;
const std::string name;
static inline void fency()
{
std::atomic_signal_fence(std::memory_order_seq_cst);
}
};
答案 0 :(得分:3)
函数调用未优化,它们被重新排序。它被编译为:
_sleep(10);
start = timestamp();
elapsed = timestamp()-start;
cout << name<<(int) elapsed << endl;
这种重新排序是合法的,因为_sleep和timestamp都不构成IO。如果你有c ++ 11支持,你可以使用信号处理程序内存栏来阻止这种重新排序。只需包含并插入:
std::atomic_signal_fence(std::memory_order_seq_cst);
在析构函数和构造函数体的开头。在x86_&amp; 4上使用GCC 4.7和4.8,这样的内存栅栏不会产生任何代码,只会限制编译器的重新排序。
答案 1 :(得分:2)
我认为C ++优化器实际上并不是问题所在。更有可能的是,问题是您尝试测量的时间量在某些情况下小于您使用的时钟的最小粒度 - 也就是说,timestamp()在TimeSlice构造函数中返回相同的值并且在析构函数中,因为第二个调用在第一个调用之后执行得如此之快,以至于时钟值没有足够的时间来增加下一个滴答量。
如果是这种情况,那么解决方案就是找到更高精度的时钟API来代替使用,或者测量更长的事件(例如,做10000次迭代的操作并测量它),或者只是理解非常小的时间增量可以通过时钟的滴答粒度有效地舍入到零。