web-dev-qa-db-ja.com

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

違いは何ですか std::system_clockおよびstd::steady_clock? (異なる結果/動作を示す例は素晴らしいでしょう)。

私の目標が関数の実行時間を正確に測定することである場合(ベンチマークなど)、std::system_clockstd::steady_clockおよびstd::high_resolution_clock

83
Vincent

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_clock_または_steady_clock_の同義語です。

たとえば、システム全体の時計は夏時間などの影響を受ける可能性があり、その時点で将来のある時点でリストされる実際の時間は実際には過去の時間になる可能性があります。 (たとえば、米国では、フォールタイムが1時間戻るため、同じ時間が「2回」発生します)ただし、_steady_clock_はそのようなことによる影響を受けません。

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

表59では、_C1_および_C2_はクロックタイプを示します。 _t1_および_t2_はC1::now()によって返される値です。ここで_t1_を返す呼び出しは_t2_を返す呼び出しの前に発生し、これらの呼び出しは両方ともC1::time_point::max()。 [注:これは、_C1_が_t1_と_t2_の間でラップアラウンドしなかったことを意味します。 —注を終了]

式:_C1::is_steady_
戻り値:_const bool_
操作上のセマンティクス:_t1 <= t2_が常にtrueで、クロックティック間の時間が一定の場合はtrue、そうでない場合はfalse

これが標準の違いです。

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

66
Billy ONeal

Billyは、私が完全に同意する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ページを読んで、上記のコードを修正してください。

45
Mateusz Pusz

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_REALTIME_対_CLOCK_MONOTONIC_について説明します。 CLOCK_REALTIMEとCLOCK_MONOTONICの違い?