Diferencia entre std :: system_clock y std :: steady_clock?

¿Cuál es la diferencia entre std::system_clock y std::steady_clock ? (Un ejemplo de caso que ilustra diferentes resultados / comportamientos sería genial).

Si mi objective es medir con precisión el tiempo de ejecución de las funciones (como un punto de referencia), ¿cuál sería la mejor opción entre std::system_clock , std::steady_clock y std::high_resolution_clock ?

Desde N3376:

20.11.7.1 [time.clock.system] / 1:

Los objetos de clase system_clock representan el tiempo de reloj de pared del reloj en tiempo real de todo el sistema.

20.11.7.2 [time.clock.steady] / 1:

Los objetos de clase steady_clock representan relojes para los cuales los valores de time_point nunca disminuyen a medida que avanza el tiempo físico y para los cuales los valores de time_point avanzan a una velocidad constante en relación con el tiempo real. Es decir, el reloj no puede ajustarse.

20.11.7.3 [time.clock.hires] / 1:

Los objetos de la clase high_resolution_clock representan relojes con el período de tick más corto. high_resolution_clock puede ser un sinónimo de steady_clock o steady_clock .

Por ejemplo, el reloj de todo el sistema podría verse afectado por algo como el horario de verano, momento en el que el tiempo real enumerado en algún momento en el futuro puede ser un momento del pasado. (Por ejemplo, en los EE. UU., En el tiempo de caída retrocede una hora, por lo que la misma hora se experimenta “dos veces”) Sin embargo, steady_clock no puede verse afectado por tales cosas.

Otra forma de pensar sobre “estable” en este caso es en los requisitos definidos en la tabla de 20.11.3 [time.clock.req] / 2:

En la Tabla 59, C1 y C2 indican los tipos de reloj. t1 y t2 son valores devueltos por C1::now() donde la llamada que retorna t1 ocurre antes de que la llamada retorne t2 y ambas llamadas ocurren antes de C1::time_point::max() . [Nota: esto significa que C1 no se envolvió entre t1 y t2 . -Finalizar nota]

Expresión: C1::is_steady
Devoluciones: const bool
Semántica operacional: true si t1 < = t2 siempre es verdadero y el tiempo entre los tics del reloj es constante, de lo contrario es false .

Eso es todo lo que tiene el estándar en sus diferencias.

Si desea hacer benchmarking, su mejor opción probablemente sea std::high_resolution_clock , porque es probable que su plataforma use un temporizador de alta resolución (por ejemplo, QueryPerformanceCounter en Windows) para este reloj. Sin embargo, si es un punto de referencia, realmente debería considerar usar temporizadores específicos de la plataforma para su punto de referencia, porque las diferentes plataformas manejan esto de manera diferente. Por ejemplo, algunas plataformas pueden proporcionarle algunos medios para determinar la cantidad real de marcas de reloj requeridas por el progtwig (independientemente de otros procesos que se ejecutan en la misma CPU). Mejor aún, pon tus manos en un generador de perfiles real y úsalo.

Billy brindó una gran respuesta basada en el estándar ISO C ++ con el que estoy totalmente de acuerdo. Sin embargo, hay otro lado de la historia: la vida real. Parece que en este momento no hay diferencia entre esos relojes en la implementación de comstackdores populares:

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; 

En el caso de gcc puede verificar si se trata de un reloj constante simplemente marcando is_steady y comportándose como corresponde. Sin embargo, VS2012 parece engañar un poco aquí 🙂

Si necesita un reloj de alta precisión, le recomiendo escribir ahora su propio reloj que cumpla con la interfaz oficial del reloj C ++ 11 y esperar a que las implementaciones lo scopen. Será un enfoque mucho mejor que usar la API específica del sistema operativo directamente en su código. Para Windows puedes hacerlo así:

 // 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 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((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())); } }; 

Para Linux es aún más fácil. Simplemente lea la página man de clock_gettime y modifique el código anterior.

Implementación de GCC 5.3.0

C ++ stdlib está dentro de la fuente GCC:

  • high_resolution_clock es un alias para system_clock
  • system_clock reenvía al primero de los siguientes que está disponible:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock avanza al primero de los siguientes que está disponible:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Entonces CLOCK_REALTIME vs CLOCK_MONOTONIC se explica en: ¿ Diferencia entre CLOCK_REALTIME y CLOCK_MONOTONIC?