Разница между std :: system_clock и std :: stable_clock?

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

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

76

Решение

От 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 на винде) за эти часы. Однако, если вы проводите бенчмаркинг, вам действительно стоит подумать об использовании таймеров для конкретных платформ в качестве эталона, потому что разные платформы обрабатывают это по-разному. Например, некоторые платформы могут дать вам некоторые средства для определения фактического количества тактов, необходимых программе (независимо от других процессов, работающих на том же процессоре). А еще лучше, возьмите в руки настоящий профилировщик и используйте его.

58

Другие решения

Билли дал отличный ответ, основанный на стандарте 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 и измените код выше.

42

Внедрение 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?

12