winapi timer cpu-cycles

winapi - ¿Cómo obtengo el recuento de ciclos de la CPU en Win32?



timer cpu-cycles (5)

En Win32, ¿hay alguna manera de obtener un recuento de ciclo de CPU único o algo similar que sería uniforme para múltiples procesos / idiomas / sistemas / etc.

Estoy creando algunos archivos de registro, pero tengo que generar múltiples archivos de registro porque estamos organizando el tiempo de ejecución .NET, y me gustaría evitar llamar de uno a otro para iniciar sesión. Como tal, estaba pensando que solo produciría dos archivos, los combinaría y luego los ordenaría, para obtener una línea de tiempo coherente que implique llamadas en todo el mundo.

Sin embargo, GetTickCount no aumenta para cada llamada, por lo que no es confiable. ¿Hay un número mejor para recibir las llamadas en el orden correcto al ordenar?

Editar : Gracias a @Greg que me puso en la pista de QueryPerformanceCounter, que hizo el truco.


La salida RDTSC puede depender de la frecuencia del reloj del núcleo actual, que para las CPU modernas no es constante ni, en una máquina multinúcleo, constante.

Use la hora del sistema y, si se trata de fuentes de varios sistemas, use una fuente de tiempo NTP. Puede obtener lecturas de tiempo confiables y consistentes de esa manera; si la sobrecarga es demasiado para sus propósitos, utilice el HPET para calcular el tiempo transcurrido, ya que la última lectura de tiempo confiable conocida es mejor que usar el HPET solo.


Puede usar la instrucción de CPU RDTSC (suponiendo x86). Esta instrucción proporciona el contador de ciclos de la CPU, pero tenga en cuenta que aumentará muy rápidamente a su valor máximo y luego se restablecerá a 0. Como se menciona en el artículo de Wikipedia, es mejor que utilice la función QueryPerformanceCounter .


System.Diagnostics.Stopwatch.GetTimestamp () devuelve el número de ciclo de la CPU desde un origen de tiempo (tal vez cuando la computadora se inicia, pero no estoy seguro) y nunca lo he visto aumentar entre 2 llamadas.

Los ciclos de la CPU serán específicos para cada computadora, por lo que no podrá usarlos para fusionar archivos de registro entre 2 computadoras.


Use GetTickCount y agregue otro contador al fusionar los archivos de registro. No le dará la secuencia perfecta entre los diferentes archivos de registro, pero al menos mantendrá todos los registros de cada archivo en el orden correcto.


¡Aquí hay un artículo interesante! dice que no use RDTSC, sino que use QueryPerformanceCounter .

Conclusión:

El uso de la timeGetTime() no es confiable en muchos sistemas operativos basados ​​en Windows porque la granularidad del temporizador del sistema puede ser de hasta 10-15 milisegundos, lo que significa que timeGetTime() solo tiene una precisión de 10-15 milisegundos. [Tenga en cuenta que las granularidades altas se producen en sistemas operativos basados ​​en NT como Windows NT, 2000 y XP. Windows 95 y 98 tienden a tener una granularidad mucho mejor, alrededor de 1-5 ms.]

Sin embargo, si llama a timeBeginPeriod(1) al comienzo de su programa (y timeEndPeriod(1) al final), timeGetTime() generalmente tendrá una precisión de 1-2 milisegundos y le proporcionará información de tiempo extremadamente precisa.

Sleep() comporta de manera similar; el tiempo que Sleep() realmente duerme va de la mano con la granularidad de timeGetTime() , por lo que después de llamar a timeBeginPeriod(1) una vez, Sleep(1) realmente dormirá durante 1-2 milisegundos, Sleep(2) para 2-3, y así sucesivamente (en lugar de dormir en incrementos de hasta 10-15 ms).

Para una sincronización de mayor precisión (precisión de menos de milisegundos), es probable que desee evitar el uso del RDTSC mnemónico de ensamblaje porque es difícil de calibrar ; en su lugar, utilice QueryPerformanceFrequency y QueryPerformanceCounter , que tienen una precisión de menos de 10 microsegundos (0,00001 segundos).

Para el tiempo simple, tanto timeGetTime como QueryPerformanceCounter funcionan bien, y QueryPerformanceCounter es obviamente más preciso. Sin embargo, si necesita hacer algún tipo de "pausas cronometradas" (como las necesarias para la limitación de framerate), debe tener cuidado de no estar en un bucle llamando a QueryPerformanceCounter, esperando que alcance cierto valor; esto consumirá el 100% de tu procesador. En cambio, considere un esquema híbrido, donde llama a Sleep (1) (¡no olvide timeBeginPeriod (1) primero!) Cuando necesite pasar más de 1 ms de tiempo, y luego ingrese solamente el bucle QueryPerformanceCounter 100% -busy al termine la última <1 / 1000th de un segundo de la demora que necesita. Esto le proporcionará retrasos ultra precisos (precisos a 10 microsegundos), con un uso mínimo de la CPU. Vea el código de arriba.