Usando solo ANSI C, ¿hay alguna forma de medir el tiempo con precisión de milisegundos o más? Estaba navegando time.h pero solo encontré segundas funciones de precisión.
c
portability
time-precision
corto
fuente
fuente
Respuestas:
No hay una función ANSI C que proporcione una resolución mejor que 1 segundo, pero la función POSIX
gettimeofday
proporciona una resolución de microsegundos. La función de reloj solo mide la cantidad de tiempo que un proceso ha pasado ejecutándose y no es precisa en muchos sistemas.Puede usar esta función así:
Esto vuelve
Time elapsed: 1.000870
a mi máquina.fuente
timeval::tv_usec
siempre es inferior a un segundo, está en bucle. Es decir, para tomar diferencias de tiempo mayores de 1 segundo, debe:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
timersub
función. Podemos usartval_result
valores (tv_sec y tv_usec) tal cual.fuente
CLOCKS_PER_SEC / 1000
podría ser inexacta, lo que podría afectar el resultado final (aunque en mi experienciaCLOCKS_PER_SEC
siempre ha sido un múltiplo de 1000). Hacer(1000 * clock()) / CLOCKS_PER_SEC
es menos susceptible a la inexactitud de división, pero por otro lado es más susceptible al desbordamiento. Solo algunos asuntos a considerar.Siempre uso la función clock_gettime (), devolviendo el tiempo del reloj CLOCK_MONOTONIC. El tiempo devuelto es la cantidad de tiempo, en segundos y nanosegundos, desde algún punto no especificado en el pasado, como el inicio del sistema de la época.
fuente
clock_gettime(CLOCK_MONOTONIC, ...)
e incluso existe la macro de prueba de características_POSIX_MONOTONIC_CLOCK
.Implementando una solución portátil
Como ya se mencionó aquí que no existe una solución ANSI adecuada con suficiente precisión para el problema de medición de tiempo, quiero escribir sobre las formas de obtener una solución de medición de tiempo portátil y, si es posible, de alta resolución.
Reloj monótono vs. sellos de tiempo
En términos generales, hay dos formas de medir el tiempo:
El primero usa un contador de reloj monótono (a veces se lo llama contador de ticks) que cuenta los ticks con una frecuencia predefinida, por lo que si tiene un valor de ticks y se conoce la frecuencia, puede convertirlos fácilmente en tiempo transcurrido. En realidad, no se garantiza que un reloj monótono refleje la hora actual del sistema de ninguna manera, también puede contar los tics desde el inicio del sistema. Pero garantiza que un reloj siempre se ejecute de manera creciente independientemente del estado del sistema. Por lo general, la frecuencia está vinculada a una fuente de alta resolución de hardware, por eso proporciona una alta precisión (depende del hardware, pero la mayoría del hardware moderno no tiene problemas con las fuentes de reloj de alta resolución).
La segunda forma proporciona un valor de hora (fecha) basado en el valor actual del reloj del sistema. También puede tener una alta resolución, pero tiene un inconveniente importante: este tipo de valor de hora puede verse afectado por diferentes ajustes de hora del sistema, es decir, cambio de zona horaria, cambio de horario de verano (DST), actualización del servidor NTP, hibernación del sistema, etc. en. En algunas circunstancias, puede obtener un valor de tiempo transcurrido negativo que puede conducir a un comportamiento indefinido. En realidad, este tipo de fuente de tiempo es menos confiable que la primera.
Entonces, la primera regla en la medición del intervalo de tiempo es usar un reloj monotónico si es posible. Por lo general, tiene una alta precisión y es confiable por diseño.
Estrategia de reserva
Al implementar una solución portátil, vale la pena considerar una estrategia alternativa: use un reloj monotónico si está disponible y un enfoque de retroceso a las marcas de tiempo si no hay un reloj monotónico en el sistema.
Ventanas
Hay un gran artículo llamado Adquisición de marcas de tiempo de alta resolución en MSDN sobre la medición de tiempo en Windows que describe todos los detalles que puede necesitar saber sobre el soporte de software y hardware. Para adquirir una marca de tiempo de alta precisión en Windows, debe:
consultar una frecuencia de temporizador (tics por segundo) con QueryPerformanceFrequency :
La frecuencia del temporizador se fija en el arranque del sistema, por lo que debe obtenerla solo una vez.
consultar el valor actual de las marcas con QueryPerformanceCounter :
escale los ticks al tiempo transcurrido, es decir, a microsegundos:
Según Microsoft, no debería tener ningún problema con este enfoque en Windows XP y versiones posteriores en la mayoría de los casos. Pero también puede usar dos soluciones de respaldo en Windows:
GetTickCount
, pero está disponible a partir de Windows Vista y superior.OS X (macOS)
OS X (macOS) tiene sus propias unidades de tiempo absoluto de Mach que representan un reloj monótono. La mejor manera de comenzar es el artículo de Apple Preguntas y respuestas técnicas QA1398: Unidades de tiempo absoluto de Mach que describe (con los ejemplos de código) cómo usar la API específica de Mach para obtener tics monótonos. También hay una pregunta local al respecto llamada alternativa clock_gettime en Mac OS X que al final puede dejarle un poco confundido sobre qué hacer con el posible desbordamiento del valor porque la frecuencia del contador se usa en forma de numerador y denominador. Entonces, un breve ejemplo de cómo obtener el tiempo transcurrido:
obtener el numerador y denominador de frecuencia de reloj:
Necesitas hacer eso solo una vez.
consultar el valor actual de la marca con
mach_absolute_time
:escale los ticks al tiempo transcurrido, es decir, a microsegundos, utilizando el numerador y el denominador previamente consultados:
La idea principal para evitar un desbordamiento es reducir las marcas a la precisión deseada antes de usar el numerador y el denominador. Como la resolución inicial del temporizador está en nanosegundos, la dividimos
1000
para obtener microsegundos. Puede encontrar el mismo enfoque utilizado en time_mac.c de Chromium . Si realmente necesita una precisión de nanosegundos, considere leer el ¿Cómo puedo usar mach_absolute_time sin desbordar? .Linux y UNIX
La
clock_gettime
llamada es su mejor manera en cualquier sistema compatible con POSIX. Puede consultar el tiempo desde diferentes fuentes de reloj, y el que necesitamos esCLOCK_MONOTONIC
. No todos los sistemas tienenclock_gettime
soporteCLOCK_MONOTONIC
, por lo que lo primero que debe hacer es verificar su disponibilidad:_POSIX_MONOTONIC_CLOCK
se define a un valor>= 0
significa queCLOCK_MONOTONIC
está disponible;si
_POSIX_MONOTONIC_CLOCK
está definido0
significa que también debe verificar si funciona en tiempo de ejecución, sugiero usarsysconf
:El uso de
clock_gettime
es bastante sencillo:obtener el valor del tiempo:
He reducido el tiempo a microsegundos aquí.
Calcule la diferencia con el valor de tiempo anterior recibido de la misma manera:
La mejor estrategia alternativa es utilizar la
gettimeofday
llamada: no es monótono, pero proporciona una resolución bastante buena. La idea es la misma que conclock_gettime
, pero para obtener un valor de tiempo debe:Nuevamente, el valor del tiempo se reduce a microsegundos.
SGI IRIX
IRIX tiene la
clock_gettime
llamada, pero le faltaCLOCK_MONOTONIC
. En cambio, tiene su propia fuente de reloj monotónico definida como laCLOCK_SGI_CYCLE
que debe usar en lugar deCLOCK_MONOTONIC
conclock_gettime
.Solaris y HP-UX
Solaris tiene su propia interfaz de temporizador de alta resolución
gethrtime
que devuelve el valor actual del temporizador en nanosegundos. Aunque las versiones más nuevas de Solaris pueden tenerclock_gettime
, puede seguirgethrtime
si necesita soportar versiones antiguas de Solaris.El uso es simple:
HP-UX carece
clock_gettime
, pero admitegethrtime
lo que debe usar de la misma manera que en Solaris.BeOS
BeOS también tiene su propia interfaz de temporizador de alta resolución
system_time
que devuelve el número de microsegundos transcurridos desde que se inició la computadora.Ejemplo de uso:
OS / 2
OS / 2 tiene su propia API para recuperar marcas de tiempo de alta precisión:
consultar una frecuencia de temporizador (ticks por unidad) con
DosTmrQueryFreq
(para el compilador GCC):consultar el valor actual de ticks con
DosTmrQueryTime
:escale los ticks al tiempo transcurrido, es decir, a microsegundos:
Implementación de ejemplo
Puede echar un vistazo a la biblioteca plibsys que implementa todas las estrategias descritas anteriormente (consulte ptimeprofiler * .c para más detalles).
fuente
timespec_get
: stackoverflow.com/a/36095407/895245timespec_get
No es monótono.timespec_get
de C11Devuelve hasta nanosegundos, redondeados a la resolución de la implementación.
Parece una estafa ANSI de POSIX '
clock_gettime
.Ejemplo: a
printf
se realiza cada 100 ms en Ubuntu 15.10:El borrador estándar C11 N1570 7.27.2.5 "La función timespec_get dice":
C ++ 11 también obtuvo
std::chrono::high_resolution_clock
: Temporizador de alta resolución multiplataforma C ++implementación de glibc 2.21
Se puede encontrar en
sysdeps/posix/timespec_get.c
:tan claramente
TIME_UTC
actualmente solo es compatiblereenvía a
__clock_gettime (CLOCK_REALTIME, ts)
, que es una API POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.htmlLinux x86-64 tiene una
clock_gettime
llamada al sistema.Tenga en cuenta que este no es un método de microevaluación a prueba de fallas porque:
man clock_gettime
dice que esta medida puede tener discontinuidades si cambia alguna configuración de hora del sistema mientras se ejecuta el programa. Esto debería ser un evento raro, por supuesto, y es posible que pueda ignorarlo.esto mide el tiempo de la pared, por lo que si el planificador decide olvidarse de su tarea, parecerá que se ejecuta por más tiempo.
Por esas razones,
getrusage()
podría ser una mejor herramienta de evaluación comparativa POSIX, a pesar de su precisión máxima más baja en microsegundos.Más información en: Mida el tiempo en Linux: ¿tiempo vs reloj vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?
fuente
La mejor precisión que puede obtener es mediante el uso de la instrucción "rdtsc" solo x86, que puede proporcionar una resolución a nivel de reloj (por supuesto, no debe tener en cuenta el costo de la llamada rdtsc en sí, que se puede medir fácilmente en inicio de la aplicación).
El problema principal aquí es medir la cantidad de relojes por segundo, que no debería ser demasiado difícil.
fuente
La respuesta aceptada es lo suficientemente buena. Pero mi solución es más simple. Solo pruebo en Linux, uso gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0.
Además
gettimeofday
, eltv_sec
es la parte del segundo, y eltv_usec
es microsegundos , no milisegundos .Imprime:
1522139691342 1522139692342
exactamente un segundofuente
Debajo de ventanas:
fuente