Deseo calcular el tiempo que tardó una API en devolver un valor. El tiempo necesario para tal acción está en el espacio de nano segundos. Como la API es una clase / función de C ++, estoy usando timer.h para calcular lo mismo:
#include <ctime>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
clock_t start;
double diff;
start = clock();
diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
cout<<"printf: "<< diff <<'\n';
return 0;
}
El código anterior da el tiempo en segundos. ¿Cómo consigo lo mismo en nano segundos y con más precisión?
clock()
no es tan rápido como pensaba.Respuestas:
Lo que otros han publicado sobre ejecutar la función repetidamente en un bucle es correcto.
Para Linux (y BSD) desea utilizar clock_gettime () .
Para las ventanas, desea utilizar QueryPerformanceCounter . Y aquí hay más sobre QPC
Aparentemente, hay un problema conocido con QPC en algunos conjuntos de chips, por lo que es posible que desee asegurarse de no tener esos conjuntos de chips. Además, algunos AMD de doble núcleo también pueden causar un problema . Vea la segunda publicación de sebbbi, donde dice:
EDITAR 16/07/2013:
Parece que existe cierta controversia sobre la eficacia de QPC en determinadas circunstancias, como se indica en http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx
Sin embargo, esta respuesta de StackOverflow https://stackoverflow.com/a/4588605/34329 establece que QPC debería funcionar bien en cualquier sistema operativo MS después del paquete de servicio 2 de Win XP.
Este artículo muestra que Windows 7 puede determinar si los procesadores tienen un TSC invariante y recurren a un temporizador externo si no lo tienen. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html La sincronización entre procesadores sigue siendo un problema.
Otra buena lectura relacionada con los temporizadores:
Consulte los comentarios para obtener más detalles.
fuente
CLOCK_MONOTONIC_RAW
, si está disponible, para obtener el tiempo del hardware no ajustado por NTP.Esta nueva respuesta usa la
<chrono>
facilidad de C ++ 11 . Si bien hay otras respuestas que muestran cómo usar<chrono>
, ninguna muestra cómo usar<chrono>
con laRDTSC
facilidad mencionada en varias de las otras respuestas aquí. Así que pensé que iba a mostrar cómo utilizarRDTSC
con<chrono>
. Además, demostraré cómo puede crear una plantilla del código de prueba en el reloj para que pueda cambiar rápidamente entreRDTSC
las funciones de reloj integradas de su sistema (que probablemente se basarán enclock()
,clock_gettime()
y / oQueryPerformanceCounter
.Tenga en cuenta que la
RDTSC
instrucción es específica de x86.QueryPerformanceCounter
es solo para Windows. Yclock_gettime()
es solo POSIX. A continuación, presento dos relojes nuevos:std::chrono::high_resolution_clock
ystd::chrono::system_clock
, que, si puede asumir C ++ 11, ahora son multiplataforma.Primero, así es como se crea un reloj compatible con C ++ 11 a partir de las
rdtsc
instrucciones de ensamblaje de Intel . Lo llamaréx::clock
:Todo lo que hace este reloj es contar los ciclos de la CPU y almacenarlos en un entero de 64 bits sin signo. Es posible que deba modificar la sintaxis del lenguaje ensamblador para su compilador. O su compilador puede ofrecer un intrínseco que puede usar en su lugar (por ejemplo
now() {return __rdtsc();}
).Para construir un reloj hay que darle la representación (tipo de almacenamiento). También debe proporcionar el período del reloj, que debe ser una constante de tiempo de compilación, aunque su máquina puede cambiar la velocidad del reloj en diferentes modos de energía. Y a partir de ellos, puede definir fácilmente la duración y el punto de tiempo "nativos" de su reloj en términos de estos fundamentos.
Si todo lo que quiere hacer es generar el número de tics del reloj, realmente no importa qué número dé para el período del reloj. Esta constante solo entra en juego si desea convertir el número de pulsos del reloj en alguna unidad de tiempo real, como nanosegundos. Y en ese caso, cuanto más preciso sea el suministro de la velocidad del reloj, más precisa será la conversión a nanosegundos (milisegundos, lo que sea).
A continuación se muestra un código de ejemplo que muestra cómo usarlo
x::clock
. En realidad, he creado una plantilla para el código del reloj, ya que me gustaría mostrar cómo puede usar muchos relojes diferentes con la misma sintaxis exacta. Esta prueba en particular muestra cuál es la sobrecarga de bucle cuando se ejecuta lo que desea cronometrar bajo un bucle:Lo primero que hace este código es crear una unidad de "tiempo real" para mostrar los resultados. He elegido picosegundos, pero puede elegir cualquier unidad que desee, ya sea integral o basada en punto flotante. Como ejemplo, hay una
std::chrono::nanoseconds
unidad prefabricada que podría haber usado.Como otro ejemplo, quiero imprimir el número promedio de ciclos de reloj por iteración como un punto flotante, así que creo otra duración, basada en el doble, que tiene las mismas unidades que el tic del reloj (llamado
Cycle
en el código).El ciclo se cronometra con llamadas a
clock::now()
ambos lados. Si desea nombrar el tipo devuelto por esta función, es:(como se muestra claramente en el
x::clock
ejemplo, y también es cierto para los relojes suministrados por el sistema).Para obtener una duración en términos de tics de reloj de punto flotante, uno simplemente resta los dos puntos de tiempo, y para obtener el valor por iteración, divida esa duración por el número de iteraciones.
Puede obtener el recuento en cualquier duración utilizando la
count()
función miembro. Esto devuelve la representación interna. Finalmente, utilizostd::chrono::duration_cast
para convertir la duraciónCycle
a la duraciónpicoseconds
e imprimirla.Usar este código es simple:
Arriba realizo la prueba usando nuestro hecho en casa
x::clock
, y comparo esos resultados con el uso de dos de los relojes provistos por el sistema:std::chrono::high_resolution_clock
ystd::chrono::system_clock
. Para mí esto imprime:Esto muestra que cada uno de estos relojes tiene un período de tic diferente, ya que los tics por iteración son muy diferentes para cada reloj. Sin embargo, cuando se convierte a una unidad de tiempo conocida (por ejemplo, picosegundos), obtengo aproximadamente el mismo resultado para cada reloj (su millaje puede variar).
Tenga en cuenta que mi código está completamente libre de "constantes de conversión mágicas". De hecho, solo hay dos números mágicos en todo el ejemplo:
x::clock
.fuente
rdtsc
es probable que el reloj tenga conversiones inexactas a otras unidades. Es una buena idea configurar sus medidas para que pueda cambiar y comparar relojes fácilmente (como se muestra en esta respuesta).Con ese nivel de precisión, sería mejor razonar en el tic de la CPU en lugar de en la llamada del sistema como clock () . Y no olvide que si se tarda más de un nanosegundo en ejecutar una instrucción ... tener una precisión de nanosegundos es prácticamente imposible.
Aún así, algo así es un comienzo:
Aquí está el código real para recuperar el número de tics de reloj de la CPU de 80x86 pasados desde la última vez que se inició la CPU. Funcionará en Pentium y superiores (386/486 no es compatible). Este código es en realidad específico de MS Visual C ++, pero probablemente pueda ser fácilmente adaptado a cualquier otra cosa, siempre que sea compatible con el ensamblaje en línea.
Esta función también tiene la ventaja de ser extremadamente rápida: por lo general, no se necesitan más de 50 ciclos de CPU para ejecutarse.
Uso de las cifras de sincronización :
si necesita traducir los conteos del reloj en tiempo transcurrido real, divida los resultados por la velocidad del reloj de su chip. Recuerde que es probable que el GHz "nominal" sea ligeramente diferente de la velocidad real de su chip. Para comprobar la velocidad real de su chip, puede utilizar varias utilidades muy buenas o la llamada de Win32, QueryPerformanceFrequency ().
fuente
Para hacer esto correctamente, puede usar una de dos formas, ya sea con
RDTSC
o conclock_gettime()
. El segundo es aproximadamente 2 veces más rápido y tiene la ventaja de dar el tiempo absoluto correcto. Tenga en cuenta que paraRDTSC
que funcione correctamente debe usarlo como se indica (otros comentarios en esta página tienen errores y pueden producir valores de tiempo incorrectos en ciertos procesadores)y para clock_gettime: (elegí resolución de microsegundos arbitrariamente)
el tiempo y los valores producidos:
fuente
Estoy usando lo siguiente para obtener los resultados deseados:
fuente
Para C ++ 11 , aquí hay un contenedor simple:
O para C ++ 03 en * nix,
Ejemplo de uso:
De https://gist.github.com/gongzhitaao/7062087
fuente
En general, para medir el tiempo que se tarda en llamar a una función, conviene hacerlo muchas más veces que una sola vez. Si llama a su función solo una vez y tarda muy poco en ejecutarse, todavía tiene la sobrecarga de llamar a las funciones del temporizador y no sabe cuánto tiempo lleva.
Por ejemplo, si estima que su función puede tardar 800 ns en ejecutarse, llámela en un bucle diez millones de veces (lo que tardará unos 8 segundos). Divida el tiempo total por diez millones para obtener el tiempo por llamada.
fuente
Puede utilizar la siguiente función con gcc ejecutándose en procesadores x86:
con Digital Mars C ++:
que lee el temporizador de alto rendimiento en el chip. Utilizo esto cuando hago perfiles.
fuente
unsigned int
como tipo interno.Si necesita una precisión de menos de un segundo, debe utilizar extensiones específicas del sistema y deberá consultar la documentación del sistema operativo. POSIX admite hasta microsegundos con gettimeofday , pero nada más preciso ya que las computadoras no tenían frecuencias por encima de 1GHz.
Si está usando Boost, puede verificar boost :: posix_time .
fuente
Estoy usando el código de Borland, aquí está el código que ti_hund me da algunas veces un número negativo, pero el tiempo es bastante bueno.
fuente
Usando el método de Brock Adams, con una clase simple:
Ejemplo de uso:
Resultado:
prueba tomó: 0.0002 ms
Tiene una sobrecarga de llamadas a funciones, pero debería ser lo suficientemente rápido :)
fuente
Puede usar Embedded Profiler (gratuito para Windows y Linux) que tiene una interfaz para un temporizador multiplataforma (en un recuento de ciclos de procesador) y puede proporcionarle una cantidad de ciclos por segundo:
El recálculo del recuento de ciclos al tiempo es posiblemente una operación peligrosa con los procesadores modernos donde la frecuencia de la CPU se puede cambiar dinámicamente. Por lo tanto, para asegurarse de que los tiempos convertidos sean correctos, es necesario fijar la frecuencia del procesador antes de generar perfiles.
fuente
Si esto es para Linux, he estado usando la función "gettimeofday", que devuelve una estructura que da los segundos y microsegundos desde la Época. Luego puede usar timersub para restar los dos para obtener la diferencia en el tiempo y convertirlo a la precisión de tiempo que desee. Sin embargo, especifica nanosegundos y parece que la función clock_gettime () es lo que está buscando. Pone el tiempo en términos de segundos y nanosegundos en la estructura por la que pasa.
fuente
Qué piensas sobre eso:
fuente
Aquí hay un buen temporizador de impulso que funciona bien:
fuente
Copiar y pegar-estructura minimalista + uso perezoso
Si la idea es tener una estructura minimalista que pueda usar para pruebas rápidas, le sugiero que simplemente copie y pegue en cualquier lugar de su archivo C ++ justo después de la
#include
. Esta es la única instancia en la que sacrifico el formato de estilo Allman.Puede ajustar fácilmente la precisión en la primera línea de la estructura. Los valores posibles son:
nanoseconds
,microseconds
,milliseconds
,seconds
,minutes
, ohours
.Uso
Resultado de salida estándar
Si quieres resumen después de la ejecución
Si desea el informe después, porque, por ejemplo, su código intermedio también escribe en la salida estándar. Luego agregue la siguiente función a la estructura (justo antes de MeasureTime ()):
Entonces puedes usar:
Que enumerará todas las marcas como antes, pero luego después de que se ejecute el otro código. Tenga en cuenta que no debe usar ambos
m.s()
ym.t()
.fuente