¿Se garantiza que gettimeofday () tenga una resolución de microsegundos?


Estoy portando un juego, que fue escrito originalmente para la API Win32, a Linux (bueno, portando el puerto OS X del puerto Win32 a Linux).

He implementado QueryPerformanceCounter dando los segundos de uso desde el inicio del proceso:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

Esto, junto con QueryPerformanceFrequency() dando una constante 1000000 como frecuencia, funciona bien en mi máquina, dándome una variable de 64 bits que contiene uSeconds desde el inicio del programa.

Entonces ¿esto es portátil? no quiero discover funciona de manera diferente si el núcleo fue compilado de cierta manera o algo por el estilo. Sin embargo, estoy bien con que no sea portable a algo que no sea Linux.

Author: Rann Lifshitz, 2008-08-01

10 answers

Tal vez. Pero tienes problemas más grandes. gettimeofday() puede resultar en tiempos incorrectos si hay procesos en su sistema que cambian el temporizador (es decir, ntpd). Sin embargo, en un linux" normal", creo que la resolución de gettimeofday() es 10us. Puede saltar hacia adelante y hacia atrás y el tiempo, en consecuencia, en función de los procesos que se ejecutan en su sistema. Esto efectivamente hace que la respuesta a su pregunta no.

Debe buscar en clock_gettime(CLOCK_MONOTONIC) los intervalos de tiempo. Sufre de varios problemas menos debido a las cosas como sistemas multi-core y ajustes de reloj externos.

También, mira la función clock_getres().

 56
Author: Louis Brandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-14 12:28:51

Alta Resolución, Bajo Tiempo de Sobrecarga para Procesadores Intel

Si usas hardware Intel, te mostramos cómo leer el contador de instrucciones en tiempo real de la CPU. Le indicará el número de ciclos de CPU ejecutados desde que se arrancó el procesador. Este es probablemente el contador de grano más fino que puede obtener para la medición del rendimiento.

Tenga en cuenta que este es el número de ciclos de CPU. En Linux puede obtener la velocidad de la CPU de / proc / cpuinfo y dividir para obtener el número de segundos. Convertir esto a un doble es bastante útil.

Cuando corro esto en mi caja, obtengo

11867927879484732
11867927879692217
it took this long to call printf: 207485

Aquí está la guía para desarrolladores de Intel que da toneladas de detalles.

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
 40
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-23 16:53:06

@Bernard:

Tengo que admitir que la mayor parte de tu ejemplo pasó directamente sobre mi cabeza. Se compila, y parece funcionar, sin embargo. ¿Es seguro para sistemas SMP o SpeedStep?

Esa es una buena pregunta... Creo que el código está bien. Desde un punto de vista práctico, lo usamos en mi empresa todos los días, y ejecutamos en una amplia gama de cajas, de 2 a 8 núcleos. Por supuesto, YMMV, etc, pero parece ser un confiable y de bajo costo (porque no hace un contexto cambiar al sistema-espacio) método de tiempo.

En General cómo funciona es:

  • declarar el bloque de código ensamblador (y volátil, por lo que el optimizer lo dejará en paz).
  • ejecute la instrucción CPUID. Además de obtener información de la CPU (con la que no hacemos nada) sincroniza el búfer de ejecución de la CPU para que los tiempos no se vean afectados por la ejecución fuera de orden.
  • ejecute la ejecución rdtsc (read timestamp). Esto trae el número de ciclos de la máquina ejecutados desde que se restableció el procesador. Este es un 64-bit valor, por lo que con las velocidades actuales de la CPU se envolverá cada 194 años más o menos. Curiosamente, en la referencia original de Pentium, notan que se envuelve alrededor de cada 5800 años más o menos.
  • el último par de líneas almacenan los valores de los registros en las variables hi y lo, y poner que en el valor de retorno de 64 bits.

Notas específicas:

  • Ejecución fuera de orden puede causa resultados incorrectos, por lo que ejecutamos el instrucción "cpuid" que además de darle alguna información acerca de la cpu también sincroniza cualquier ejecución de instrucciones fuera de orden.

  • La mayoría de los sistemas operativos sincronizan los contadores en las CPU cuando se inician, por lo que la respuesta es buena para dentro de un par de nanosegundos.

  • El comentario de hibernación es probablemente cierto, pero en la práctica probablemente no se preocupe por los tiempos a través de la hibernación límite.

  • Con respecto a speedstep: Las CPU Intel más nuevas compensan la velocidad cambia y devuelve un recuento ajustado. Hice un escaneo rápido algunas de las cajas en nuestra red y solo encontramos una caja que no lo tenía: un Pentium 3 corriendo un viejo servidor de base de datos. (estas son cajas de Linux, así que revisé con: grep constant_tsc / proc / cpuinfo)

  • No estoy seguro sobre las CPU AMD, somos principalmente una tienda de Intel, aunque conozco a algunos de nuestros gurús de sistemas de bajo nivel hizo un Evaluación de AMD.

Espero que esto satisfaga su curiosidad, es un interesante y (IMHO) área de programación poco estudiada. Sabes cuando Jeff y Joel estaban hablando de si un programador debe saber o no C? Yo estaba gritándoles, " hey olviden esas cosas de alto nivel C... montador es lo que debes aprender si quieres saber qué es el ordenador haciendo!"

 18
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-15 06:44:06
 14
Author: David Schlosnagle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-07 23:04:40

Wine está usando gettimeofday() para implementar QueryPerformanceCounter() y se sabe que hace que muchos juegos de Windows funcionen en Linux y Mac.

Comienza http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

Conduce a http://source.winehq.org/source/dlls/ntdll/time.c#L448

 11
Author: Vincent Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-04 14:44:56

Así que dice microsegundos explícitamente, pero dice que la resolución del reloj del sistema no está especificada. Supongo que la resolución en este contexto significa cómo la cantidad más pequeña que nunca se incrementará?

La estructura de datos se define como tener microsegundos como unidad de medida, pero eso no significa que el reloj o el sistema operativo sea realmente capaz de medir eso finamente.

Como otras personas han sugerido, gettimeofday() es malo porque establecer la hora puede causar reloj sesgar y tirar de su cálculo. clock_gettime(CLOCK_MONOTONIC) es lo que quieres, y clock_getres() te dirá la precisión de tu reloj.

 10
Author: Joe Shaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-19 04:39:01

La resolución real de gettimeofday() depende de la arquitectura de hardware. Los procesadores Intel y las máquinas SPARC ofrecen temporizadores de alta resolución que miden microsegundos. Otras arquitecturas de hardware recurren al temporizador del sistema, que normalmente se establece en 100 Hz. En tales casos, la resolución temporal será menos precisa.

Obtuve esta respuesta de Medición de Tiempo y Temporizadores de Alta Resolución, Parte I

 9
Author: CodingWithoutComments,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-12 18:12:53

Por mi experiencia, y por lo que he leído en Internet, la respuesta es "No", no está garantizada. Depende de la velocidad de la CPU, el sistema operativo, el sabor de Linux, etc.

 5
Author: CodingWithoutComments,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-01 15:01:13

Esta respuesta menciona problemas con el ajuste del reloj. Tanto sus problemas de garantía de unidades tick como los problemas con el tiempo ajustado se resuelven en C++11 con la biblioteca <chrono>.

Se garantiza que el reloj std::chrono::steady_clock no se ajustará, y además avanzará a una velocidad constante en relación con el tiempo real, por lo que tecnologías como SpeedStep no deben afectarlo.

Puede obtener unidades typesafe mediante la conversión a una de las especializaciones std::chrono::duration, tales como std::chrono::microseconds. Con este tipo no hay ambigüedad sobre las unidades utilizadas por el valor de tick. Sin embargo, tenga en cuenta que el reloj no necesariamente tiene esta resolución. Puede convertir una duración a attosegundos sin tener realmente un reloj tan preciso.

 5
Author: bames53,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:37

La lectura del RDTSC no es confiable en sistemas SMP, ya que cada CPU mantiene su propio contador y cada contador no está garantizado por sincronizado con respecto a otra CPU.

Podría sugerir intentar clock_gettime(CLOCK_REALTIME). El manual posix indica que esto debe implementarse en todos los sistemas compatibles. Puede proporcionar un recuento de nanosegundos, pero probablemente querrá verificar clock_getres(CLOCK_REALTIME) en su sistema para ver cuál es la resolución real.

 3
Author: Doug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-07 23:05:44