Разница между std:: системные часы и std:: устойчивый часы?
в чем разница между std::system_clock
и std::steady_clock
? (Пример случай, который иллюстрирует различные результаты / поведение было бы здорово).
если моя цель состоит в том, чтобы точно измерить время выполнения функции (как эталон), что бы быть лучшим выбором между std::system_clock
,std::steady_clock
и std::high_resolution_clock
?
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:
steady_clock не позволено быть повлиянным на такими вещами.объекты класса
high_resolution_clock
представляют часы с самым коротким периодом тика.high_resolution_clock
может быть синонимsystem_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
vsCLOCK_MONOTONIC
см.: разница между CLOCK_REALTIME и CLOCK_MONOTONIC?