c++ - example - Diferencia entre std:: system_clock y std:: steady_clock?
date c++ (3)
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 compiladores 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 alcancen. 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<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()));
}
};
Para Linux es aún más fácil. Simplemente lea la página man de clock_gettime y modifique el código anterior.
¿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 objetivo 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_clockrepresentan 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_clockrepresentan relojes para los cuales los valores detime_pointnunca disminuyen a medida que avanza el tiempo físico y para los cuales los valores detime_pointavanzan 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_clockrepresentan relojes con el período de tick más corto.high_resolution_clockpuede ser un sinónimo desteady_clockosteady_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,
C1yC2indican los tipos de reloj.t1yt2son valores devueltos porC1::now()donde la llamada que retornat1ocurre antes de que la llamada retornet2y ambas llamadas ocurren antes deC1::time_point::max(). [Nota: esto significa queC1no se envolvió entret1yt2. -finalizar nota]Expresión:
C1::is_steady
Devoluciones:const bool
Semántica operacional:truesit1 <= t2siempre es verdadero y el tiempo entre los tics del reloj es constante, de lo contrario esfalse.
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 programa (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.
GCC 5.3.0 (C ++ stdlib está dentro de la fuente GCC):
-
high_resolution_clockes un alias parasystem_clock -
system_clockreenvía al primero de los siguientes que está disponible:-
clock_gettime(CLOCK_REALTIME, ...) -
gettimeofday -
time
-
-
steady_clockavanza 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?