Разница между std:: system_clock и std:: stable_clock?
В чем разница между std::system_clock
и std::steady_clock
? (Примерный пример, иллюстрирующий разные результаты/поведение, будет большим).
Если моя цель - точно измерить время выполнения функций (например, контрольный показатель), какой лучший выбор между std::system_clock
, std::steady_clock
и std::high_resolution_clock
?
Ответы
Ответ 1
От N3376:
20.11.7.1 [time.clock.system]/1:
Объекты класса system_clock
представляют собой часы настенных часов из общесистемных часов реального времени.
20.11.7.2 [time.clock.steady]/1:
Объекты класса steady_clock
представляют собой часы, для которых значения time_point
никогда не уменьшаются по мере продвижения физического времени и для которых значения time_point
продвигаются с постоянной скоростью относительно реального времени. То есть, часы могут не регулироваться.
20.11.7.3 [time.clock.hires]/1:
Объекты класса high_resolution_clock
представляют часы с самым коротким тиковым периодом. high_resolution_clock
может быть синонимом для system_clock
или steady_clock
.
Например, на системные часы может повлиять что-то вроде летнего времени, и в этот момент фактическое время, указанное в какой-то момент в будущем, может на самом деле быть временем в прошлом. (Например, в США в осеннее время отходит один час, поэтому один и тот же час переживается "дважды"). Однако steady_clock
не может быть затронуто такими вещами.
Другой способ мышления об "устойчивом" в этом случае - в требованиях, определенных в таблице 20.11.3 [time.clock.req]/2:
В таблице 59 C1
и C2
обозначены типы часов. t1
и t2
- значения, возвращаемые C1::now()
где возврат вызова t1
происходит до вызова t2
и оба этих вызова происходят до C1::time_point::max()
. [Примечание: это означает, что C1
не обертывается между t1
и t2
. -End note]
Выражение: C1::is_steady
Возврат: const bool
Операционная семантика: true
если t1 <= t2
всегда истинно, а время между часами - постоянным, в противном случае - false
.
То, что весь стандарт имеет на свои различия.
Если вы хотите провести бенчмаркинг, лучшим вариантом будет, вероятно, std::high_resolution_clock
, потому что, вероятно, ваша платформа использует таймер с высоким разрешением (например, QueryPerformanceCounter
для Windows) для этих часов. Однако, если вы проводите бенчмаркинг, вам следует подумать о том, чтобы использовать определенные для платформы таймеры для своего теста, потому что разные платформы обрабатывают это по-другому. Например, некоторые платформы могут дать вам некоторые способы определения фактического количества тактов синхронизации, которые требуется программе (независимо от других процессов, работающих на одном процессоре). Еще лучше, возьмитесь за реальный профилировщик и используйте это.
Ответ 2
Билли предоставил отличный ответ на основе стандарта ISO С++, с которым я полностью согласен. Однако есть и другая сторона истории - настоящая жизнь. Похоже, что сейчас практически нет разницы между этими часами в реализации популярных компиляторов:
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, кажется, немного обманывает здесь: -)
Если вам нужны часы с высокой точностью, я рекомендую сейчас писать собственные часы, которые соответствуют официальному интерфейсу часов С++ 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 это еще проще. Просто прочитайте страницу руководства clock_gettime
и измените код выше.
Ответ 3
Внедрение 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?