Tengo que calcular el tiempo de ejecución de un fragmento de código C ++ en segundos. Debe estar funcionando en máquinas Windows o Unix.
Utilizo el siguiente código para hacer esto. (importar antes)
clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;
Sin embargo, para entradas pequeñas o declaraciones breves como a = a + 1, obtengo un resultado de "0 segundos". Creo que debe ser algo así como 0,0000001 segundos o algo así.
Recuerdo que System.nanoTime()
en Java funciona bastante bien en este caso. Sin embargo, no puedo obtener la misma funcionalidad exacta de la clock()
función de C ++.
tienes una solución?
c++
benchmarking
AhmetB - Google
fuente
fuente
Respuestas:
Puedes usar esta función que escribí. Usted llama
GetTimeMs64()
, y devuelve el número de milisegundos transcurridos desde la época de Unix usando el reloj del sistema, al igual quetime(NULL)
, excepto en milisegundos.Funciona tanto en Windows como en Linux; es seguro para subprocesos.
Tenga en cuenta que la granularidad es de 15 ms en Windows; en Linux depende de la implementación, pero también suele ser de 15 ms.
fuente
gettimeofday
puede dar un resultado no deseado si se cambia el reloj del sistema. Si esto fuera un problema para usted, es posible que desee mirar en suclock_gettime
lugar.GetTickCount
?gcc -std=c99
GetTickCount
es el tiempo transcurrido desde que se inició el sistema, mientras que mi función devuelve el tiempo desde la época de UNIX, lo que significa que puede usarlo para fechas y horas. Si solo está interesado en el tiempo transcurrido entre dos eventos, el mío sigue siendo una mejor opción porque es un int64; GetTickCount es un int32 y se desborda cada 50 días, lo que significa que puede obtener resultados extraños si los dos eventos que registró se encuentran entre el desbordamiento.Tengo otro ejemplo de trabajo que usa microsegundos (UNIX, POSIX, etc.).
Aquí está el archivo donde codificamos esto:
https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c
fuente
#include <sys/time.h>
al comienzo de su ejemplo.Aquí hay una solución simple en C ++ 11 que le brinda una resolución satisfactoria.
O en * nix, para c ++ 03
Aquí está el uso de ejemplo:
De https://gist.github.com/gongzhitaao/7062087
fuente
/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
Cuando
progress_timer
salga del alcance imprimirá el tiempo transcurrido desde su creación.ACTUALIZACIÓN : Aquí hay una versión que funciona sin Boost (probada en macOS / iOS):
fuente
Windows proporciona la función QueryPerformanceCounter () y Unix tiene gettimeofday () Ambas funciones pueden medir al menos 1 microsegundo de diferencia.
fuente
#ifdef
debe estar bien (y es a juzgar por la respuesta que ha aceptado), y luego no veo el problema:#ifdef WIN32 #include <windows.h> ... #else ... #endif
.En algunos programas que escribí usé RDTS para tal propósito. RDTSC no se trata de tiempo, sino de número de ciclos desde el inicio del procesador. Debe calibrarlo en su sistema para obtener un resultado en segundos, pero es realmente útil cuando desea evaluar el rendimiento, es incluso mejor usar el número de ciclos directamente sin intentar volver a cambiarlos a segundos.
(el enlace de arriba es a una página de Wikipedia en francés, pero tiene ejemplos de código C ++, la versión en inglés está aquí )
fuente
Sugiero utilizar las funciones de la biblioteca estándar para obtener información de tiempo del sistema.
Si desea una resolución más fina, realice más iteraciones de ejecución. En lugar de ejecutar el programa una vez y obtener muestras, ejecútelo 1000 veces o más.
fuente
Es mejor ejecutar el bucle interno varias veces con el tiempo de ejecución solo una vez y el promedio dividiendo las repeticiones del bucle interno que ejecutar todo (bucle + tiempo de rendimiento) varias veces y promedio. Esto reducirá la sobrecarga del código de sincronización de rendimiento frente a su sección perfilada real.
Envuelva sus llamadas de temporizador para el sistema apropiado. Para Windows, QueryPerformanceCounter es bastante rápido y "seguro" de usar.
También puede usar "rdtsc" en cualquier PC X86 moderna, pero puede haber problemas en algunas máquinas multinúcleo (el salto de núcleo puede cambiar el temporizador) o si tiene activado el paso de velocidad de algún tipo.
fuente
(solución específica de Windows) La forma actual (alrededor de 2017) de obtener tiempos precisos en Windows es utilizar "QueryPerformanceCounter". Este enfoque tiene la ventaja de proporcionar resultados muy precisos y es recomendado por MS. Simplemente coloque el blob de código en una nueva aplicación de consola para obtener una muestra funcional. Aquí hay una larga discusión: Adquirir marcas de tiempo de alta resolución
fuente
Una solución completa e infalible para la programación de subprocesos, que debería producir exactamente los mismos tiempos para cada prueba, es compilar su programa para que sea independiente del sistema operativo y arrancar su computadora para ejecutar el programa en un entorno sin sistema operativo. Sin embargo, esto es poco práctico y, en el mejor de los casos, sería difícil.
Un buen sustituto del sistema operativo libre es simplemente establecer la afinidad del hilo actual en 1 núcleo y la prioridad en la más alta. Esta alternativa debería proporcionar resultados suficientemente consistentes.
También debe desactivar las optimizaciones que interferirían con la depuración, lo que para g ++ o gcc significa agregar
-Og
a la línea de comandos , para evitar que el código que se está probando se optimice. los-O0
bandera no debe usarse porque introduce una sobrecarga adicional innecesaria que se incluiría en los resultados de temporización, sesgando así la velocidad temporizada del código.Por el contrario, asumiendo que usa
-Ofast
(o, al menos,-O3
) en la compilación de producción final e ignorando el problema de la eliminación del código "muerto",-Og
realiza muy pocas optimizaciones en comparación con-Ofast
; por lo tanto,-Og
puede tergiversar la velocidad real del código en el producto final.Además, todas las pruebas de velocidad (hasta cierto punto) son falsas: en el producto de producción final compilado
-Ofast
, cada fragmento / sección / función de código no está aislado; más bien, cada fragmento de código fluye continuamente hacia el siguiente, lo que permite al compilador unir, fusionar y optimizar piezas de código de todas partes.Al mismo tiempo, si está comparando un fragmento de código que hace un uso intensivo
realloc()
, entonces el fragmento de código podría ejecutarse más lento en un producto de producción con una fragmentación de memoria suficientemente alta. Por lo tanto, la expresión "el todo es más que la suma de sus partes" se aplica a esta situación porque el código en la compilación de producción final puede ejecutarse notablemente más rápido o más lento que el fragmento individual que está probando.Una solución parcial que puede reducir la incongruencia es el uso
-Ofast
de pruebas de velocidad CON la adición deasm volatile("" :: "r"(var))
las variables involucradas en la prueba para evitar la eliminación de códigos muertos / bucles.A continuación, se muestra un ejemplo de cómo comparar funciones de raíz cuadrada en una computadora con Windows.
Además, crédito a Mike Jarvis por su temporizador.
Tenga en cuenta (esto es muy importante) que si va a ejecutar fragmentos de código más grandes, entonces realmente debe reducir el número de iteraciones para evitar que su computadora se congele.
fuente
-O0
código de evaluación comparativa es una gran pérdida de tiempo porque la sobrecarga en-O0
lugar de una normal-O2
o-O3 -march=native
varía enormemente según el código y la carga de trabajo. por ejemplo, vars tmp con nombre adicional cuestan tiempo en-O0
. Hay otras formas de evitar que las cosas se optimicen, como ocultar cosas del optimizador convolatile
funciones no en línea o declaraciones asm en línea vacías.-O0
ni siquiera está cerca de ser utilizable porque el código tiene diferentes cuellos de botella en-O0
, no lo mismo pero peor.-Og
todavía no es muy realista, dependiendo del código. Al menos-O2
, preferiblemente-O3
es más realista. Utiliceasm volatile("" ::: "+r"(var))
o algo para hacer que el compilador materialice un valor en un registro y anule la propagación constante a través de él.-O3
y el fragmento de código conasm volatile("" ::: "+r"(var))
.asm volatile("" ::: "+r"( i ));
parece innecesario. En código optimizado, no hay razón para forzar al compilador a materializarsei
tan bien comoi<<7
dentro del ciclo. Estás impidiendo que se optimice entmp -= 128
lugar de cambiar cada vez. Sin embargo, usar el resultado de una llamada de función es bueno si no esvoid
. Al igualint result = (*function_to_do)( i << 7 );
. Podría utilizar unaasm
declaración sobre ese resultado.function_to_do
para quefunction_to_do
pueda insertarse sin ser eliminado. Por favor, avíseme si tiene más sugerencias.Para los casos en los que desea cronometrar el mismo tramo de código cada vez que se ejecuta (por ejemplo, para el código de creación de perfiles que cree que podría ser un cuello de botella), aquí hay un envoltorio (una pequeña modificación a) la función de Andreas Bonini que encuentro útil:
fuente
solo una clase simple que compara el bloque de código:
fuente
boost :: timer probablemente le dará tanta precisión como necesite. No es lo suficientemente preciso como para decirle cuánto tiempo
a = a+1;
tomará, pero ¿por qué razón tendría que cronometrar algo que demora un par de nanosegundos?fuente
clock()
función del encabezado estándar de C ++.Creé una lambda que llama a su función llamada N veces y le devuelve el promedio.
Puede encontrar el encabezado de c ++ 11 aquí .
fuente
Creé una utilidad simple para medir el rendimiento de bloques de código, utilizando el reloj high_resolution_clock de la biblioteca chrono: https://github.com/nfergu/codetimer .
Los tiempos se pueden registrar en diferentes claves y se puede mostrar una vista agregada de los tiempos para cada tecla.
El uso es el siguiente:
fuente
También puede mirar en
[cxx-rtimers][1]
GitHub, que proporciona algunas rutinas solo de encabezado para recopilar estadísticas sobre el tiempo de ejecución de cualquier bloque de código donde puede crear una variable local. Esos temporizadores tienen versiones que usan std :: chrono en C ++ 11, o temporizadores de la biblioteca Boost o funciones de temporizador POSIX estándar. Estos temporizadores informarán la duración media, máxima y mínima empleada en una función, así como el número de veces que se llama. Se pueden utilizar de la siguiente manera:fuente
Así es como lo hago, no hay mucho código, es fácil de entender, se adapta a mis necesidades:
Uso:
fuente
fuente