Разница между std:: системные часы и std:: устойчивый часы?


в чем разница между std::system_clock и std::steady_clock? (Пример случай, который иллюстрирует различные результаты / поведение было бы здорово).

если моя цель состоит в том, чтобы точно измерить время выполнения функции (как эталон), что бы быть лучшим выбором между std::system_clock,std::steady_clock и std::high_resolution_clock?

3 73

3 ответа:

Из N3376:

20.11.7.1 [время.часы.system]/1:

объекты класса system_clock представляют время настенных часов от общесистемных часов реального времени.

20.11.7.2 [время.часы.устойчивый]/1:

объекты класса steady_clock представляют часы, для которых значения time_point никогда не уменьшаться по мере продвижения физического времени и для каких значений time_point вперед с постоянной скоростью относительно реального времени. То есть часы не могут быть отрегулированы.

20.11.7.3 [время.часы.hires]/1:

объекты класса high_resolution_clock представляют часы с самым коротким периодом тика. high_resolution_clock может быть синоним system_clock или steady_clock.

steady_clock не позволено быть повлиянным на такими вещами.

другой способ мышления об "устойчивом" в этом случае заключается в требованиях, определенных в таблице 20.11.3 [time.часы.req] / 2:

В Таблице 59 C1 и C2 обозначают типы часов. t1 и t2 - это значения, возвращаемые C1::now() куда возвращается вызов t1 происходит до возврата вызова t2 и оба эти вызова происходят до C1::time_point::max(). [ Примечание: это означает C1 не обернуть вокруг между t1 и t2. -конец Примечание ]

выражение: C1::is_steady
Возвращает:const bool
Операционная Семантика:true если t1 <= t2 всегда верно и время между тиками часов является постоянным, в противном случае false.

это все, что стандарт имеет на их различия.

если вы хотите сделать бенчмаркинг, ваш лучший выбор, вероятно, будет std::high_resolution_clock, потому что вполне вероятно, что ваша платформа использует таймер высокого разрешения (например,QueryPerformanceCounter на Windows) для этих часов. Однако, если вы проводите бенчмаркинг, вы должны действительно рассмотреть возможность использования платформенных таймеров для вашего бенчмаркинга, потому что разные платформы обрабатывают это по-разному. Например, некоторые платформы могут дать вам некоторые средства определения фактического количества тактов, требуемых программой (независимо от других процессов, запущенных на тот же процессор). А еще лучше, возьмите в руки настоящий профилировщик и используйте его.

Билли предоставил отличный ответ, основанный на стандарте ISO C++, с которым я полностью согласен. Однако есть и другая сторона истории-реальная жизнь. Похоже, что сейчас действительно нет разницы между этими часами в реализации популярных компиляторов:

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, и ждать реализации, чтобы догнать. Это будет гораздо лучший подход, чем использование конкретного 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 это еще проще. Просто прочитайте man-страницу clock_gettime и изменить код выше.

реализация 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 vs CLOCK_MONOTONIC см.: разница между CLOCK_REALTIME и CLOCK_MONOTONIC?