Función de temporizador para proporcionar tiempo en nano segundos usando C ++

101

Deseo calcular el tiempo que tardó una API en devolver un valor. El tiempo necesario para tal acción está en el espacio de nano segundos. Como la API es una clase / función de C ++, estoy usando timer.h para calcular lo mismo:

  #include <ctime>
  #include <cstdio>

  using namespace std;

  int main(int argc, char** argv) {

      clock_t start;
      double diff;
      start = clock();
      diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
      cout<<"printf: "<< diff <<'\n';

      return 0;
  }

El código anterior da el tiempo en segundos. ¿Cómo consigo lo mismo en nano segundos y con más precisión?

gagneet
fuente
el código anterior se calcula en segundos, quiero obtener la respuesta en nano segundos ...
gagneet
Necesita agregar la plataforma a la pregunta (y preferiblemente también al título) para obtener una buena respuesta.
Patrick Johnmeyer
Además de obtener el tiempo, es necesario buscar problemas con el microbenchmarking (que es extremadamente complejo): es poco probable que solo hacer una ejecución y obtener el tiempo al principio y al final proporcione suficiente precisión.
Blaisorblade
@Blaisorblade: Especialmente desde que descubrí en algunas de mis pruebas que clock()no es tan rápido como pensaba.
Mooing Duck

Respuestas:

83

Lo que otros han publicado sobre ejecutar la función repetidamente en un bucle es correcto.

Para Linux (y BSD) desea utilizar clock_gettime () .

#include <sys/time.h>

int main()
{
   timespec ts;
   // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD
   clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux
}

Para las ventanas, desea utilizar QueryPerformanceCounter . Y aquí hay más sobre QPC

Aparentemente, hay un problema conocido con QPC en algunos conjuntos de chips, por lo que es posible que desee asegurarse de no tener esos conjuntos de chips. Además, algunos AMD de doble núcleo también pueden causar un problema . Vea la segunda publicación de sebbbi, donde dice:

QueryPerformanceCounter () y QueryPerformanceFrequency () ofrecen una resolución un poco mejor, pero tienen problemas diferentes. Por ejemplo, en Windows XP, todas las CPU AMD Athlon X2 de doble núcleo devuelven la PC de cualquiera de los núcleos "al azar" (la PC a veces salta un poco hacia atrás), a menos que instale especialmente el paquete de controladores AMD de doble núcleo para solucionar el problema. No hemos notado que ninguna otra CPU dual + core tenga problemas similares (p4 dual, p4 ht, core2 dual, core2 quad, phenom quad).

EDITAR 16/07/2013:

Parece que existe cierta controversia sobre la eficacia de QPC en determinadas circunstancias, como se indica en http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx

... Mientras QueryPerformanceCounter y QueryPerformanceFrequency normalmente se ajustan para múltiples procesadores, los errores en el BIOS o los controladores pueden hacer que estas rutinas devuelvan valores diferentes a medida que el hilo se mueve de un procesador a otro ...

Sin embargo, esta respuesta de StackOverflow https://stackoverflow.com/a/4588605/34329 establece que QPC debería funcionar bien en cualquier sistema operativo MS después del paquete de servicio 2 de Win XP.

Este artículo muestra que Windows 7 puede determinar si los procesadores tienen un TSC invariante y recurren a un temporizador externo si no lo tienen. http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html La sincronización entre procesadores sigue siendo un problema.

Otra buena lectura relacionada con los temporizadores:

Consulte los comentarios para obtener más detalles.

afligirse
fuente
1
He visto el reloj TSC sesgado en una PC Xeon dual más antigua, pero no tan mal como en un Athlon X2 con la rampa de reloj C1 habilitada. Con la aceleración del reloj C1, la ejecución de una instrucción HLT ralentiza el reloj, lo que hace que el TSC en los núcleos inactivos aumente más lentamente que en los núcleos activos.
bk1e
6
CLOCK_MONOTONIC funciona en las versiones de Linux que tengo disponibles.
Bernard
1
@Bernard - Eso debe ser agregado recientemente desde la última vez que miré esto. Gracias por el aviso.
duelo
3
De hecho, debe usar CLOCK_MONOTONIC_RAW, si está disponible, para obtener el tiempo del hardware no ajustado por NTP.
Como se discutió aquí, la implementación correcta de QPC no usa el contador TSC, al menos donde se sabe que no es confiable: stackoverflow.com/q/510462/53974
Blaisorblade
69

Esta nueva respuesta usa la <chrono>facilidad de C ++ 11 . Si bien hay otras respuestas que muestran cómo usar <chrono>, ninguna muestra cómo usar <chrono>con la RDTSCfacilidad mencionada en varias de las otras respuestas aquí. Así que pensé que iba a mostrar cómo utilizar RDTSCcon <chrono>. Además, demostraré cómo puede crear una plantilla del código de prueba en el reloj para que pueda cambiar rápidamente entre RDTSClas funciones de reloj integradas de su sistema (que probablemente se basarán en clock(), clock_gettime()y / o QueryPerformanceCounter.

Tenga en cuenta que la RDTSCinstrucción es específica de x86. QueryPerformanceCounteres solo para Windows. Y clock_gettime()es solo POSIX. A continuación, presento dos relojes nuevos: std::chrono::high_resolution_clocky std::chrono::system_clock, que, si puede asumir C ++ 11, ahora son multiplataforma.

Primero, así es como se crea un reloj compatible con C ++ 11 a partir de las rdtscinstrucciones de ensamblaje de Intel . Lo llamaré x::clock:

#include <chrono>

namespace x
{

struct clock
{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2'800'000'000>       period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }
};

}  // x

Todo lo que hace este reloj es contar los ciclos de la CPU y almacenarlos en un entero de 64 bits sin signo. Es posible que deba modificar la sintaxis del lenguaje ensamblador para su compilador. O su compilador puede ofrecer un intrínseco que puede usar en su lugar (por ejemplo now() {return __rdtsc();}).

Para construir un reloj hay que darle la representación (tipo de almacenamiento). También debe proporcionar el período del reloj, que debe ser una constante de tiempo de compilación, aunque su máquina puede cambiar la velocidad del reloj en diferentes modos de energía. Y a partir de ellos, puede definir fácilmente la duración y el punto de tiempo "nativos" de su reloj en términos de estos fundamentos.

Si todo lo que quiere hacer es generar el número de tics del reloj, realmente no importa qué número dé para el período del reloj. Esta constante solo entra en juego si desea convertir el número de pulsos del reloj en alguna unidad de tiempo real, como nanosegundos. Y en ese caso, cuanto más preciso sea el suministro de la velocidad del reloj, más precisa será la conversión a nanosegundos (milisegundos, lo que sea).

A continuación se muestra un código de ejemplo que muestra cómo usarlo x::clock. En realidad, he creado una plantilla para el código del reloj, ya que me gustaría mostrar cómo puede usar muchos relojes diferentes con la misma sintaxis exacta. Esta prueba en particular muestra cuál es la sobrecarga de bucle cuando se ejecuta lo que desea cronometrar bajo un bucle:

#include <iostream>

template <class clock>
void
test_empty_loop()
{
    // Define real time units
    typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
    // or:
    // typedef std::chrono::nanoseconds nanoseconds;
    // Define double-based unit of clock tick
    typedef std::chrono::duration<double, typename clock::period> Cycle;
    using std::chrono::duration_cast;
    const int N = 100000000;
    // Do it
    auto t0 = clock::now();
    for (int j = 0; j < N; ++j)
        asm volatile("");
    auto t1 = clock::now();
    // Get the clock ticks per iteration
    auto ticks_per_iter = Cycle(t1-t0)/N;
    std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
    // Convert to real time units
    std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
              << "ps per iteration\n";
}

Lo primero que hace este código es crear una unidad de "tiempo real" para mostrar los resultados. He elegido picosegundos, pero puede elegir cualquier unidad que desee, ya sea integral o basada en punto flotante. Como ejemplo, hay una std::chrono::nanosecondsunidad prefabricada que podría haber usado.

Como otro ejemplo, quiero imprimir el número promedio de ciclos de reloj por iteración como un punto flotante, así que creo otra duración, basada en el doble, que tiene las mismas unidades que el tic del reloj (llamado Cycleen el código).

El ciclo se cronometra con llamadas a clock::now()ambos lados. Si desea nombrar el tipo devuelto por esta función, es:

typename clock::time_point t0 = clock::now();

(como se muestra claramente en el x::clockejemplo, y también es cierto para los relojes suministrados por el sistema).

Para obtener una duración en términos de tics de reloj de punto flotante, uno simplemente resta los dos puntos de tiempo, y para obtener el valor por iteración, divida esa duración por el número de iteraciones.

Puede obtener el recuento en cualquier duración utilizando la count()función miembro. Esto devuelve la representación interna. Finalmente, utilizo std::chrono::duration_castpara convertir la duración Cyclea la duración picosecondse imprimirla.

Usar este código es simple:

int main()
{
    std::cout << "\nUsing rdtsc:\n";
    test_empty_loop<x::clock>();

    std::cout << "\nUsing std::chrono::high_resolution_clock:\n";
    test_empty_loop<std::chrono::high_resolution_clock>();

    std::cout << "\nUsing std::chrono::system_clock:\n";
    test_empty_loop<std::chrono::system_clock>();
}

Arriba realizo la prueba usando nuestro hecho en casa x::clock, y comparo esos resultados con el uso de dos de los relojes provistos por el sistema: std::chrono::high_resolution_clocky std::chrono::system_clock. Para mí esto imprime:

Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration

Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration

Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration

Esto muestra que cada uno de estos relojes tiene un período de tic diferente, ya que los tics por iteración son muy diferentes para cada reloj. Sin embargo, cuando se convierte a una unidad de tiempo conocida (por ejemplo, picosegundos), obtengo aproximadamente el mismo resultado para cada reloj (su millaje puede variar).

Tenga en cuenta que mi código está completamente libre de "constantes de conversión mágicas". De hecho, solo hay dos números mágicos en todo el ejemplo:

  1. La velocidad del reloj de mi máquina para definir x::clock.
  2. El número de iteraciones para probar. Si cambiar este número hace que sus resultados varíen mucho, entonces probablemente debería aumentar el número de iteraciones o vaciar su computadora de procesos competidores durante la prueba.
Howard Hinnant
fuente
5
Por "RDTSC es solo para Intel", realmente se está refiriendo a la arquitectura x86 y sus derivados, ¿no es así? Los chips AMD, Cyrix, Transmeta x86 tienen la instrucción , y los procesadores Intel RISC y ARM no.
Ben Voigt
1
@BenVoigt: +1 Sí, su corrección es bastante correcta, gracias.
Howard Hinnant
1
¿Cómo afectará la aceleración de la CPU a esto? ¿No cambia la velocidad del reloj en función de la carga de la CPU?
Tejas Kale
@TejasKale: Esto se describe en la respuesta en los dos párrafos consecutivos que comienzan con "Para construir un reloj tú ...". Normalmente, el código de tiempo no mide el trabajo que bloquea un hilo (pero puede hacerlo). Y, por lo general, su CPU no se acelera. Pero si está midiendo código que involucra suspensión, bloqueo de mutex, condición_variable de espera, etc., rdtsces probable que el reloj tenga conversiones inexactas a otras unidades. Es una buena idea configurar sus medidas para que pueda cambiar y comparar relojes fácilmente (como se muestra en esta respuesta).
Howard Hinnant
27

Con ese nivel de precisión, sería mejor razonar en el tic de la CPU en lugar de en la llamada del sistema como clock () . Y no olvide que si se tarda más de un nanosegundo en ejecutar una instrucción ... tener una precisión de nanosegundos es prácticamente imposible.

Aún así, algo así es un comienzo:

Aquí está el código real para recuperar el número de tics de reloj de la CPU de 80x86 pasados ​​desde la última vez que se inició la CPU. Funcionará en Pentium y superiores (386/486 no es compatible). Este código es en realidad específico de MS Visual C ++, pero probablemente pueda ser fácilmente adaptado a cualquier otra cosa, siempre que sea compatible con el ensamblaje en línea.

inline __int64 GetCpuClocks()
{

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    // Return result
    return *(__int64 *)(&counter);

}

Esta función también tiene la ventaja de ser extremadamente rápida: por lo general, no se necesitan más de 50 ciclos de CPU para ejecutarse.

Uso de las cifras de sincronización :
si necesita traducir los conteos del reloj en tiempo transcurrido real, divida los resultados por la velocidad del reloj de su chip. Recuerde que es probable que el GHz "nominal" sea ligeramente diferente de la velocidad real de su chip. Para comprobar la velocidad real de su chip, puede utilizar varias utilidades muy buenas o la llamada de Win32, QueryPerformanceFrequency ().

VonC
fuente
gracias por la información, esto es útil. No pensé en los ciclos de la CPU para calcular el tiempo, creo que es un muy buen punto a tener en cuenta :-)
gagneet
4
Es posible que el uso de QueryPerformanceFrequency () para convertir los recuentos de TSC en tiempo transcurrido no funcione. QueryPerformanceCounter () utiliza HPET (Temporizador de eventos de alta precisión) en Vista cuando está disponible. Utiliza el temporizador de administración de energía ACPI si el usuario agrega / USEPMTIMER a boot.ini.
bk1e
23

Para hacer esto correctamente, puede usar una de dos formas, ya sea con RDTSCo con clock_gettime(). El segundo es aproximadamente 2 veces más rápido y tiene la ventaja de dar el tiempo absoluto correcto. Tenga en cuenta que para RDTSCque funcione correctamente debe usarlo como se indica (otros comentarios en esta página tienen errores y pueden producir valores de tiempo incorrectos en ciertos procesadores)

inline uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx" );
    return (uint64_t)hi << 32 | lo;
}

y para clock_gettime: (elegí resolución de microsegundos arbitrariamente)

#include <time.h>
#include <sys/timeb.h>
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 mcs resolution (divide by 1M to get time_t)
uint64_t ClockGetTime()
{
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec / 1000LL;
}

el tiempo y los valores producidos:

Absolute values:
rdtsc           = 4571567254267600
clock_gettime   = 1278605535506855

Processing time: (10000000 runs)
rdtsc           = 2292547353
clock_gettime   = 1031119636
Marius
fuente
22

Estoy usando lo siguiente para obtener los resultados deseados:

#include <time.h>
#include <iostream>
using namespace std;

int main (int argc, char** argv)
{
    // reset the clock
    timespec tS;
    tS.tv_sec = 0;
    tS.tv_nsec = 0;
    clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    ...
    ... <code to check for the time to be put here>
    ...
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    cout << "Time taken is: " << tS.tv_sec << " " << tS.tv_nsec << endl;

    return 0;
}
gagneet
fuente
2
Bajé la votación porque al intentar aplicar este código tuve que buscar primero en Google por qué la especificación de tiempo no está definida. Luego tuve que buscar en Google qué es POSIX ... y, según lo entendí, este código no es relevante para los usuarios de Windows que deben seguir con la biblioteca estándar.
Daniel Katz
8

Para C ++ 11 , aquí hay un contenedor simple:

#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 para C ++ 03 en * nix,

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

Ejemplo de uso:

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
5

En general, para medir el tiempo que se tarda en llamar a una función, conviene hacerlo muchas más veces que una sola vez. Si llama a su función solo una vez y tarda muy poco en ejecutarse, todavía tiene la sobrecarga de llamar a las funciones del temporizador y no sabe cuánto tiempo lleva.

Por ejemplo, si estima que su función puede tardar 800 ns en ejecutarse, llámela en un bucle diez millones de veces (lo que tardará unos 8 segundos). Divida el tiempo total por diez millones para obtener el tiempo por llamada.

Greg Hewgill
fuente
en realidad, estoy tratando de obtener el rendimiento de la API para una llamada en particular. para cada ejecución, puede dar un tiempo diferente, esto puede afectar el gráfico que hago para la mejora del rendimiento ... de ahí el tiempo en nano segundos. pero sí, esta es una gran idea, la consideraré.
gagneet
5

Puede utilizar la siguiente función con gcc ejecutándose en procesadores x86:

unsigned long long rdtsc()
{
  #define rdtsc(low, high) \
         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

  unsigned int low, high;
  rdtsc(low, high);
  return ((ulonglong)high << 32) | low;
}

con Digital Mars C ++:

unsigned long long rdtsc()
{
   _asm
   {
        rdtsc
   }
}

que lee el temporizador de alto rendimiento en el chip. Utilizo esto cuando hago perfiles.

Walter Bright
fuente
2
esto es útil, verificaré si el procesador es x86, ya que estoy usando una Mac de Apple para experimentar ... gracias :-)
gagneet
1
¿Qué valores se supone que debe dar el usuario para alto y bajo? ¿Por qué define una macro dentro del cuerpo de una función? Además, ulonglong, presumiblemente typedef'd to unsigned long long, no es un tipo estándar. Me gustaría usar esto, pero no estoy seguro de cómo;)
Joseph Garvin
1
unsigned long no es lo correcto para usar en linux. Es posible que desee considerar usar int en su lugar, ya que long y long long son ambos de 64 bits en Linux de 64 bits.
Marius
3
Hoy en día, el contador TSC a menudo no es confiable: cambia su velocidad en muchos procesadores cuando se cambia la frecuencia y es inconsistente en diferentes núcleos, por lo que el TSC no siempre crece.
Blaisorblade
1
@Marius: Implementé tu comentario, usando unsigned intcomo tipo interno.
Blaisorblade
3

Si necesita una precisión de menos de un segundo, debe utilizar extensiones específicas del sistema y deberá consultar la documentación del sistema operativo. POSIX admite hasta microsegundos con gettimeofday , pero nada más preciso ya que las computadoras no tenían frecuencias por encima de 1GHz.

Si está usando Boost, puede verificar boost :: posix_time .

Raymond Martineau
fuente
quiero mantener el código portátil, veré la biblioteca boost y comprobaré si puedo empaquetar esto con el código. gracias :-)
gagneet
3

Estoy usando el código de Borland, aquí está el código que ti_hund me da algunas veces un número negativo, pero el tiempo es bastante bueno.

#include <dos.h>

void main() 
{
struct  time t;
int Hour,Min,Sec,Hun;
gettime(&t);
Hour=t.ti_hour;
Min=t.ti_min;
Sec=t.ti_sec;
Hun=t.ti_hund;
printf("Start time is: %2d:%02d:%02d.%02d\n",
   t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
....
your code to time
...

// read the time here remove Hours and min if the time is in sec

gettime(&t);
printf("\nTid Hour:%d Min:%d Sec:%d  Hundreds:%d\n",t.ti_hour-Hour,
                             t.ti_min-Min,t.ti_sec-Sec,t.ti_hund-Hun);
printf("\n\nAlt Ferdig Press a Key\n\n");
getch();
} // end main
Paul J. Moesman
fuente
3

Usando el método de Brock Adams, con una clase simple:

int get_cpu_ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}

__int64 get_cpu_clocks()
{
    struct { int32 low, high; } counter;

    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    return *(__int64 *)(&counter);
}

class cbench
{
public:
    cbench(const char *desc_in) 
         : desc(strdup(desc_in)), start(get_cpu_clocks()) { }
    ~cbench()
    {
        printf("%s took: %.4f ms\n", desc, (float)(get_cpu_clocks()-start)/get_cpu_ticks());
        if(desc) free(desc);
    }
private:
    char *desc;
    __int64 start;
};

Ejemplo de uso:

int main()
{
    {
        cbench c("test");
        ... code ...
    }
    return 0;
}

Resultado:

prueba tomó: 0.0002 ms

Tiene una sobrecarga de llamadas a funciones, pero debería ser lo suficientemente rápido :)

Thomas
fuente
3

Puede usar Embedded Profiler (gratuito para Windows y Linux) que tiene una interfaz para un temporizador multiplataforma (en un recuento de ciclos de procesador) y puede proporcionarle una cantidad de ciclos por segundo:

EProfilerTimer timer;
timer.Start();

... // Your code here

const uint64_t number_of_elapsed_cycles = timer.Stop();
const uint64_t nano_seconds_elapsed =
    mumber_of_elapsed_cycles / (double) timer.GetCyclesPerSecond() * 1000000000;

El recálculo del recuento de ciclos al tiempo es posiblemente una operación peligrosa con los procesadores modernos donde la frecuencia de la CPU se puede cambiar dinámicamente. Por lo tanto, para asegurarse de que los tiempos convertidos sean correctos, es necesario fijar la frecuencia del procesador antes de generar perfiles.

Mi-La
fuente
2

Si esto es para Linux, he estado usando la función "gettimeofday", que devuelve una estructura que da los segundos y microsegundos desde la Época. Luego puede usar timersub para restar los dos para obtener la diferencia en el tiempo y convertirlo a la precisión de tiempo que desee. Sin embargo, especifica nanosegundos y parece que la función clock_gettime () es lo que está buscando. Pone el tiempo en términos de segundos y nanosegundos en la estructura por la que pasa.

Will Mc
fuente
clock_gettime () debería funcionar por ahora. intentaré usar el mismo para mi propósito ...
gagneet
2

Qué piensas sobre eso:

    int iceu_system_GetTimeNow(long long int *res)
    {
      static struct timespec buffer;
      // 
    #ifdef __CYGWIN__
      if (clock_gettime(CLOCK_REALTIME, &buffer))
        return 1;
    #else
      if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &buffer))
        return 1;
    #endif
      *res=(long long int)buffer.tv_sec * 1000000000LL + (long long int)buffer.tv_nsec;
      return 0;
    }
hielo bueno
fuente
2

Aquí hay un buen temporizador de impulso que funciona bien:

//Stopwatch.hpp

#ifndef STOPWATCH_HPP
#define STOPWATCH_HPP

//Boost
#include <boost/chrono.hpp>
//Std
#include <cstdint>

class Stopwatch
{
public:
    Stopwatch();
    virtual         ~Stopwatch();
    void            Restart();
    std::uint64_t   Get_elapsed_ns();
    std::uint64_t   Get_elapsed_us();
    std::uint64_t   Get_elapsed_ms();
    std::uint64_t   Get_elapsed_s();
private:
    boost::chrono::high_resolution_clock::time_point _start_time;
};

#endif // STOPWATCH_HPP


//Stopwatch.cpp

#include "Stopwatch.hpp"

Stopwatch::Stopwatch():
    _start_time(boost::chrono::high_resolution_clock::now()) {}

Stopwatch::~Stopwatch() {}

void Stopwatch::Restart()
{
    _start_time = boost::chrono::high_resolution_clock::now();
}

std::uint64_t Stopwatch::Get_elapsed_ns()
{
    boost::chrono::nanoseconds nano_s = boost::chrono::duration_cast<boost::chrono::nanoseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(nano_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_us()
{
    boost::chrono::microseconds micro_s = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(micro_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_ms()
{
    boost::chrono::milliseconds milli_s = boost::chrono::duration_cast<boost::chrono::milliseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(milli_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_s()
{
    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(sec.count());
}
Patrick K
fuente
2

Copiar y pegar-estructura minimalista + uso perezoso

Si la idea es tener una estructura minimalista que pueda usar para pruebas rápidas, le sugiero que simplemente copie y pegue en cualquier lugar de su archivo C ++ justo después de la #include. Esta es la única instancia en la que sacrifico el formato de estilo Allman.

Puede ajustar fácilmente la precisión en la primera línea de la estructura. Los valores posibles son: nanoseconds, microseconds, milliseconds, seconds, minutes, o hours.

#include <chrono>
struct MeasureTime
{
    using precision = std::chrono::microseconds;
    std::vector<std::chrono::steady_clock::time_point> times;
    std::chrono::steady_clock::time_point oneLast;
    void p() {
        std::cout << "Mark " 
                << times.size()/2
                << ": " 
                << std::chrono::duration_cast<precision>(times.back() - oneLast).count() 
                << std::endl;
    }
    void m() {
        oneLast = times.back();
        times.push_back(std::chrono::steady_clock::now());
    }
    void t() {
        m();
        p();
        m();
    }
    MeasureTime() {
        times.push_back(std::chrono::steady_clock::now());
    }
};

Uso

MeasureTime m; // first time is already in memory
doFnc1();
m.t(); // Mark 1: next time, and print difference with previous mark
doFnc2();
m.t(); // Mark 2: next time, and print difference with previous mark
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.t(); // prints 'Mark 3: 123123' etc...

Resultado de salida estándar

Mark 1: 123
Mark 2: 32
Mark 3: 433234

Si quieres resumen después de la ejecución

Si desea el informe después, porque, por ejemplo, su código intermedio también escribe en la salida estándar. Luego agregue la siguiente función a la estructura (justo antes de MeasureTime ()):

void s() { // summary
    int i = 0;
    std::chrono::steady_clock::time_point tprev;
    for(auto tcur : times)
    {
        if(i > 0)
        {
            std::cout << "Mark " << i << ": "
                    << std::chrono::duration_cast<precision>(tprev - tcur).count()
                    << std::endl;
        }
        tprev = tcur;
        ++i;
    }
}

Entonces puedes usar:

MeasureTime m;
doFnc1();
m.m();
doFnc2();
m.m();
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.m();
m.s();

Que enumerará todas las marcas como antes, pero luego después de que se ejecute el otro código. Tenga en cuenta que no debe usar ambos m.s()y m.t().

Yeti
fuente
Funciona perfectamente con OpenMP en Ubuntu 16.04. ¡Muchas gracias, esta debería ser la mejor respuesta en mi opinión!
Íhor Mé