visual studio compile linux winapi visual-c++ unix timer

studio - visual c++ en linux



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

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 uSeconds 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() da una frecuencia constante de 1000000 como la frecuencia, funciona bien en mi máquina , dándome una variable de 64 bits que contiene uSeconds desde el inicio del programa.

Entonces, ¿ es portátil? No quiero descubrir que funciona de manera diferente si el núcleo se compiló de cierta manera o algo así. Sin embargo, estoy de acuerdo con que no sea portátil para algo que no sea Linux.


Entonces 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 se incrementará la cantidad más pequeña.

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

Al igual que otras personas han sugerido, gettimeofday() es malo porque establecer la hora puede causar que el reloj se desvíe y deseche su cálculo. clock_gettime(CLOCK_MONOTONIC) es lo que desea, y clock_getres() le dirá la precisión de su reloj.


La resolución real de gettimeofday () depende de la arquitectura del 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 generalmente se establece en 100 Hz. En tales casos, la resolución del tiempo será menos precisa.

Obtuve esta respuesta de Medición de tiempo de alta resolución y temporizadores, Parte I


@Bernardo:

Tengo que admitir que la mayoría de tu ejemplo fue directo a mi cabeza. Sin embargo, sí compila y parece funcionar. ¿Es esto seguro para los 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 corremos en una amplia gama de cajas, desde 2 hasta 8 núcleos. Por supuesto, YMMV, etc., pero parece ser un método de temporización confiable y de bajo costo (porque no hace que un contexto cambie al espacio del sistema).

En general, cómo funciona es:

  • declara que el bloque de código es ensamblador (y volátil, por lo que el optimizador lo dejará solo).
  • ejecuta 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 de rdtsc (lectura de marca de tiempo). Esto obtiene el número de ciclos de máquina ejecutados desde que se reinició el procesador. Este es un valor de 64 bits, por lo que con las velocidades actuales de la CPU se ajustará cada 194 años más o menos. Curiosamente, en la referencia original de Pentium, notan que se envuelve cada 5800 años más o menos.
  • el último par de líneas almacena los valores de los registros en las variables hi y lo, y lo coloca en el valor de retorno de 64 bits.

Notas especificas:

  • la ejecución fuera de orden puede causar resultados incorrectos, por lo que ejecutamos la instrucción "cpuid" que además de brindarle información sobre la cpu también sincroniza cualquier ejecución de instrucción 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 en un par de nanosegundos.

  • El comentario de hibernación probablemente sea cierto, pero en la práctica probablemente no te interesen los tiempos a través de los límites de hibernación.

  • con respecto al paso de velocidad: las CPU Intel más nuevas compensan los cambios de velocidad y devuelven un recuento ajustado. Hice un escaneo rápido en algunos de los cuadros de nuestra red y encontré solo un cuadro que no lo tenía: un Pentium 3 con un servidor de base de datos antiguo. (estos son cuadros de Linux, así que verifiqué con: grep constant_tsc / proc / cpuinfo)

  • No estoy seguro acerca de las CPU AMD, somos principalmente una tienda de Intel, aunque sé que algunos de nuestros gurús de sistemas de bajo nivel hicieron una evaluación AMD.

Espero que esto satisfaga su curiosidad, es un área de programación interesante y (en mi humilde opinión) poco estudiada. ¿Sabes cuando Jeff y Joel estaban hablando sobre si un programador debería saber C? Les estaba gritando: "¡Oigan, olviden que las cosas de alto nivel C ... ensamblador es lo que deben aprender si quieren saber qué está haciendo la computadora!"


La lectura del RDTSC no es confiable en los sistemas SMP, ya que cada CPU mantiene su propio contador y no se garantiza que cada contador esté sincronizado con respecto a otra CPU.

Podría sugerir probar 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 desee comprobar clock_getres(CLOCK_REALTIME) en su sistema para ver cuál es la resolución real.


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


Tal vez. Pero tienes mayores problemas. gettimeofday() puede generar 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 clock_gettime(CLOCK_MONOTONIC) para ver los intervalos de tiempo. Sufre de varios problemas menos debido a cosas como sistemas de múltiples núcleos y configuraciones de reloj externo.

Además, mire la función clock_getres() .




Esta respuesta menciona problemas con el ajuste del reloj. Tanto sus problemas para garantizar las unidades de marca 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 ajusta, 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 al convertir a una de las especializaciones std::chrono::duration Duration, 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 un reloj tan preciso.


Alta resolución, bajo tiempo de sobrecarga para procesadores Intel

Si usa hardware Intel, aquí le mostramos cómo leer el contador de instrucciones en tiempo real de la CPU. Le indicará la cantidad de ciclos de CPU ejecutados desde que se inició el procesador. Este es probablemente el contador más fino que puede obtener para medir el 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 ejecuto esto en mi caja, me sale

11867927879484732 11867927879692217 it took this long to call printf: 207485

Aquí está la guía del desarrollador de Intel que brinda 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); }