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 もタイムスタンプも 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 コンストラクターと両方で同じ値を返します。これは、最初の呼び出しの後に 2 番目の呼び出しが非常に迅速に実行されたため、クロック値が次のティック量をインクリメントするのに十分な時間がなかったためです。

その場合、解決策は、代わりに使用する高精度のクロック API を見つけるか、より長いイベントを測定するか (たとえば、操作の 10000 回の反復のループを実行してそれを測定する)、または単にそれを理解して生きることです。非常に小さな時間増分は、クロックの目盛りの粒度によって効果的にゼロに切り捨てられる場合があります。

于 2014-03-09T06:23:24.760 に答える