Recientemente decidí que necesitaba para cambiar el uso de milisegundos y microsegundos para mi clase Timer, y después de investigar un poco he decidido que QueryPerformanceCounter es, probablemente, mi apuesta más segura. (La advertencia en Boost::Posix que es posible que no funciona en la API de Win32 me puso un poco). Sin embargo, no estoy muy seguro de cómo implementarlo.

Lo que estoy haciendo es llamar a cualquier GetTicks() esque función estoy usando y su asignación a los del Temporizador startingTicks variable. A continuación, para encontrar la cantidad de tiempo que ha pasado yo sólo resta el valor devuelto por la función de la startingTicks, y cuando me restablecer el temporizador acabo de llamar a la función y asignar startingTicks a ella. Por desgracia, desde el código que he visto no es tan simple como llamar a QueryPerformanceCounter(), y no estoy seguro de que lo voy a pasar como argumento.

InformationsquelleAutor Anonymous | 2009-11-15

4 Comentarios

  1. 155
    #include <windows.h>
    
    double PCFreq = 0.0;
    __int64 CounterStart = 0;
    
    void StartCounter()
    {
        LARGE_INTEGER li;
        if(!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";
    
        PCFreq = double(li.QuadPart)/1000.0;
    
        QueryPerformanceCounter(&li);
        CounterStart = li.QuadPart;
    }
    double GetCounter()
    {
        LARGE_INTEGER li;
        QueryPerformanceCounter(&li);
        return double(li.QuadPart-CounterStart)/PCFreq;
    }
    
    int main()
    {
        StartCounter();
        Sleep(1000);
        cout << GetCounter() <<"\n";
        return 0;
    }

    Este programa debe mostrar un número de cerca de 1000 (windows dormir ¿no es exacta, pero debe ser como 999).

    La StartCounter() función registra el número de garrapatas el contador de rendimiento en el CounterStart variable. El GetCounter() función devuelve el número de milisegundos desde StartCounter() última fue llamado como un doble, así que si GetCounter() devuelve 0.001 entonces ha sido de alrededor de 1 microsegundo desde StartCounter() fue llamado.

    Si quieres tener el temporizador utilice segundos en su lugar, a continuación, cambie

    PCFreq = double(li.QuadPart)/1000.0;

    a

    PCFreq = double(li.QuadPart);

    o si desea microsegundos, a continuación, utilizar

    PCFreq = double(li.QuadPart)/1000000.0;

    Pero en realidad se trata de comodidad, ya que devuelve un double.

    • Exactamente, ¿qué es LARGE_INTEGER?
    • es un tipo windows, básicamente, un portátil entero de 64 bits. Es la definición depende de si el sistema de destino admite enteros de 64 bits o no. Si el sistema no es compatible con 64 bits enteros, a continuación, se define como el 2 de 32 bits enteros, un HighPart y un LowPart. Si el sistema tiene soporte para 64 bits enteros, entonces es una unión entre el 2 enteros de 32 bits y de 64 bits int llamado la QuadPart.
    • Así se devuelve el número de garrapatas en alta resolución de reloj del sistema, que creo que es de hardware a su cargo, y es por eso que usted necesita para utilizar QueryPerformanceFrequency para averiguar la frecuencia del reloj. En mi sistema, la frecuencia es de 2,272,000 hz, o acerca de 2.272 pasos por microsegundo.
    • Y debo incluir Windows.h?
    • Así que basado en su explicación, devuelve el tiempo en milisegundos, pero con precisión de microsegundos?
    • Es de precisión se basa en realidad en su sistema de temporizador, que debe ser un poco más preciso que el de microsegundos. Pero sí, el ejemplo como yo de la lista funcionará bien por microsegundo de temporización, o se puede cambiar de modo de 1.0 significa 1 microsegundo si prefiere pensar acerca de microsegundos.
    • Me estoy poniendo el tiempo en segundos, pero necesito precisión de microsegundos. Yo estaba usando una función que devuelve el número de milisegundos, lo cual me dividido por 1000 para obtener la hora en cuestión de segundos, pero desde ahora necesito microsegundos yo necesitaba un temporizador que devuelve el número de microsegundos o alguna otra unidad con precisión de microsegundos. Vamos a intentar poner en práctica ahora.
    • Me estoy poniendo muy pequeños valores (e-312). Estoy leyendo todo y no estar en un equipo portátil tiene algo que ver con él?
    • Donde están recibiendo los valores pequeños?
    • Al realizar la m_StartingTime – li.QuadPart (sin dividir, porque de lo que se mostró anteriormente parece que el tiempo está en segundos, con una precisión de microsegundos).
    • si haces algo como StartCounter(); cout << GetCounter(); a continuación, usted debe obtener un valor pequeño, porque no había mucho tiempo entre StartCounter() y GetCounter(). Si usted StartCounter(); Sleep(1000); cout << GetCounter(); a continuación, debe ser de 1 segundo.
    • Así que usted todavía necesita la división, o de lo contrario vas a obtener el número de pasos que el contador ha hecho desde m_StartingTime, pero desea una unidad estándar de tiempo.
    • Si haces la división con números enteros a pesar de que usted va a perder precisión. Las funciones que he publicado manejar esto correctamente, y en mi respuesta me dicen cómo modificar el uso de los segundos como la unidad, pero sigue dando de alta precisión.
    • Ah entiendo cuál es la frecuencia es, por ahora. Que trabajó definitivamente, pero ahora la diferencia es de 975 que es demasiado alto. No creo que lo que usted describe devuelve en segundos con una precisión de microsegundos. Creo que devuelve el número de microsegundos.
    • Mis funciones como listados de retorno de milisegundos, pero me dicen cómo modificar el StartCounter función() para devolver segundos con alta precisión en la respuesta.
    • Así por ejemplo se dice que el uso de segundos cambiar el /1000 sólo la asignación de PCFreq a la QueryPerformanceFrequency. Cuando hago lo que puedo conseguir los números en los cientos de modo que, obviamente, no puede ser a la derecha.
    • Tampoco estoy usando Sleep().
    • Pruebe el código de ejemplo en mi respuesta, he editado de modo que si la llamada a QueryPerformanceFrequency falla, entonces se imprime en la pantalla.
    • No creo que esté fallando. He decidido que sólo voy a seguir con milisegundos y se redondea a 1 milisegundo siempre es 0. El QueryPerformanceCounter está dando muy inestable resultados, yo.e los marcos están muy alterados y lisa, que no en todos.
    • Esta respuesta está mal, es deficiente. QueryPerformanceCounter lee un núcleo específico de contador de ciclos de registro, y si el hilo de ejecución ha sido reprogramada en otro núcleo, dos medidas de QueryPerformanceCounter incorporar no sólo el tiempo transcurrido, pero a menudo un fijo, grande y duro para localizar delta entre los dos núcleos de los registros. Así que esto sólo funciona de forma fiable como se presenta si el proceso está vinculado a un determinado núcleo.
    • Te sugiero que señalar que el contador de rendimiento de frecuencia es tratada como una constante. De hecho, el valor obtenido para la frecuencia se desvía de la const devuelto por la llamada a QueryPerformanceFrequency. más…
    • href=»http://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx» >documentación de MSDN dice: On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). Este código no está mal imperfecto, pero algunas BIOS o HAL.
    • sí, he leído que antes de Microsoft de forma de echarse la culpa. La escritura de código que se basa en algo que se sabe que no funciona de forma fiable es errónea, si el error está en la función de la aplicación o la forma en que se interactúa con el firmware o hardware es irrelevante. Decir que el uso de esta para la velocidad de fotogramas cálculos en un juego, enviar su juego, el 20% de la empresa/hardware de los tornillos – ¿crees que la prensa, los clientes van a decir que «eso está bien – es un BIOS/HAL problema»? A veces es posible evitar este con algo de carga-tiempo de la cruz-core delta mediciones, pero AFAIK no SOS la aplicación.
    • Yo sólo veían en esto un poco más. He añadido la siguiente llamada en la StartCounter función: old_mask = SetThreadAffinityMask(GetCurrentThread,1); y, a continuación, volver al final SetThreadAffinityMask ( GetCurrentThread , old_mask ) ;. Espero que va a hacer el truco. Esto debería evitar que mi hilo de reprogramando para nada pero la 1ª núcleo de la CPU. (Que es, evidentemente, sólo una solución para un entorno de pruebas)
    • si que se adapte a sus propósitos, eso es genial… triste que este tipo de cosas es un problema en este día y edad, en particular con las otras funciones de sincronización de Windows sólo ser bueno ~15ms.
    • El problema es que yo realmente no sé en qué otras opciones serían si quiero llegar en el momento preciso. También, se plantea la cuestión de cómo el Visual Studio analizador ocupa de este problema o si tiene los mismos problemas.
    • lo que la mayoría de la gente hace es repetir la operación tantas veces que el tiempo acumulado se levanta hacia/en el intervalo de segundos, luego se divide por el número de iteraciones. No sé lo que el analizador no, pero si tienes la integración con el sistema operativo entonces usted probablemente puede registrarse para el kernel de información sobre el subproceso de programación – evitando el problema… creo que Visual Studio necesita derechos de administrador local para el analizador de ejecución, que se relacionen con este. Personalmente, creo que el frente delta análisis se menciono anteriormente… escribió para el trabajo, a pesar de que por tanto, los problemas en torno a la distribución de ella.

  2. 18

    Puedo usar la define:

    /** Use to init the clock */
    #define TIMER_INIT \
        LARGE_INTEGER frequency; \
        LARGE_INTEGER t1,t2; \
        double elapsedTime; \
        QueryPerformanceFrequency(&frequency);
    
    
    /** Use to start the performance timer */
    #define TIMER_START QueryPerformanceCounter(&t1);
    
    /** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */
    #define TIMER_STOP \
        QueryPerformanceCounter(&t2); \
        elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart; \
        std::wcout<<elapsedTime<<L" sec"<<endl;

    De uso (soportes para evitar que se redefine el concepto de):

    TIMER_INIT
    
    {
       TIMER_START
       Sleep(1000);
       TIMER_STOP
    }
    
    {
       TIMER_START
       Sleep(1234);
       TIMER_STOP
    }

    Salida de ejemplo de uso:

    1.00003 sec
    1.23407 sec
  3. 2

    Suponiendo que estás en Windows (si es así usted debe etiquetar la pregunta como tal!), en esta página de MSDN usted puede encontrar la fuente de una forma sencilla, útil HRTimer clase de C++ que envuelve el necesario sistema de llamadas a hacer algo muy parecido a lo que usted requiere (sería fácil añadir un GetTicks() método, en particular, para hacer exactamente lo que usted necesita).

    En plataformas distintas de Windows, no hay ninguna función QueryPerformanceCounter, por lo que la solución no será directamente portátil. Sin embargo, si se envuelve en una clase como la mencionada HRTimer, será más fácil para cambiar la implementación de la clase a usar lo que la plataforma actual es de hecho capaz de ofrecer (tal vez a través de Boost o lo que sea!).

  4. 1

    Me gustaría extender esta pregunta con un controlador NDIS ejemplo en llegar a tiempo. Como se sabe, KeQuerySystemTime (imitado bajo NdisGetCurrentSystemTime) tiene una baja resolución por encima de milisegundos, y hay algunos procesos, como la red de paquetes o de otro Irp que pueden necesitar un mejor marca de hora;

    El ejemplo es igual de simple:

    LONG_INTEGER data, frequency;
    LONGLONG diff;
    data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency)
    diff = data.QuadPart / (Frequency.QuadPart/$divisor)

    donde el divisor es de 10^3, o 10^6 dependiendo de la resolución requerida.

Dejar respuesta

Please enter your comment!
Please enter your name here