はかせのラボ

私の頭の中を書いていく雑記ブログです

boost boost::cpu_timer 読んでみる

あいさつ

どうも、はかせです。
今回はboostを入れたときに最初に触った
boost::cpu_timerのコードを読んでみたいと思います。

読んでみる

まずは前回同様定義へジャンプしてみます。

class BOOST_TIMER_DECL cpu_timer
{
public:

  //  constructor
  cpu_timer() BOOST_NOEXCEPT  { start(); }

  //  observers
  bool          is_stopped() const BOOST_NOEXCEPT              { return m_is_stopped; }
  cpu_times     elapsed() const BOOST_NOEXCEPT;  // does not stop()
  std::string   format(short places, const std::string& format) const
                      { return ::boost::timer::format(elapsed(), places, format); }
  std::string   format(short places = default_places) const
                      { return ::boost::timer::format(elapsed(), places); }
  //  actions
  void          start() BOOST_NOEXCEPT;
  void          stop() BOOST_NOEXCEPT;
  void          resume() BOOST_NOEXCEPT; 

private:
  cpu_times     m_times;
  bool          m_is_stopped;
};

どうやらコンストラクタでstartメソッドを呼んでいるようです。
ではstartの実装に飛んでみます。

void cpu_timer::start() BOOST_NOEXCEPT
{
  m_is_stopped = false;
  get_cpu_times(m_times);
}

今のところホントにboostなのかってぐらい単純ですね。
timerのストップフラグを折って
get_cpu_timesというメソッドを呼んでいますね。
(なんか嫌な予感がするな)

じゃ次へ飛びましょう。

  void get_cpu_times(boost::timer::cpu_times& current)
  {
    boost::chrono::duration<boost::int64_t, boost::nano>
      x (boost::chrono::high_resolution_clock::now().time_since_epoch());
    current.wall = x.count();

# if defined(BOOST_WINDOWS_API)

    FILETIME creation, exit;
    if (::GetProcessTimes(::GetCurrentProcess(), &creation, &exit,
            (LPFILETIME)&current.system, (LPFILETIME)&current.user))
    {
      current.user   *= 100;  // Windows uses 100 nanosecond ticks
      current.system *= 100;
    }
    else
    {
      current.system = current.user = boost::timer::nanosecond_type(-1);
    }
# else
    tms tm;
    clock_t c = ::times(&tm);
    if (c == static_cast<clock_t>(-1)) // error
    {
      current.system = current.user = boost::timer::nanosecond_type(-1);
    }
    else
    {
      current.system = boost::timer::nanosecond_type(tm.tms_stime + tm.tms_cstime);
      current.user = boost::timer::nanosecond_type(tm.tms_utime + tm.tms_cutime);
      boost::int_least64_t factor;
      if ((factor = tick_factor()) != -1)
      {
        current.user *= factor;
        current.system *= factor;
      }
      else
      {
        current.user = current.system = boost::timer::nanosecond_type(-1);
      }
    }
# endif
  }

なにやらメソッドを呼んで値を取得し、
マクロの分岐を使って環境ごとに取得した値に補正をかけて返しているようです。

ブログの文字数と私の理解力が限界を迎えつつあるので
一気に根っこまで行きます。

extern "C" {
BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC
QueryPerformanceCounter(::_LARGE_INTEGER* lpPerformanceCount);

BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC
QueryPerformanceFrequency(::_LARGE_INTEGER* lpFrequency);
} // extern "C"

BOOST_FORCEINLINE BOOL_ QueryPerformanceCounter(LARGE_INTEGER_* lpPerformanceCount)
{
    return ::QueryPerformanceCounter(reinterpret_cast< ::_LARGE_INTEGER* >(lpPerformanceCount));
}

BOOST_FORCEINLINE BOOL_ QueryPerformanceFrequency(LARGE_INTEGER_* lpFrequency)
{
    return ::QueryPerformanceFrequency(reinterpret_cast< ::_LARGE_INTEGER* >(lpFrequency));
}

C言語登場≡\(・ω・)/ シュタッ
externということはどっかにあるC言語のメソッドを呼んでいるんですかね。
WinAPIに同じような名前のやつがあったので
多分それと似た動きをすると思います。

要はCPU時間をナノかミリかはわかりませんが
取得してきてくれるものでしょう。きっと。

つまりboost::cpu_timerは
①CPU時間を取得
②環境や設定に応じた値に修正
③formatメソッドを使いstringで値を返す

大雑把ですがこんな感じの処理をしているようです。

あとがき

今回はboost::cpu_timerのコードを読んでみました。
前回のlexical_castに比べて読みやすい印象を受けました。
まぁそれでも追いきれなくなったのでまだまだなんですけどね。

あと地味にこの記事で100記事目だったようです。
それでは今回はこの辺でノシ