c++ c linux time measurement

measure time c++



Mide fácilmente el tiempo transcurrido (22)

C ++ std :: chrono tiene un claro beneficio de ser multiplataforma. Sin embargo, también introduce una sobrecarga significativa en comparación con POSIX clock_gettime (). En mi caja de Linux, todos los sabores de std::chrono::xxx_clock::now() funcionan aproximadamente de la misma manera:

std::chrono::system_clock::now() std::chrono::steady_clock::now() std::chrono::high_resolution_clock::now()

Aunque POSIX clock_gettime(CLOCK_MONOTONIC, &time) debería ser el mismo que steady_clock::now() pero es más de 3 veces más rápido!

Aquí está mi prueba, para la integridad.

#include <stdio.h> #include <chrono> #include <ctime> void print_timediff(const char* prefix, const struct timespec& start, const struct timespec& end) { double milliseconds = (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3; printf("%s: %lf milliseconds/n", prefix, milliseconds); } int main() { int i, n = 1000000; struct timespec start, end; // Test stopwatch clock_gettime(CLOCK_MONOTONIC, &start); for (i = 0; i < n; ++i) { struct timespec dummy; clock_gettime(CLOCK_MONOTONIC, &dummy); } clock_gettime(CLOCK_MONOTONIC, &end); print_timediff("clock_gettime", start, end); // Test chrono system_clock clock_gettime(CLOCK_MONOTONIC, &start); for (i = 0; i < n; ++i) auto dummy = std::chrono::system_clock::now(); clock_gettime(CLOCK_MONOTONIC, &end); print_timediff("chrono::system_clock::now", start, end); // Test chrono steady_clock clock_gettime(CLOCK_MONOTONIC, &start); for (i = 0; i < n; ++i) auto dummy = std::chrono::steady_clock::now(); clock_gettime(CLOCK_MONOTONIC, &end); print_timediff("chrono::steady_clock::now", start, end); // Test chrono high_resolution_clock clock_gettime(CLOCK_MONOTONIC, &start); for (i = 0; i < n; ++i) auto dummy = std::chrono::high_resolution_clock::now(); clock_gettime(CLOCK_MONOTONIC, &end); print_timediff("chrono::high_resolution_clock::now", start, end); return 0; }

Y esta es la salida que obtengo cuando se compila con gcc7.2 -O3:

clock_gettime: 24.484926 milliseconds chrono::system_clock::now: 85.142108 milliseconds chrono::steady_clock::now: 87.295347 milliseconds chrono::high_resolution_clock::now: 84.437838 milliseconds

Estoy tratando de usar el time() para medir varios puntos de mi programa.

Lo que no entiendo es por qué los valores del antes y el después son los mismos. Entiendo que esta no es la mejor manera de perfilar mi programa, solo quiero ver cuánto tiempo toma algo.

printf("**MyProgram::before time= %ld/n", time(NULL)); doSomthing(); doSomthingLong(); printf("**MyProgram::after time= %ld/n", time(NULL));

Yo he tratado:

struct timeval diff, startTV, endTV; gettimeofday(&startTV, NULL); doSomething(); doSomethingLong(); gettimeofday(&endTV, NULL); timersub(&endTV, &startTV, &diff); printf("**time taken = %ld %ld/n", diff.tv_sec, diff.tv_usec);

¿Cómo leo un resultado de **time taken = 0 26339 ? ¿Eso significa 26,339 nanosegundos = 26.3 ms?

¿Qué pasa con **time taken = 4 45025 , significa eso 4 segundos y 25 ms?


Como otros ya han señalado, la función time () en la biblioteca estándar de C no tiene una resolución mejor que un segundo. La única función C completamente portátil que puede proporcionar una mejor resolución parece ser clock (), pero que mide el tiempo del procesador en lugar del tiempo de reloj de pared. Si uno se contenta con limitarse a las plataformas POSIX (por ejemplo, Linux), entonces la función clock_gettime () es una buena opción.

Desde C ++ 11, existen muchas mejores facilidades de temporización disponibles que ofrecen una mejor resolución en una forma que debería ser muy portátil entre diferentes compiladores y sistemas operativos. De manera similar, la biblioteca boost :: datetime proporciona buenas clases de tiempo de alta resolución que deberían ser altamente portátiles.

Un desafío en el uso de cualquiera de estas facilidades es el tiempo de retraso introducido al consultar el reloj del sistema. Al experimentar con clock_gettime (), boost::datetime y std :: chrono, este retraso puede ser fácilmente una cuestión de microsegundos. Por lo tanto, al medir la duración de cualquier parte de su código, debe permitir que exista un error de medición de alrededor de este tamaño, o intentar corregir ese error cero de alguna manera. Idealmente, es posible que desee recopilar varias mediciones del tiempo tomado por su función y calcular el promedio, o el tiempo máximo / mínimo tomado en varias ejecuciones.

Para ayudar con todos estos problemas de portabilidad y recopilación de estadísticas, he estado desarrollando la biblioteca cxx-rtimers disponible en Github que intenta proporcionar una API simple para bloques de tiempo de código C ++, calcular errores cero e informar estadísticas de múltiples temporizadores integrados en su codigo Si tiene un compilador de C ++ 11, simplemente #include <rtimers/cxx11.hpp> , y use algo como:

void expensiveFunction() { static rtimers::cxx11::DefaultTimer timer("expensiveFunc"); auto scopedStartStop = timer.scopedStart(); // Do something costly... }

Al salir del programa, obtendrás un resumen de las estadísticas de tiempo escritas en std :: cerr como:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

que muestra el tiempo medio, su desviación estándar, los límites superior e inferior y el número de veces que se llamó a esta función.

Si desea usar funciones de tiempo específicas de Linux, puede #include <rtimers/posix.hpp> , o si tiene las bibliotecas Boost pero un compilador de C ++ más antiguo, puede #include <rtimers/boost.hpp> . También hay versiones de estas clases de temporizador que pueden recopilar información estadística de tiempo a través de múltiples hilos. También hay métodos que le permiten estimar el error cero asociado con dos consultas inmediatamente consecutivas del reloj del sistema.


Como puedo ver en tu pregunta, parece que quieres saber el tiempo transcurrido después de la ejecución de algún fragmento de código. Supongo que estaría cómodo para ver los resultados en segundo (s). Si es así, intente usar la función difftime() como se muestra a continuación. Espero que esto resuelva tu problema.

#include <time.h> #include <stdio.h> time_t start,end; time (&start); . . . <your code> . . . time (&end); double dif = difftime (end,start); printf ("Elasped time is %.2lf seconds.", dif );


En Linux, clock_gettime () es una de las buenas opciones. Debe enlazar la biblioteca en tiempo real (-lrt).

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #define BILLION 1000000000L; int main( int argc, char **argv ) { struct timespec start, stop; double accum; if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) { perror( "clock gettime" ); exit( EXIT_FAILURE ); } system( argv[1] ); if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) { perror( "clock gettime" ); exit( EXIT_FAILURE ); } accum = ( stop.tv_sec - start.tv_sec ) + ( stop.tv_nsec - start.tv_nsec ) / BILLION; printf( "%lf/n", accum ); return( EXIT_SUCCESS ); }


En respuesta a las tres preguntas específicas de OP .

"Lo que no entiendo es por qué los valores del antes y el después son los mismos? "

La primera pregunta y el código de muestra muestran que el time() tiene una resolución de 1 segundo, por lo que la respuesta debe ser que las dos funciones se ejecutan en menos de 1 segundo. Pero ocasionalmente informará (aparentemente de manera ilógica) 1 segundo si las dos marcas del temporizador se ubican a horcajadas en un límite de un segundo.

El siguiente ejemplo usa gettimeofday() que llena esta estructura

struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };

y la segunda pregunta pregunta: "¿Cómo leo un resultado de **time taken = 0 26339 ? ¿ **time taken = 0 26339 significa 26,339 nanosegundos = 26.3 mseg?"

Mi segunda respuesta es que el tiempo empleado es de 0 segundos y 26339 microsegundos, es decir, 0.026339 segundos, lo que confirma el primer ejemplo de ejecución en menos de 1 segundo.

La tercera pregunta pregunta: "¿Qué pasa con el **time taken = 4 45025 ¿Significa eso 4 segundos y 25 ms?"

Mi tercera respuesta es que el tiempo tomado es de 4 segundos y 45025 microsegundos, es decir, 4.045025 segundos, lo que muestra que OP ha alterado las tareas realizadas por las dos funciones que previamente cronometró.


Internamente, la función accederá al reloj del sistema, por lo que devuelve valores diferentes cada vez que lo llama. En general, con lenguajes no funcionales, puede haber muchos efectos secundarios y estados ocultos en funciones que no se pueden ver simplemente mirando el nombre y los argumentos de la función.


La función de tiempo (NULL) devolverá el número de segundos transcurridos desde el 01/01/1970 a las 00:00. Y porque, esa función se llama en un momento diferente en su programa, siempre será diferente el tiempo en C ++


La llamada a la función time(NULL) devolverá el número de segundos transcurridos desde epoc: 1 de enero de 1970. Tal vez lo que quieres hacer es tomar la diferencia entre dos marcas de tiempo:

size_t start = time(NULL); doSomthing(); doSomthingLong(); printf ("**MyProgram::time elapsed= %lds/n", time(NULL) - start);


La razón por la que ambos valores son iguales es porque su procedimiento largo no toma tanto tiempo: menos de un segundo. Puede intentar simplemente agregar un bucle largo (para (int i = 0; i <100000000; i ++);) al final de la función para asegurarse de que este es el problema, luego podemos continuar desde allí ...

En caso de que lo anterior resulte cierto, deberá buscar una función del sistema diferente (entiendo que trabaja en Linux, por lo que no puedo ayudarlo con el nombre de la función) para medir el tiempo con mayor precisión. Estoy seguro de que hay una función similar a GetTickCount () en Linux, solo necesitas encontrarla.


Los valores impresos por su segundo programa son segundos y microsegundos.

0 26339 = 0.026''339 s = 26339 µs 4 45025 = 4.045''025 s = 4045025 µs


Por lo que se ve, tv_sec almacena los segundos transcurridos, mientras que tv_usec almacena los microsegundos transcurridos por separado. Y no son las conversiones de los demás. Por lo tanto, deben cambiarse a la unidad adecuada y agregarse para obtener el tiempo total transcurrido.

struct timeval startTV, endTV; gettimeofday(&startTV, NULL); doSomething(); doSomethingLong(); gettimeofday(&endTV, NULL); printf("**time taken in microseconds = %ld/n", (endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec)) );


Puede abstraer el mecanismo de medición de tiempo y hacer que el tiempo de ejecución de cada ordenador sea medido con un código extra mínimo , solo con una estructura de temporizador. Además, en el momento de la compilación puede parametrizar el tipo de tiempo (milisegundos, nanosegundos, etc.).

Gracias a la revisión de Loki Astari y la sugerencia de usar varias plantillas. This es la razón por la llamada a la función reenviada.

#include <iostream> #include <chrono> template<typename TimeT = std::chrono::milliseconds> struct measure { template<typename F, typename ...Args> static typename TimeT::rep execution(F&& func, Args&&... args) { auto start = std::chrono::steady_clock::now(); std::forward<decltype(func)>(func)(std::forward<Args>(args)...); auto duration = std::chrono::duration_cast< TimeT> (std::chrono::steady_clock::now() - start); return duration.count(); } }; int main() { std::cout << measure<>::execution(functor(dummy)) << std::endl; }

Demo

Según el comentario de Howard Hinnant , es mejor no escapar del sistema crono hasta que tengamos que hacerlo. Por lo tanto, la clase anterior podría dar al usuario la opción de count manualmente al proporcionar un método estático adicional (que se muestra en C ++ 14)

template<typename F, typename ...Args> static auto duration(F&& func, Args&&... args) { auto start = std::chrono::steady_clock::now(); std::forward<decltype(func)>(func)(std::forward<Args>(args)...); return std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now()-start); } // call .count() manually later when needed (eg IO) auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2.0;

y ser mas util para clientes que

"quiero postprocesar un montón de duraciones antes de la E / S (por ejemplo, el promedio)"

El código completo se puede encontrar aquí . here se registra mi intento de construir una herramienta de evaluación comparativa basada en el crono.

Si está disponible std::invoke C ++ 17, la invocación de la invocable en execution podría hacer así:

invoke(forward<decltype(func)>(func), forward<Args>(args)...);

para proporcionar callables que son punteros a las funciones miembro.


Puede utilizar la biblioteca SFML , que es una biblioteca multimedia simple y rápida. Incluye muchas clases útiles y bien definidas como Reloj, Socket, Sonido, Gráficos, etc. Es muy fácil de usar y muy recomendable.

Este es un ejemplo para esta pregunta.

sf::Clock clock; ... Time time1 = clock.getElapsedTime(); ... Time time2 = clock.restart();


Son los mismos porque su función doSomething ocurre más rápido que la granularidad del temporizador. Tratar:

printf ("**MyProgram::before time= %ld/n", time(NULL)); for(i = 0; i < 1000; ++i) { doSomthing(); doSomthingLong(); } printf ("**MyProgram::after time= %ld/n", time(NULL));


Usualmente uso lo siguiente:

#include <chrono> #include <type_traits> using perf_clock = std::conditional< std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock >::type; using floating_seconds = std::chrono::duration<double>; template<class F, class... Args> floating_seconds run_test(Func&& func, Args&&... args) { const auto t0 = perf_clock::now(); std::forward<Func>(func)(std::forward<Args>(args)...); return floating_seconds(perf_clock::now() - t0); }

Es lo mismo que propuso @ nikos-athanasiou, excepto que evito usar un reloj no fijo y uso el número de segundos flotantes como una duración.


time(NULL) devuelve el número de segundos transcurridos desde el 01/01/1970 a las 00:00 ( la época ). Entonces, la diferencia entre los dos valores es la cantidad de segundos que tomó el procesamiento.

int t0 = time(NULL); doSomthing(); doSomthingLong(); int t1 = time(NULL); printf ("time = %d secs/n", t1 - t0);

Puede obtener mejores resultados con getttimeofday() , que devuelve la hora actual en segundos, como lo hace time() y también en microsegundos.


Sólo Windows: (la etiqueta de Linux se agregó después de que publiqué esta respuesta)

Puede usar GetTickCount() para obtener la cantidad de milisegundos que han transcurrido desde que se inició el sistema.

long int before = GetTickCount(); // Perform time-consuming operation long int after = GetTickCount();


#include <ctime> void f() { using namespace std; clock_t begin = clock(); code_to_time(); clock_t end = clock(); double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; }

La función time() solo es precisa en un segundo, pero hay CLOCKS_PER_SEC "relojes" en un segundo. Esta es una medida fácil y portátil, aunque está simplificada en exceso.


#include <ctime> #include <cstdio> #include <iostream> #include <chrono> #include <sys/time.h> using namespace std; using namespace std::chrono; void f1() { high_resolution_clock::time_point t1 = high_resolution_clock::now(); high_resolution_clock::time_point t2 = high_resolution_clock::now(); double dif = duration_cast<nanoseconds>( t2 - t1 ).count(); printf ("Elasped time is %lf nanoseconds./n", dif ); } void f2() { timespec ts1,ts2; clock_gettime(CLOCK_REALTIME, &ts1); clock_gettime(CLOCK_REALTIME, &ts2); double dif = double( ts2.tv_nsec - ts1.tv_nsec ); printf ("Elasped time is %lf nanoseconds./n", dif ); } void f3() { struct timeval t1,t0; gettimeofday(&t0, 0); gettimeofday(&t1, 0); double dif = double( (t1.tv_usec-t0.tv_usec)*1000); printf ("Elasped time is %lf nanoseconds./n", dif ); } void f4() { high_resolution_clock::time_point t1 , t2; double diff = 0; t1 = high_resolution_clock::now() ; for(int i = 1; i <= 10 ; i++) { t2 = high_resolution_clock::now() ; diff+= duration_cast<nanoseconds>( t2 - t1 ).count(); t1 = t2; } printf ("high_resolution_clock:: Elasped time is %lf nanoseconds./n", diff/10 ); } void f5() { timespec ts1,ts2; double diff = 0; clock_gettime(CLOCK_REALTIME, &ts1); for(int i = 1; i <= 10 ; i++) { clock_gettime(CLOCK_REALTIME, &ts2); diff+= double( ts2.tv_nsec - ts1.tv_nsec ); ts1 = ts2; } printf ("clock_gettime:: Elasped time is %lf nanoseconds./n", diff/10 ); } void f6() { struct timeval t1,t2; double diff = 0; gettimeofday(&t1, 0); for(int i = 1; i <= 10 ; i++) { gettimeofday(&t2, 0); diff+= double( (t2.tv_usec-t1.tv_usec)*1000); t1 = t2; } printf ("gettimeofday:: Elasped time is %lf nanoseconds./n", diff/10 ); } int main() { // f1(); // f2(); // f3(); f6(); f4(); f5(); return 0; }


#include<time.h> // for clock #include<math.h> // for fmod #include<cstdlib> //for system #include <stdio.h> //for delay using namespace std; int main() { clock_t t1,t2; t1=clock(); // first time capture // Now your time spanning loop or code goes here // i am first trying to display time elapsed every time loop runs int ddays=0; // d prefix is just to say that this variable will be used for display int dhh=0; int dmm=0; int dss=0; int loopcount = 1000 ; // just for demo your loop will be different of course for(float count=1;count<loopcount;count++) { t2=clock(); // we get the time now float difference= (((float)t2)-((float)t1)); // gives the time elapsed since t1 in milliseconds // now get the time elapsed in seconds float seconds = difference/1000; // float value of seconds if (seconds<(60*60*24)) // a day is not over { dss = fmod(seconds,60); // the remainder is seconds to be displayed float minutes= seconds/60; // the total minutes in float dmm= fmod(minutes,60); // the remainder are minutes to be displayed float hours= minutes/60; // the total hours in float dhh= hours; // the hours to be displayed ddays=0; } else // we have reached the counting of days { float days = seconds/(24*60*60); ddays = (int)(days); float minutes= seconds/60; // the total minutes in float dmm= fmod(minutes,60); // the rmainder are minutes to be displayed float hours= minutes/60; // the total hours in float dhh= fmod (hours,24); // the hours to be displayed } cout<<"Count Is : "<<count<<"Time Elapsed : "<<ddays<<" Days "<<dhh<<" hrs "<<dmm<<" mins "<<dss<<" secs"; // the actual working code here,I have just put a delay function delay(1000); system("cls"); } // end for loop }// end of main


//***C++11 Style:*** std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now(); std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() <<std::endl; std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() <<std::endl;


struct profiler { std::string name; std::chrono::high_resolution_clock::time_point p; profiler(std::string const &n) : name(n), p(std::chrono::high_resolution_clock::now()) { } ~profiler() { using dura = std::chrono::duration<double>; auto d = std::chrono::high_resolution_clock::now() - p; std::cout << name << ": " << std::chrono::duration_cast<dura>(d).count() << std::endl; } }; #define PROFILE_BLOCK(pbn) profiler _pfinstance(pbn)

El uso es a continuación ::

{ PROFILE_BLOCK("Some time"); // your code or function }

Esto es similar a RAII en alcance

NOTA: esto no es mío, pero pensé que era relevante aquí