2009-04-28 16 views
6

Estoy tratando de encontrar una manera de probar cuánto tiempo lleva ejecutar un bloque de código C++. Lo estoy usando para comparar el código con diferentes algoritmos y en diferentes idiomas, así que, idealmente, me gustaría un tiempo en segundos/milisegundos. En Java que estoy usando algo como esto:Probando el rendimiento de una aplicación C++

long startTime = System.currentTimeMillis(); 

function(); 

long stopTime = System.currentTimeMillis(); 
long elapsedTime = stopTime - startTime; 

¿Hay una buena manera de conseguir un tiempo preciso, al igual que en C++ (O debería utilizar algún otro medio de evaluación comparativa)?

+4

Rela ted pregunta: http://stackoverflow.com/questions/275004/c-timer-function-to-provide-time-in-nano-seconds –

+1

El tiempo depende de la plataforma. Debería enumerar qué plataforma (s) está utilizando. –

+0

Es frustrante que ninguna de las respuestas aquí tenga un componente estadístico. – uckelman

Respuesta

8

utilizar el mejor contador disponibles en su plataforma, caen de nuevo a tiempo() para la portabilidad. Estoy usando QueryPerformanceCounter, pero veo los comentarios en la otra respuesta.

consejo general:

El bucle interno debe ejecutar al menos aproximadamente 20 veces la resolución de su reloj, para hacer que el error de resolución < 5%. (por lo tanto, cuando use el tiempo() su ciclo interno debería ejecutarse al menos 20 segundos)

Repita estas mediciones para ver si son consistentes.

Utilizo un circuito externo adicional, ejecutando diez veces e ignorando la medición más rápida y la más lenta para calcular el promedio y la desviación. La desviación es útil cuando se comparan dos implementaciones: si tiene un algoritmo que toma 2.0ms +/-. 5, y el otro 2.2 +/- .5, la diferencia no es significativa para llamar a uno de ellos "más rápido". (máximo y mínimo aún se deben mostrar). Así que en mi humilde opinión una medida del rendimiento válida debe ser algo como esto:

10000 x 2.0 +/- 0.2 ms (min = 1.2, , max=12.6), 10 repetitions 

Si sabe lo que está haciendo, purgar el caché y el establecimiento de afinidad hilo puede hacer sus mediciones mucho más robusto.

Sin embargo, esto no es sin pifalls. Cuanto más "estable" es la medida, menos realista es también. Cualquier implementación variará fuertemente con el tiempo, dependiendo del estado de los datos y la caché de instrucciones. Soy flojo aquí, usando el valor máximo = para juzgar la penalización de la primera ejecución, esto puede no ser suficiente para algunos escenarios.

7

Ejecute la función miles de veces para obtener una medición precisa.

Una sola medición puede estar dominada por eventos del sistema operativo u otro ruido aleatorio.

2

Puede usar la función time() para obtener un temporizador con una resolución de un segundo. Si necesita más resolución, puede usar gettimeofday(). La resolución de eso depende de su sistema operativo y biblioteca de tiempo de ejecución.

5

En Windows, puede utilizar contadores de alto rendimiento para obtener resultados más precisos:

Puede utilizar la función de QueryPerformanceFrequency() para obtener el número de alta frecuencia de pulsaciones por seconde y el usuario del QueryPerformanceCounter() antes y después de la función que quiero tiempo

Por supuesto, este método no es portátil ...

+0

Tenga cuidado con los contadores de HF. Los sistemas multiprocesador a veces hacen su uso ... interesante. Funcionan con contadores específicos del procesador, por lo que si termina con su código en una CPU diferente, los contadores pueden estar apagados (dependiendo de su hardware exacto, por supuesto). –

+1

El ajuste de la afinidad de subprocesos a una sola CPU durante la duración de la prueba de referencia eliminará las distorsiones de tiempo relacionadas con SMP. También puede haber rampas de reloj debido a la administración de energía, que importaría si la CPU queda inactiva porque el código de referencia duerme o bloquea en E/S. Para los sistemas AMD, la instalación del controlador de procesador AMD mejorará considerablemente la sincronización de QPC(). Windows Vista y Windows 7 usan el temporizador HPET (si está disponible) en lugar del TSC, por lo que los problemas de TSC pueden desaparecer (cuando/si Windows XP desaparece). – bk1e

+0

Consulte http://support.microsoft.com/kb/895980 para obtener soluciones. – peterchen

5

¿Usted ha considerado realmente utilizando un generador de perfiles? Visual Studio Team System tiene uno integrado, pero hay otros disponibles como VTune y GlowCode.

Ver también What's the best free C++ profiler for Windows?

+0

Gah! ¿Tienen unos que no cuestan tanto? –

+1

Sí, mira más arriba. – rlbond

+4

Los perfiladores son buenos para responder a la pregunta "¿cuál es la parte más lenta de mi programa?" pero por lo general no es tan bueno respondiendo a la pregunta "¿Qué tan lento es mi programa?" precisamente. – bk1e

0

Usted puede simplemente utilizar time() dentro de su código de medir con la precisión de segundos. Los puntos de referencia detallados deberían tener muchas iteraciones para precisión, por lo que los segundos deberían tener un margen lo suficientemente grande. Si está utilizando Linux, puede utilizar la utilidad tiempo de lo previsto por la línea de comandos, así:

[[email protected]]$time ./loops.sh 

real 0m3.026s 
user 0m4.000s 
sys  0m0.020s 
0

en sistemas Unix (Linux, Mac, etc.) que puede utilizar time utilidad de este modo:

$ time ./my_app 
0

Si su función es muy rápida, una buena práctica es sincronizar la función en un bucle y luego restar el bucle por encima.

Algo como esto:

int i; 
int limit=1000000; 
int t0=getTime(); 
for(i=0; i < limit; ++i) 
    ; 
int t1=getTime(); 
int loopoverhead = t1-t0; 
t0=getTime(); 
for(i=0; i < limit; ++i) 
    function(); 
t1=getTime(); 
double tfunction = (1.0/limit)*((t1-t0)-loopoverhead); 
2

siempre uso boost::timer o boost::progress_timer.

psudo-código:

#include <boost/timer.hpp> 

boost::timer t; 

func1(); 
cout << "fun1: " << t.elapsed(); 

t.restart(); 
func2(); 
cout << "func2(): " << t.elapsed(); 
2

Si quieres que comprobar el rendimiento, se debe considerar la medición de tiempo utilizado procesador, no el tiempo real de que está tratando de medir ahora. De lo contrario, puede obtener tiempos bastante imprecisos si alguna otra aplicación que se ejecuta en segundo plano decide hacer algunos cálculos pesados ​​al mismo tiempo. Las funciones que desea serían GetProcessTimes en Windows y getrusage en Linux.

También debe considerar el uso de los perfiles, como otras personas sugirieron.

0

Ejecútelo 1000 veces como 100 iteraciones * 10 iteraciones, donde desenrollará el bucle interno para minimizar la sobrecarga. Luego los segundos se traducen en milisegundos.

Como han señalado otros, esta es una buena manera de medir cuánto tiempo lleva.

Sin embargo, si también desea reducir el tiempo, ese es un objetivo diferente y necesita una técnica diferente. My favorite is this.

3

¿Qué pasa con clock() y CLOCKS_PER_SEC? Son estándar C89.

Algo así como (mellado de MSDN):

long i = 6000000L; 
    clock_t start, finish; 
    double duration; 

    // Measure the duration of an event. 
    printf("Time to do %ld empty loops is ", i); 
    start = clock(); 
    while(i--) 
     ; 
    finish = clock(); 
    duration = (double)(finish - start)/CLOCKS_PER_SEC; 
    printf("%2.1f seconds\n", duration); 
0

su plataforma de despliegue puede tener un grave impacto en su precisión de reloj. Si está tomando muestras dentro de una Máquina Virtual, todas las apuestas están desactivadas. El reloj del sistema en una VM flota en relación con el reloj físico y tiene que rescindirse ocasionalmente.Es casi una certeza que esto va a suceder, sucederá, dada la naturaleza traviesa del Sr. Murphy en el universo de software

2

RESUMEN

He escrito un simple truco semántico para esto.

  • Fácil de usar
  • Código ve limpio.

MACRO

#include <time.h> 

#ifndef SYSOUT_F 
#define SYSOUT_F(f, ...)  _RPT1(0, f, __VA_ARGS__) // For Visual studio 
#endif 

#ifndef speedtest__    
#define speedtest__(data) for (long blockTime = NULL; (blockTime == NULL ? (blockTime = clock()) != NULL : false); SYSOUT_F(data "%.9fs", (double) (clock() - blockTime)/CLOCKS_PER_SEC)) 
#endif 

USO

speedtest__("Block Speed: ") 
{ 
    // The code goes here 
} 

OUTPUT

Block Speed: 0.127000000s 
Cuestiones relacionadas