В чем разница между std::system_clock
а также std::steady_clock
? (Пример случая, который иллюстрирует различные результаты / поведение, был бы великолепен).
Если моя цель состоит в том, чтобы точно измерить время выполнения функций (например, тест), что будет лучшим выбором между std::system_clock
, std::steady_clock
а также std::high_resolution_clock
?
От 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
, —Конечная записка]Выражение:
C1::is_steady
Возвращает:const bool
Операционная семантика:true
еслиt1 <= t2
всегда верно, а время между тактами постоянноfalse
,
Это все, что стандарт имеет на их различия.
Если вы хотите сделать бенчмаркинг, ваш лучший выбор, вероятно, будет std::high_resolution_clock
потому что вполне вероятно, что ваша платформа использует таймер высокого разрешения (например, QueryPerformanceCounter
на винде) за эти часы. Однако, если вы проводите бенчмаркинг, вам действительно стоит подумать об использовании таймеров для конкретных платформ в качестве эталона, потому что разные платформы обрабатывают это по-разному. Например, некоторые платформы могут дать вам некоторые средства для определения фактического количества тактов, необходимых программе (независимо от других процессов, работающих на том же процессоре). А еще лучше, возьмите в руки настоящий профилировщик и используйте его.
Билли дал отличный ответ, основанный на стандарте 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 это даже проще. Просто прочитайте справочную страницу 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
против CLOCK_MONOTONIC
объясняется по адресу: Разница между CLOCK_REALTIME и CLOCK_MONOTONIC?