std :: system_clockとstd :: steady_clockの違いは?


97

違いは何であるstd::system_clockとはstd::steady_clock?(異なる結果/動作を示す例のケースは素晴らしいでしょう)。

私の目標が関数の実行時間を正確に測定することである場合(ベンチマークなど)std::system_clockstd::steady_clockとの間の最良の選択はstd::high_resolution_clock何ですか?


9
まず、system_clockが安定していない可能性があります。
James McNellis、

12
@CharlesSalvia他のプラットフォームで話すことはできませんが、system_clockWindowsでは安定していません。Windowsでは、十分に権限のあるユーザーがシステム時刻を任意の値に変更できます。さらに、時刻同期サービスは、必要に応じてシステム時刻を逆に調整する場合があります。他のほとんどのプラットフォームには、システム時刻の調整を可能にする同様の機能があると思います。
James McNellis、2015

3
@Charles:私が知っているほとんどのPOSIXボックスは同様に影響を受け、ユーザーが時刻を変更すると、時刻も変更されます。
Billy ONeal、2015

5
この質問に対する動画の回答:youtube.com/watch
P32hvk8b13M&

1
@CharlesSalvia。数十のPCデータ収集システムからのタイミング出力を分析した私の自身の経験によれば、コンピューターからの時間は安定していません。Linux、Windows、および使用される特定のシステムコールは不明ですが、共通点は、後続の時間値間の負の時間差が頻繁に発生することです。直線時間は標準ではありません。
タイソンヒルマー2017

回答:


71

N3376から:

20.11.7.1 [time.clock.system] / 1:

クラスのオブジェクトはsystem_clock、システム全体のリアルタイムクロックからの実時間を表します。

20.11.7.2 [time.clock.steady] / 1:

クラスのオブジェクトは、物理的な時間の進行に伴ってsteady_clock値がtime_point減少することのないクロックと、time_pointリアルタイムに比べて一定の速度で値が進行するクロックを表します。つまり、クロックを調整できない場合があります。

20.11.7.3 [time.clock.hires] / 1:

クラスのオブジェクトはhigh_resolution_clock、ティック周期が最も短いクロックを表します。high_resolution_clock同義語かもしれsystem_clocksteady_clock

たとえば、システム全体の時計は夏時間などの影響を受ける可能性があり、その時点で将来のある時点でリストされている実際の時刻は、実際には過去の時刻になる可能性があります。(たとえば、米国では、秋の時間が1時間戻るので、同じ時間が「2回」経験steady_clockされます)ただし、そのようなことに影響を受けることは許可されていません。

この場合の「安定した」についての別の考え方は、20.11.3 [time.clock.req] / 2の表で定義されている要件にあります。

表59でC1C2はクロックタイプを示しています。t1およびt2C1::now()、コールが戻るt1前にコールが戻る場所から返される値で、t2これらの両方のコールがの前に行われC1::time_point::max()ます。[注:これはC1t1との間でラップしなかったことを意味しt2ます。—エンドノート]

式:C1::is_steady
戻り値:const bool
操作上のセマンティクス:trueif t1 <= t2が常にtrueであり、クロックの刻みの間の時間が一定である場合、それ以外の場合false

それが標準の違いです。

ベンチマークを行う場合std::high_resolution_clockは、プラットフォームがQueryPerformanceCounterこのクロックに高解像度タイマー(Windowsなど)を使用している可能性が高いため、最善の策はになるでしょう。ただし、ベンチマークを行う場合は、プラットフォームごとに異なる方法で処理するため、ベンチマークにプラットフォーム固有のタイマーを使用することを検討する必要があります。たとえば、一部のプラットフォームでは、(同じCPUで実行されている他のプロセスとは無関係に)プログラムに必要な実際のクロック数を決定する手段が提供される場合があります。さらに良いことに、実際のプロファイラーを手に入れ、それを使用してください。


1
@チャールズ:それが事実である標準で指摘することに気をつけますか?それは明らかに反対を示しているようです。
Billy ONeal

9
@Charles:また、POSIX時間は「安定した」ものではありません。ユーザーがコンピューターの時間設定を変更すると、POSIX時間も変化します。卵を調理していて、4分間持続するタイマーが必要な場合は、現在の時刻が変更されても、4分間持続する必要があります。5時の3時に会議のタイマーを設定している場合、現地時間が変更された場合は、そのタイマーを変更する必要があります。したがって、ここsteady_clockとの違いsystem_clock
Billy ONeal

1
@ 5gon:system_clockUTCである必要はありません。
Billy ONeal、2015

1
@CharlesSalvia POSIX時間はUTCに関連付けられているため、UTCにはうるう秒がある(en.wikipedia.org/wiki/Unix_time#Leap_secondsを参照)ことにも注意してください。つまり、マシンの時刻が調整されない場合でも、C / POSIXの時刻は単調ではない可能性があります。
Michael Schlottke-Lakemper

3
UPDATE(Visual Studio 2015)安定したクロックの実装が変更されました[.....]安定したクロックはQueryPerformanceCounter()に基づいており、high_resolution_clockは定常的なクロックのtypedefになりました。msdn.microsoft.com/en-us/library/hh874757.aspx
felix-b

47

ビリーは、私が完全に同意するISO C ++標準に基づく素晴らしい答えを提供しました。しかし、ストーリーにはもう1つの側面があります-実生活。現在のところ、一般的なコンパイラーの実装では、これらのクロックに違いはないようです。

gcc 4.8:

#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
   ...
#else
  typedef system_clock steady_clock;
#endif
  typedef system_clock high_resolution_clock;

Visual Studio 2012:

class steady_clock : public system_clock
{   // wraps monotonic clock
public:
  static const bool is_monotonic = true;    // retained
  static const bool is_steady = true;
};

typedef system_clock high_resolution_clock;

gccの場合、チェックするだけで安定したクロックを処理しているかどうかを確認しis_steady、それに応じて動作させることができます。ただし、VS2012はここで少しだましているようです:-)

高精度クロックが必要な場合は、C ++ 11公式クロックインターフェイスに準拠した独自のクロックを作成し、実装が追いつくのを待つことをお勧めします。コードで直接OS固有のAPIを使用するよりもはるかに優れたアプローチになります。Windowsの場合、次のように実行できます。

// Self-made Windows QueryPerformanceCounter based C++11 API compatible clock
struct qpc_clock {
  typedef std::chrono::nanoseconds                       duration;      // nanoseconds resolution
  typedef duration::rep                                  rep;
  typedef duration::period                               period;
  typedef std::chrono::time_point<qpc_clock, duration>   time_point;
  static bool is_steady;                                                // = true
  static time_point now()
  {
    if(!is_inited) {
      init();
      is_inited = true;
    }
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return time_point(duration(static_cast<rep>((double)counter.QuadPart / frequency.QuadPart *
                                                period::den / period::num)));
  }

private:
  static bool is_inited;                                                // = false
  static LARGE_INTEGER frequency;
  static void init()
  {
    if(QueryPerformanceFrequency(&frequency) == 0)
      throw std::logic_error("QueryPerformanceCounter not supported: " + std::to_string(GetLastError()));
  }
};

Linuxの場合はさらに簡単です。clock_gettime上記のコードのmanページを読んで修正するだけです。


19
VC ++ 2012の実装は、MSの標準ライブラリのメンテナからバグとして認められています。
ildjarn 2012年

5
興味のある方のために、これはそのバグへのリンクです
Ben Voigt 2013

1
BoostはQueryPerformanceCounterを使用するため、Visual Studio 14がリリースされるまで、このバグをboost :: chronoを使用することで回避できます
Mohamed El-Nakib '19

そして、ここにGCC 5.3.0で転送するPOSIXコールがあります:stackoverflow.com/a/36700301/895245
Ciro Santilli郝海东冠状病六四事件法轮機能

19

GCC 5.3.0の実装

C ++ stdlibはGCCソース内にあります:

  • high_resolution_clock のエイリアスです system_clock
  • system_clock 利用可能な次の最初のものに転送します。
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock 利用可能な次の最初のものに転送します。
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

次にCLOCK_REALTIMEvs CLOCK_MONOTONICについて説明します:CLOCK_REALTIMEとCLOCK_MONOTONICの違い?


2

たぶん、最も大きな違いは、その開始点がstd::chrono:system_clock1.1.1970、いわゆるUNIXエポックであるという事実です。一方、std::chrono::steady_clock通常はPCの起動時間であり、間隔の測定に最適です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.