temporizador - tiempo de ejecucion en nanosegundos c++
Cómo calcular el tiempo de ejecución de un fragmento de código en C++ (16)
(solución específica de Windows) La forma actual (circa 2017) de obtener sincronizaciones precisas en Windows es usar "QueryPerformanceCounter". Este enfoque tiene la ventaja de dar resultados muy precisos y es recomendado por MS. Solo despliega el blob de código en una nueva aplicación de consola para obtener una muestra de trabajo. Aquí hay una larga discusión: Adquirir sellos de tiempo de alta resolución
#include <iostream>
#include <tchar.h>
#include <windows.h>
int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };
// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;
QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);
for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
// code to be timed
std::cout << "cur_tick = " << iter << "/n";
QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
totalTicks += endTick - startTick; // accumulate time taken
}
// convert to elapsed microseconds
__int64 totalMicroSeconds = (totalTicks * 1000000ull)/ ticksPerSecond;
__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;
std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us/n";
return 0;
}
Tengo que calcular el tiempo de ejecución de un fragmento de código de C ++ en segundos. Debe estar funcionando en máquinas Windows o Unix.
Uso el código del siguiente código para hacer esto. (importación 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 cortas 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 función clock()
de C ++.
tienes una solución?
Aquí hay una solución simple en C ++ 11 que le da una resolución satisfactoria.
#include <iostream>
#include <chrono>
class Timer
{
public:
Timer() : beg_(clock_::now()) {}
void reset() { beg_ = clock_::now(); }
double elapsed() const {
return std::chrono::duration_cast<second_>
(clock_::now() - beg_).count(); }
private:
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<double, std::ratio<1> > second_;
std::chrono::time_point<clock_> beg_;
};
O en * nix, para c ++ 03
#include <iostream>
#include <ctime>
class Timer
{
public:
Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }
double elapsed() {
clock_gettime(CLOCK_REALTIME, &end_);
return end_.tv_sec - beg_.tv_sec +
(end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
}
void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }
private:
timespec beg_, end_;
};
Aquí está el uso de ejemplo:
int main()
{
Timer tmr;
double t = tmr.elapsed();
std::cout << t << std::endl;
tmr.reset();
t = tmr.elapsed();
std::cout << t << std::endl;
return 0;
}
Creé un lambda que te llama a la función llamada N veces y te devuelve el promedio.
double c = BENCHMARK_CNT(25, fillVectorDeque(variable));
Puede encontrar el encabezado c ++ 11 here .
Creé una utilidad simple para medir el rendimiento de bloques de código, usando high_resolution_clock de la biblioteca chrono: https://github.com/nfergu/codetimer .
Los tiempos se pueden registrar contra diferentes claves, y se puede visualizar una vista agregada de los tiempos para cada tecla.
El uso es el siguiente:
#include <chrono>
#include <iostream>
#include "codetimer.h"
int main () {
auto start = std::chrono::high_resolution_clock::now();
// some code here
CodeTimer::record("mykey", start);
CodeTimer::printStats();
return 0;
}
En algunos programas que escribí, utilicé RDTS para tal fin. RDTSC no se trata de tiempo, sino de la cantidad de ciclos desde el inicio del procesador. Tienes que calibrarlo en tu sistema para obtener un resultado en segundo lugar, pero es realmente útil cuando quieres evaluar el rendimiento, incluso es mejor usar la cantidad de ciclos directamente sin intentar cambiarlos a segundos.
(el enlace de arriba está en una página wikipedia francesa, pero tiene ejemplos de código C ++, la versión en inglés está here )
Es mejor ejecutar el ciclo interno varias veces con el tiempo de rendimiento solo una vez y el promedio al dividir las repeticiones de bucle interno que ejecutar todo el proceso (ciclo + tiempo de rendimiento) varias veces y promedio. Esto reducirá la sobrecarga del código de tiempo de rendimiento frente a su sección de perfil 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 cronómetro) o si tiene un paso de velocidad de algún tipo activado.
Para los casos en los que desee sincronizar el mismo tramo de código cada vez que se ejecute (por ejemplo, para crear un código de perfil que cree que puede ser un cuello de botella), aquí hay un resumen (una ligera modificación) de la función de Andreas Bonini que considero útil:
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif
/*
* A simple timer class to see how long a piece of code takes.
* Usage:
*
* {
* static Timer timer("name");
*
* ...
*
* timer.start()
* [ The code you want timed ]
* timer.stop()
*
* ...
* }
*
* At the end of execution, you will get output:
*
* Time for name: XXX seconds
*/
class Timer
{
public:
Timer(std::string name, bool start_running=false) :
_name(name), _accum(0), _running(false)
{
if (start_running) start();
}
~Timer() { stop(); report(); }
void start() {
if (!_running) {
_start_time = GetTimeMicroseconds();
_running = true;
}
}
void stop() {
if (_running) {
unsigned long long stop_time = GetTimeMicroseconds();
_accum += stop_time - _start_time;
_running = false;
}
}
void report() {
std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds/n";
}
private:
// cf. http://.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
unsigned long long GetTimeMicroseconds()
{
#ifdef _WIN32
/* Windows */
FILETIME ft;
LARGE_INTEGER li;
/* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
* * to a LARGE_INTEGER structure. */
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
unsigned long long ret = li.QuadPart;
ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
/* Linux */
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long long ret = tv.tv_usec;
/* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
ret += (tv.tv_sec * 1000000);
#endif
return ret;
}
std::string _name;
long long _accum;
unsigned long long _start_time;
bool _running;
};
Puedes usar esta función que escribí. Llama a GetTimeMs64()
y devuelve el número de milisegundos transcurridos desde la época Unix utilizando el reloj del sistema: el time(NULL)
justo time(NULL)
, excepto en milisegundos.
Funciona tanto en Windows como en Linux; es seguro para hilos.
Tenga en cuenta que la granularidad es de 15 ms en Windows; en Linux depende de la implementación, pero generalmente también 15 ms.
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif
/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;
/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
* windows and linux. */
uint64 GetTimeMs64()
{
#ifdef _WIN32
/* Windows */
FILETIME ft;
LARGE_INTEGER li;
/* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
* to a LARGE_INTEGER structure. */
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
uint64 ret = li.QuadPart;
ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */
return ret;
#else
/* Linux */
struct timeval tv;
gettimeofday(&tv, NULL);
uint64 ret = tv.tv_usec;
/* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
ret /= 1000;
/* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
ret += (tv.tv_sec * 1000);
return ret;
#endif
}
Si desea obtener buenos resultados exactos, entonces como se indicó anteriormente, su tiempo de ejecución depende de la programación del hilo. Una solución completa e inquebrantable para esto, que debe producir exactamente los mismos tiempos para cada prueba, es compilar su programa para que sea independiente del sistema operativo y reinicie su computadora para ejecutar el programa en un entorno libre de sistema operativo. Sin embargo, un buen sustituto para esto es simplemente establecer la afinidad del hilo actual en 1 núcleo y la prioridad en el más alto. El resultado de hacer esto es resultados muy consistentes. Y, una cosa más es que debe desactivar las optimizaciones, lo que para g ++ o gcc significa agregar -O0 a la línea de comando, para evitar que su código que se está probando se optimice. Aquí hay un ejemplo de cómo estoy marcando las funciones de raíz cuadrada en una computadora con Windows.
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
class Timer {
public:
Timer() : beg_(clock_::now()) {}
void reset() { beg_ = clock_::now(); }
double elapsed() const {
return std::chrono::duration_cast<second_>
(clock_::now() - beg_).count(); }
private:
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<double, std::ratio<1> > second_;
std::chrono::time_point<clock_> beg_;
};
unsigned int guess_sqrt32(register unsigned int n) {
register unsigned int g = 0x8000;
if(g*g > n) {
g ^= 0x8000;
}
g |= 0x4000;
if(g*g > n) {
g ^= 0x4000;
}
g |= 0x2000;
if(g*g > n) {
g ^= 0x2000;
}
g |= 0x1000;
if(g*g > n) {
g ^= 0x1000;
}
g |= 0x0800;
if(g*g > n) {
g ^= 0x0800;
}
g |= 0x0400;
if(g*g > n) {
g ^= 0x0400;
}
g |= 0x0200;
if(g*g > n) {
g ^= 0x0200;
}
g |= 0x0100;
if(g*g > n) {
g ^= 0x0100;
}
g |= 0x0080;
if(g*g > n) {
g ^= 0x0080;
}
g |= 0x0040;
if(g*g > n) {
g ^= 0x0040;
}
g |= 0x0020;
if(g*g > n) {
g ^= 0x0020;
}
g |= 0x0010;
if(g*g > n) {
g ^= 0x0010;
}
g |= 0x0008;
if(g*g > n) {
g ^= 0x0008;
}
g |= 0x0004;
if(g*g > n) {
g ^= 0x0004;
}
g |= 0x0002;
if(g*g > n) {
g ^= 0x0002;
}
g |= 0x0001;
if(g*g > n) {
g ^= 0x0001;
}
return g;
}
unsigned int empty_function( unsigned int _input ) {
return _input;
}
unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;
template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
register unsigned int i=benchmark_repetitions;
register unsigned long long start=0;
my_time.reset();
start=__rdtsc();
while ( i-- ) {
(*function_to_do)( i << 7 );
}
if ( function_name == nullptr ) {
empty_ticks = (__rdtsc()-start);
empty_seconds = my_time.elapsed();
std::cout<< "Empty:/n" << empty_ticks
<< " ticks/n" << benchmark_repetitions << " repetitions/n"
<< std::setprecision(15) << empty_seconds
<< " seconds/n/n";
} else {
std::cout<< function_name<<":/n" << (__rdtsc()-start-empty_ticks)
<< " ticks/n" << benchmark_repetitions << " repetitions/n"
<< std::setprecision(15) << (my_time.elapsed()-empty_seconds)
<< " seconds/n/n";
}
}
int main( void ) {
void* Cur_Thread= GetCurrentThread();
void* Cur_Process= GetCurrentProcess();
unsigned long long Current_Affinity;
unsigned long long System_Affinity;
unsigned long long furthest_affinity;
unsigned long long nearest_affinity;
if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
}
if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
}
GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
nearest_affinity = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
SetProcessAffinityMask( Cur_Process, furthest_affinity );
SetThreadAffinityMask( Cur_Thread, furthest_affinity );
const int repetitions=524288;
benchmark<repetitions>( nullptr, empty_function );
benchmark<repetitions>( "Standard Square Root", standard_sqrt );
benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );
SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
SetProcessAffinityMask( Cur_Process, nearest_affinity );
SetThreadAffinityMask( Cur_Thread, nearest_affinity );
for (;;) { getchar(); }
return 0;
}
Además, acredite a Mike Jarvis por su temporizador.
Y, tenga en cuenta (esto es muy importante) que si va a ejecutar fragmentos de código más grandes, REALMENTE debe rechazar el número de iteraciones para evitar que la computadora se congele.
Sugiero usar las funciones de 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.
También puede consultar los [cxx-rtimers][1]
en GitHub, que proporcionan algunas rutinas de solo 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 de Boost, o funciones estándar de temporizador POSIX. Estos temporizadores informarán la duración promedio, máxima y mínima de una función, así como la cantidad de veces que se la llama. Se pueden usar de la siguiente manera:
#include <rtimers/cxx11.hpp>
void expensiveFunction() {
static rtimers::cxx11::DefaultTimer timer("expensive");
auto scopedStartStop = timer.scopedStart();
// Do something costly...
}
Tengo otro ejemplo de trabajo que usa microsegundos (UNIX, POSIX, etc.).
#include <sys/time.h>
typedef unsigned long long timestamp_t;
static timestamp_t
get_timestamp ()
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
}
...
timestamp_t t0 = get_timestamp();
// Process
timestamp_t t1 = get_timestamp();
double secs = (t1 - t0) / 1000000.0L;
Aquí está el archivo donde codificamos esto:
https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c
Windows proporciona la función QueryPerformanceCounter () y Unix tiene gettimeofday () Ambas funciones pueden medir al menos 1 diferencia de microsegundos.
solo una clase simple que compara el bloque de código:
using namespace std::chrono;
class benchmark {
public:
time_point<high_resolution_clock> t0, t1;
unsigned int *d;
benchmark(unsigned int *res) : d(res) {
t0 = high_resolution_clock::now();
}
~benchmark() { t1 = high_resolution_clock::now();
milliseconds dur = duration_cast<milliseconds>(t1 - t0);
*d = dur.count();
}
};
// simple usage
// unsigned int t;
// { // put the code in a block
// benchmark bench(&t);
// // ...
// // code to benchmark
// }
// HERE the t contains time in milliseconds
// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) /
unsigned int __time__##__LINE__ = 0; /
{ benchmark bench(&__time__##__LINE__); /
CODEBLOCK /
} /
printf("%s took %d ms/n",(TITLE),__time__##__LINE__);
int main(void) {
BENCH("TITLE",{
for(int n = 0; n < testcount; n++ )
int a = n % 3;
});
return 0;
}
boost::timer probablemente te dará tanta precisión como necesites. 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 toma un par de nanosegundos?
#include <boost/progress.hpp>
using namespace boost;
int main (int argc, const char * argv[])
{
progress_timer timer;
// do stuff, preferably in a 100x loop to make it take longer.
return 0;
}
Cuando progress_timer
se sale del alcance, imprimirá el tiempo transcurrido desde su creación.
ACTUALIZACIÓN : Hice un reemplazo independiente simple (OSX / iOS pero fácil de portar): https://github.com/catnapgames/TestTimerScoped