Cómo calcular el tiempo de ejecución de un fragmento de código en C ++

121

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?

AhmetB - Google
fuente
29
Tenga en cuenta que cualquier comparación basada en la diferencia de tiempo puede ser inexacta debido al hecho de que es posible que el sistema operativo no ejecute su hilo de principio a fin. Puede interrumpirlo y ejecutar otros subprocesos entrelazados con el suyo, lo que tendrá un impacto significativo en el tiempo real necesario para completar su operación. Puede ejecutar varias veces y promediar los resultados; puede minimizar el número de otros procesos en ejecución. Pero ninguno de estos eliminará por completo el efecto de suspensión del hilo.
Mordachai
14
Mordachi, ¿por qué querrías eliminarlo? Desea ver cómo se desempeña su función en un entorno del mundo real, no en un reino mágico donde los hilos no se interrumpen nunca. Siempre que lo ejecute varias veces y haga un promedio, será muy preciso.
Thomas Bonini
Sí, lo ejecuto varias veces y promedie los resultados.
AhmetB - Google
14
Andreas, el comentario de Mordachai es relevante si el OP desea comparar el rendimiento de su código con un algoritmo diferente. Por ejemplo, si ejecuta varias pruebas de reloj esta tarde y luego prueba un algoritmo diferente mañana por la mañana, es posible que su comparación no sea confiable ya que puede estar compartiendo recursos con muchos más procesos por la tarde que por la mañana. O tal vez un conjunto de código hará que el sistema operativo le dé menos tiempo de procesamiento. Existen numerosas razones por las que este tipo de medición del rendimiento no es confiable si desea realizar una comparación basada en el tiempo.
weberc2
4
@Mordachai Sé que estoy respondiendo a un comentario antiguo, pero para quien tropiece con esto como yo lo hice: para medir el rendimiento de los algoritmos, debe tomar el mínimo de algunas ejecuciones, no el promedio. Este es el que tuvo menos interrupciones por parte del sistema operativo y, por lo tanto, está cronometrando principalmente su código.
Baruch

Respuestas:

115

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 que time(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.

#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
}
Thomas Bonini
fuente
1
Para referencia futura: simplemente lo coloco en un archivo de encabezado y lo uso. Me alegro de tenerlo.
Daniel Handojo
1
Creo que el método gettimeofdaypuede 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 su clock_gettimelugar.
Azmisov
¿Tiene alguna ventaja este método para Windows GetTickCount?
MicroVirus
No se compila utilizandogcc -std=c99
Assimilater
@MicroVirus: sí, GetTickCountes 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.
Thomas Bonini
43

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

arhuaco
fuente
5
Debe agregar #include <sys/time.h>al comienzo de su ejemplo.
niekas
40

Aquí hay una solución simple en C ++ 11 que le brinda 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;
}

De https://gist.github.com/gongzhitaao/7062087

gongzhitaao
fuente
Recibo este error con su solución de c ++ 11:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932
@julianromera ¿qué plataforma estás usando? ¿Instalaste la biblioteca libstdc ++ y g ++?
gongzhitaao
Es una cuadrícula Slurm de Linux ubuntu 12. Lo acabo de arreglar. Agregué -static-libstdc ++ al final del enlazador. Gracias por preguntar a @gongzhitaao
user9869932
18
#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_timersalga 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):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}
Tomas Andrle
fuente
2
Esto funciona, pero tenga en cuenta que progress_timer está en desuso (en algún momento antes de boost 1.50); ​​auto_cpu_timer puede ser más apropiado.
DavidA
3
@meowsqueak hmm, auto_cpu_timer parece requerir que la biblioteca del sistema Boost esté vinculada, por lo que ya no es una solución solo de encabezado. Lástima ... hace que las otras opciones sean más atractivas de repente.
Tomas Andrle
1
sí, ese es un buen punto, si aún no vincula Boost, entonces es más problemático de lo que vale. Pero si ya lo hace, funciona bastante bien.
davidA
@meowsqueak Sí, o para algunas pruebas comparativas rápidas, simplemente obtenga esa versión anterior de Boost.
Tomas Andrle
@TomasAndrle El enlace ya no existe.
Zheng Qu
5

Windows proporciona la función QueryPerformanceCounter () y Unix tiene gettimeofday () Ambas funciones pueden medir al menos 1 microsegundo de diferencia.

Capitán Comic
fuente
Pero el uso de windows.h está restringido. La misma fuente compilada debe ejecutarse tanto en Windows como en Unix. ¿Cómo manejar este problema?
AhmetB - Google
2
Luego busque una biblioteca contenedora stackoverflow.com/questions/1487695/…
Captain Comic
4
la misma fuente compilada suena como si quisiera ejecutar el mismo binario en ambos sistemas, lo que no parece ser el caso. si nos referimos la misma fuente a continuación, una #ifdefdebe 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.
solo alguien
3

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í )

kriss
fuente
2

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.

Thomas Matthews
fuente
2

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.

Adisak
fuente
2

(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

#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;
}

fuente
2

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 -Oga 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", -Ogrealiza muy pocas optimizaciones en comparación con -Ofast; por lo tanto, -Ogpuede 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 -Ofastde pruebas de velocidad CON la adición de asm 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.

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

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-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    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, 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.

Jack Giffin
fuente
2
Buena respuesta excepto por desactivar la optimización. El -O0código de evaluación comparativa es una gran pérdida de tiempo porque la sobrecarga en -O0 lugar de una normal -O2o -O3 -march=nativevarí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 con volatilefunciones no en línea o declaraciones asm en línea vacías. -O0ni siquiera está cerca de ser utilizable porque el código tiene diferentes cuellos de botella en -O0, no lo mismo pero peor.
Peter Cordes
1
Uf, -Ogtodavía no es muy realista, dependiendo del código. Al menos -O2, preferiblemente -O3es más realista. Utilice asm 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.
Peter Cordes
@PeterCordes Gracias nuevamente por sus ideas. He actualizado el contenido con -O3y el fragmento de código con asm volatile("" ::: "+r"(var)).
Jack Giffin
1
asm volatile("" ::: "+r"( i ));parece innecesario. En código optimizado, no hay razón para forzar al compilador a materializarse itan bien como i<<7dentro del ciclo. Estás impidiendo que se optimice en tmp -= 128lugar de cambiar cada vez. Sin embargo, usar el resultado de una llamada de función es bueno si no es void. Al igual int result = (*function_to_do)( i << 7 );. Podría utilizar una asmdeclaración sobre ese resultado.
Peter Cordes
@PeterCordes Muchas gracias de nuevo por sus ideas. Mi publicación ahora contiene las correcciones para el valor de retorno de function_to_dopara que function_to_dopueda insertarse sin ser eliminado. Por favor, avíseme si tiene más sugerencias.
Jack Giffin
1

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:

#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://stackoverflow.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;
};
Mike Jarvis
fuente
1

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;
}
nullqube
fuente
0

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?

Brendan Long
fuente
Se basa en la clock()función del encabezado estándar de C ++.
Petter
0

Creé una lambda que llama a su función llamada N veces y le devuelve el promedio.

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

Puede encontrar el encabezado de c ++ 11 aquí .

quemador
fuente
0

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:

#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;
}
Neil
fuente
0

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:

#include <rtimers/cxx11.hpp>

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

Así es como lo hago, no hay mucho código, es fácil de entender, se adapta a mis necesidades:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

Uso:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);
cisco211
fuente
0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;
Nate Frisch
fuente
2
Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resultaría en más votos a favor. Recuerde que está respondiendo la pregunta a los lectores en el futuro, no solo a la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos.
Dharman