Boost.Asio の Timer精度調査 (Windows環境)
要旨
- 目的: Boost.Asio には Timerクラスである deadline_timerがある.この時間精度について調べてみる.
- 調査環境: Boost 1.44.0, Windows XP (x64)
- 結論: date_timeライブラリに依存している.調査環境におけるdate_timeライブラリの時間取得関数はGetSystemTime/GetSystemTimeAsFileTimeである.これらの精度は10ms程度.
boost::asio::deadline_timerクラス
主に関係するヘッダファイルは次の通り:
- boost/asio/deadline_timer.hpp
- basic_deadline_timer に boost::posix_time::ptime を与えてtypedef
- boost/asio/basic_deadline_timer.hpp
- クラス定義.動作はdeadline_timer_serviceに投げる.
- boost/asio/deadline_timer_service.hpp
- 動作の記述.詳細はdetail::deadline_timer_serviceに投げる
- boost/asio/detail/deadline_timer_service.hpp
- 動作の詳細定義.
これより,wait()やasync_***()系の定義は
これらのファイルの中では,時間に関係する部分はtemplateによって記述されている.最終的に,(現在の実装では)
読み進めると,タイマーなど分解能を要する時間に関係する部分は,boost::posix_time::microsec_clock に依存するように書かれている.
date_time の時間精度
主に関係するヘッダファイルは次の通り:
- boost/date_time/microsec_time_clock.hpp
- boost/date_time/filetime_functions.hpp
micro秒の扱いについて定義しているmicrosec_time_clock.hppを見てみると,82行目あたりに次のような定義を見る.
#ifdef BOOST_HAS_GETTIMEOFDAY timeval tv; gettimeofday(&tv, 0); //gettimeofday does not support TZ adjust on Linux. std::time_t t = tv.tv_sec; boost::uint32_t sub_sec = tv.tv_usec; #elif defined(BOOST_HAS_FTIME) winapi::file_time ft; winapi::get_system_time_as_file_time(ft); uint64_t micros = winapi::file_time_to_microseconds(ft); // it will not wrap, since ft is the current time // and cannot be before 1970-Jan-01 std::time_t t = static_cast<std::time_t>(micros / 1000000UL); // seconds since epoch // microseconds -- static casts supress warnings boost::uint32_t sub_sec = static_cast<boost::uint32_t>(micros % 1000000UL); #else #error Internal Boost.DateTime error: BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK is defined, however neither gettimeofday nor FILETIME support is detected. #endif
winapi::get_system_time_as_file_time関数 などは filetime_functions.hpp 内で定義されており,たとえば66行目あたりを見ると次のように定義されている.
typedef FILETIME file_time; typedef SYSTEMTIME system_time; inline void get_system_time_as_file_time(file_time& ft) { #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205)) // Some runtime library implementations expect local times as the norm for ctime. file_time ft_utc; GetSystemTimeAsFileTime(&ft_utc); FileTimeToLocalFileTime(&ft_utc, &ft); #elif defined(BOOST_NO_GETSYSTEMTIMEASFILETIME) system_time st; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); #else GetSystemTimeAsFileTime(&ft); #endif }
すなわち,調査環境においては,時間計測はGetSystemTime / GetSystemTimeAsFileTime 関数に依存していることがわかる.これらの関数は精度10ms程度程度である.
結論
調査環境では,Boost.Asioのタイマー系の精度は10ms程度のようであるから,これにあった運用をすべきである.
備考1
Windows環境では,clock (GetSystemTimeAsFileTime依存), GetTickCount, timeGetTime, QueryPerformanceCounter などが利用できる.(TODO: 暇ができたらまとめる・・・か?)
シビアな時間制御をする際は,timeGetTimeや QueryPerformanceCounter を用いて自前で用意をしたほうがよいだろう.
しかし,そもそもAsioの想定しているSocket通信や,非RTOSであるWindowsでそれほどシビアな運用を要求するアプリケーションを作成するのは無茶というもの・・・かもしれない.
備考2
boostのバージョンによって実装は日々変化しているようだ.手元にあった1.44と1.36のソースをざっと見比べてみたが,ファイル構成や関数定義について,さまざまな部分で違いがみられた.
参考
- Reference - Boost 1.46.1, http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/reference.html