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

How to prevent timestamp from being reorder out?

本文关键字:排序 新排序 何防止 时间戳      更新时间:2023-10-16

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

函数调用没有被优化,它们被重新排序。它被编译为:

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

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

如果是这种情况,那么解决方案将是找到一个更高精度的时钟API来使用,或者测量更长的事件(例如,做一个10000次迭代的循环操作并测量它),或者仅仅接受这样的理解,即非常小的时间增量可能会被时钟的tick-granularity有效地舍入到零。