代码之家  ›  专栏  ›  技术社区  ›  Mikhail

如何防止时间戳被重新排序?

  •  2
  • Mikhail  · 技术社区  · 11 年前

    我的理解是,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);
        }
    };
    
    2 回复  |  直到 11 年前
        1
  •  3
  •   user2229152    11 年前

    函数调用没有优化,而是重新排序。其编译方式如下:

        _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,这样的内存围栏不会产生任何代码,只会限制编译器重新排序。

        2
  •  2
  •   Jeremy Friesner    11 年前

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

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