Skip to content

Instantly share code, notes, and snippets.

@t-mat
Created September 21, 2012 20:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save t-mat/3763854 to your computer and use it in GitHub Desktop.
Save t-mat/3763854 to your computer and use it in GitHub Desktop.
MSVC++2012の std::chrono の精度はどれくらい?

std::chrono の精度はどれくらい?

短いまとめ

MSVC++2012 の std::chrono 下にあるクラスの時間精度は、良くてミリ秒オーダだと思ったほうが良い

MSVC++2012 の std::chrono の定義

  • まとめ:std::chrono 下の全クラスは時刻取得に _Xtime_get_ticks() を用いている

%ProgramFiles(x86)\Microsoft Visual Studio 11.0\VC\include\chrono 内での定義は以下のようになっている

// MSVC++2012 : <chrono>
namespace std {
  namespace chrono {
    struct system_clock {
      ...
      static time_point now() __NOEXCEPT {
        return (time_point(duration(_Xtime_get_ticks())));
      }
      ...
    };
    class steady_clock : public system_clock { ... };
    typedef steady_clock monotonic_clock;
    typedef system_clock high_resolution_clock;
  }
}

つまり std::chrono 下のクラス system_clock, steady_clock, monotonic_clock, high_resolution_clock は 時刻取得(now())に _Xtime_get_ticks() を用いており、精度の違いは無い。

_Xtime_get_ticks() の実際のコードは?

%ProgramFiles(x86)\Microsoft Visual Studio 11.0\VC\crt\src\thr\xtime.c によると、 以下のようになっている

_LONGLONG _Xtime_get_ticks() {
  FILETIME ft;
  GetSystemTimeAsFileTime(&ft);
  ... 以下 ft を適宜変換する ...
}

つまり WIN32 API GetSystemTimeAsFileTime() によって精度が決まる。

WIN32 API GetSystemTimeAsFileTime() の精度は?

この API の返す値は単純にシステム(ドライバ)依存なので、 以下のようなコードで簡単に実測した

#include <windows.h>
#include <stdint.h>
#include <array>
#include <chrono>

static uint64_t getTime() {
  ULARGE_INTEGER uli;
  GetSystemTimeAsFileTime((LPFILETIME) &uli);
  return uli.QuadPart;
}

int main() {
  typedef std::chrono::steady_clock Clk;
  static std::array<uint64_t, 1000 * 1000 * 10> a = { 0 };
  uint64_t t0 = getTime();
  for(auto e = Clk::now() + std::chrono::seconds(5); Clk::now() < e; ) {
    uint64_t t1 = getTime();
    a[(size_t) min(t1-t0, a.size()-1)] += 1;
    t0 = t1;
  }
  for(size_t i = 0; i < a.size(); ++i) {
    a[i] && printf("%9d nsec : %10lld\n", i * 100, a[i]);
  }
  return 0;
}

# 別のタイマ源を用いて、実時間としての精度も見るべきだけど、面倒なのでしていない

手元の環境 (ASUS P8Z68-V, Core i7-2600K 3.40GHz, Windows7 x64) では以下のようになった:

        0 nsec :  379730723
  1000000 nsec :       2139
  1000100 nsec :       2860

つまり、ほぼ1ミリ秒 (100万ナノ秒) の精度で値を返している。

まとめ

  • MSVC++2012 の std::chrono 下の全クラスは、WIN32 API GetSystemTimeAsFileTime() によって時刻を取得している
  • この API の数値表現上の精度は、100 ナノ秒単位となっている
  • ただし、実際の時間精度は環境依存となる
  • よって MSVC++2012 の std::chrono には、2012 年時点での QueryPerformanceCounter() に期待される MHz (マイクロ秒) オーダの精度は見込めない
@t-mat
Copy link
Author

t-mat commented May 21, 2021

VC++2019かつWindows8以降の場合、下記のように実装されている。計測した限り、 system_clock , steady_clock のいずれの場合も、実計測時間で100ns精度の値が返ってくる。また、 steady_clock::now() のほうが若干処理時間が短いように見える。1フレに数十回程度の実行であれば、気にする必要はないかも。

// C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/include/chrono
namespace std::chrono {
  struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime
    static time_point now() noexcept {
      return time_point(duration(_Xtime_get_ticks()));
    }
  }

  struct steady_clock { // wraps QueryPerformanceCounter
    static time_point now() noexcept { // get current time
      const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot
      const long long _Ctr  = _Query_perf_counter();
      const long long _Whole = (_Ctr / _Freq) * period::den;
      const long long _Part  = (_Ctr % _Freq) * period::den / _Freq;
      return time_point(duration(_Whole + _Part));
    }
  };

  using high_resolution_clock = steady_clock;
}
// C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/crt/src/stl/xtime.cpp
long long _Xtime_get_ticks() { // get system time in 100-nanosecond intervals since the epoch
    FILETIME ft;
    __crtGetSystemTimePreciseAsFileTime(&ft);
    return ((static_cast<long long>(ft.dwHighDateTime)) << 32) + static_cast<long long>(ft.dwLowDateTime) - _Epoch;
}

// C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/crt/src/stl/awint.hpp
#define __crtGetSystemTimePreciseAsFileTime(x) GetSystemTimePreciseAsFileTime(x)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment