2

我的理解是,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);
    }
};
4

2 回答 2

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_&4 上使用 GCC 4.7 和 4.8,这样的内存栅栏不会产生任何代码,只是限制编译器重新排序。

于 2014-03-09T18:01:34.597 回答
2

我不认为 C++ 优化器实际上是这里的问题。更有可能的是,问题在于您尝试测量的时间量在某些情况下小于您使用的时钟的最小粒度——也就是说,timestamp() 在您的 TimeSlice 构造函数和在析构函数中,因为第二次调用在第一次调用之后执行得如此之快,以至于时钟值没有足够的时间增加下一个刻度量。

如果是这种情况,那么解决方案将是找到一个更高精度的时钟 API 来代替使用,或者测量更长的事件(例如,执行 10000 次操作迭代的循环并测量它),或者只是理解非常小的时间增量可能会被时钟的刻度粒度有效地四舍五入为零。

于 2014-03-09T06:23:24.760 回答