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_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 detime_point
nunca disminuyen a medida que avanza el tiempo físico y para los cuales los valores detime_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 desteady_clock
osteady_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
yC2
indican los tipos de reloj.t1
yt2
son valores devueltos porC1::now()
donde la llamada que retornat1
ocurre antes de que la llamada retornet2
y ambas llamadas ocurren antes deC1::time_point::max()
. [Nota: esto significa queC1
no se envolvió entret1
yt2
. -finalizar nota]Expresión:
C1::is_steady
Devoluciones:const bool
Semántica operacional:true
sit1 <= t2
siempre 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_clock
es un alias parasystem_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?