2009-02-25 19 views
96

En Windows, clock() devuelve el tiempo en milisegundos, pero en este cuadro de Linux en el que estoy trabajando, lo redondea al 1000 más cercano la precisión es solo al nivel "segundo" y no al nivel de milisegundos.C++ obteniendo un tiempo de milisegundos en Linux - clock() no parece funcionar correctamente

he encontrado una solución con Qt utilizando la clase QTime, crear instancias de un objeto y llamar start() en ella, luego llamar elapsed() para obtener el número de milisegundos transcurridos.

llegué tipo de suerte porque estoy trabajando con Qt para empezar, pero me gustaría una solución que no depende de bibliotecas de terceros,

¿No hay manera estándar de hacer esto?

ACTUALIZACIÓN

Por favor no lo recomiendan Boost ..

Si Boost y Qt pueden hacerlo, sin duda no es magia, tiene que haber algo estándar que están usando!

+2

Acerca de edición - pero hacerlo de manera portátil es un poco doloroso – Anonymous

+0

Relevante: https://stackoverflow.com/questions/28396014/why-is-clock-considered-bad –

Respuesta

33

usted podría utilizar gettimeofday al comienzo y al final de su método y luego diferencia de las dos estructuras de retorno. Usted obtendrá una estructura como la siguiente:

struct timeval { 
    time_t tv_sec; 
    suseconds_t tv_usec; 
} 
+36

terrible para el trabajo serio. Grandes problemas dos veces al año, cuando alguien tiene citas -s, y por supuesto sincronización NTP. Use clock_gettime (CLOCK_MONOTONIC,) – AndrewStone

+9

@AndrewStone: el tiempo de UNIX no cambia dos veces al año. O incluso una vez al año. Pero, sí, 'CLOCK_MONOTONIC' es ideal para evitar ajustes de tiempo del sistema localizados. –

2

clock() no devuelve milisegundos o segundos en linux. Por lo general, clock() devuelve microsegundos en un sistema Linux. La forma correcta de interpretar el valor devuelto por clock() es dividirlo por CLOCKS_PER_SEC para calcular cuánto tiempo ha pasado.

+0

¡No en la caja en la que estoy trabajando! además, I * estoy * dividiendo por CLOCKS_PER_SEC, pero no tiene sentido porque la resolución solo se reduce al segundo – hasen

+0

, para ser justos, las unidades * son * microsegundos (CLOCKS_PER_SEC es 1000000 en todos los sistemas POSIX). Solo tiene una resolución de segundos. :-PAG. –

1

En el estándar POSIX clock tiene su valor de retorno definido en términos del símbolo CLOCKS_PER_SEC y una implementación es libre de definir esto de cualquier manera conveniente. Bajo Linux, he tenido buena suerte con la función times().

0

Yo prefiero el Boost Timer library por su sencillez, pero si usted no desea utilizar las bibliotecas de tercera parrty, utilizando el reloj() parece razonable.

1

Esto debería funcionar ... probado en un mac ...

#include <stdio.h> 
#include <sys/time.h> 

int main() { 
     struct timeval tv; 
     struct timezone tz; 
     struct tm *tm; 
     gettimeofday(&tv,&tz); 
     tm=localtime(&tv.tv_sec); 
     printf("StartTime: %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec); 
} 

Sí ... ejecutarlo dos veces y restar ...

137
#include <sys/time.h> 
#include <stdio.h> 
#include <unistd.h> 
int main() 
{ 
    struct timeval start, end; 

    long mtime, seconds, useconds;  

    gettimeofday(&start, NULL); 
    usleep(2000); 
    gettimeofday(&end, NULL); 

    seconds = end.tv_sec - start.tv_sec; 
    useconds = end.tv_usec - start.tv_usec; 

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5; 

    printf("Elapsed time: %ld milliseconds\n", mtime); 

    return 0; 
} 
+4

¿Por qué agregas +0.5 a la diferencia? –

+19

@Computer Guru, es una técnica común para redondear valores positivos. Cuando el valor se trunca en un valor entero, cualquier cosa entre 0.0 y 0.4999 ... antes de que la adición se trunque a 0, y entre 0.5 y 0.9999 ... se trunca a 1. –

+0

Esto es genial. Acabo de usar un poco de maquillaje y lo estoy usando. Segundos = End.tv_sec - Start.tv_sec; milisegundos = End.tv_usec - Start.tv_usec; Transcurrido = (Segundos * 1000 + Milisegundos/1000.0) + 0.5; printf ("Segundos transcurridos:% .3f \ n", (float) Elapsed/1000.0); –

18

también recomendar las herramientas que ofrece Aumentar. Ya sea el Boost Timer mencionado, o hackear algo de Boost.DateTime o hay nueva biblioteca se propone en la caja de arena - Boost.Chrono: Este último será un reemplazo para el temporizador y contará con:

  • utilidades vez que el C++ 0x de la biblioteca estándar, incluyendo:
    • plantilla de clase duration
    • plantilla de clase time_point
    • Relojes:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • plantilla de clase timer, con typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • relojes y temporizadores de proceso:
    • process_clock, reales captura, el usuario de la CPU, y tiempos del sistema de la CPU.
    • process_timer, capturando los tiempos reales, usuario-CPU y CPU del sistema.
    • run_timer, reportes convenientes de | process_timer | resultados.
  • La aritmética racional en tiempo de compilación de C++ 0x Standard Library.

Here is the source de la lista de características

+0

gracias ... excepto que lo necesito ahora, no cuando sale C++ 0x/1x – hasen

+0

Por ahora puede usar el Boost Timer y luego migrar con gracia a Chrono cuando es revisado/aceptado. – Anonymous

9

Si usted no necesita el código para ser portátil a los viejos sistemas Unix, puede utilizar clock_gettime(), el cual le dará el tiempo en nanosegundos (si su el procesador es compatible con esa resolución). Es POSIX, pero desde 2001.

4

clock() tiene a menudo una resolución bastante pésima. Si desea medir el tiempo en el nivel de milisegundo, una alternativa es usar clock_gettime(), como explained in this question.

(Recuerde que debe vincular con -lrt en Linux).

55

Tenga en cuenta que clock hace no mide el tiempo del reloj de pared. Eso significa que si su programa tarda 5 segundos, clock no necesariamente medirá 5 segundos, pero podría hacerlo más (su programa podría ejecutar múltiples hilos y por lo tanto podría consumir más CPU que en tiempo real) o menos. Mide una aproximación de Tiempo de CPU utilizado.Para ver la diferencia en cuenta este código

#include <iostream> 
#include <ctime> 
#include <unistd.h> 

int main() { 
    std::clock_t a = std::clock(); 
    sleep(5); // sleep 5s 
    std::clock_t b = std::clock(); 

    std::cout << "difference: " << (b - a) << std::endl; 
    return 0; 
} 

Genera en mi sistema

$ difference: 0 

Debido a que todo lo que hicimos estaba durmiendo y no usar ningún tiempo de CPU! Sin embargo, el uso de gettimeofday conseguimos lo que queremos (?)

#include <iostream> 
#include <ctime> 
#include <unistd.h> 
#include <sys/time.h> 

int main() { 
    timeval a; 
    timeval b; 

    gettimeofday(&a, 0); 
    sleep(5); // sleep 5s 
    gettimeofday(&b, 0); 

    std::cout << "difference: " << (b.tv_sec - a.tv_sec) << std::endl; 
    return 0; 
} 

salidas en mi sistema

$ difference: 5 

Si necesita más precisión, pero desea conseguir el tiempo CPU, entonces se puede considerar el uso de la getrusage función.

+0

⁺¹ acerca de mencionar un 'sueño()' - ya estoy pensado para hacer una pregunta * (¿por qué funciona bien para todos menos yo?!) *, Cuando encontró su respuesta. –

0

Como una actualización, parece que el reloj de Windows() mide el tiempo de reloj de pared (con una precisión CLOCKS_PER_SEC)

http://msdn.microsoft.com/en-us/library/4e2ess30(VS.71).aspx 

mientras que en Linux se mide el tiempo de la CPU a través de núcleos utilizados por el proceso actual

http://www.manpagez.com/man/3/clock 

y (parece, y según lo observado por el cartel original) en realidad con menos precisión que CLOCKS_PER_SEC, aunque tal vez esto depende de la versión específica de Linux.

13

He escrito una clase Timer basada en CTT's answer. Puede ser utilizado de la siguiente manera:

Timer timer = Timer(); 
timer.start(); 
/* perform task */ 
double duration = timer.stop(); 
timer.printTime(duration); 

Aquí es su aplicación:

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/time.h> 
using namespace std; 

class Timer { 
private: 

    timeval startTime; 

public: 

    void start(){ 
     gettimeofday(&startTime, NULL); 
    } 

    double stop(){ 
     timeval endTime; 
     long seconds, useconds; 
     double duration; 

     gettimeofday(&endTime, NULL); 

     seconds = endTime.tv_sec - startTime.tv_sec; 
     useconds = endTime.tv_usec - startTime.tv_usec; 

     duration = seconds + useconds/1000000.0; 

     return duration; 
    } 

    static void printTime(double duration){ 
     printf("%5.6f seconds\n", duration); 
    } 
}; 
+2

Esto es genial, pero los "nseconds" son engañosos porque timeval no contiene nanosegundos, contiene microsegundos, por lo que sugeriría que las personas llamen a esto "useconds". – pho0

+0

Gracias. Corrección hecha. –

1

gettimeofday - el problema es que la voluntad puede tener valores más bajos si se cambia el reloj de hardware (con NTP, por ejemplo,) Boost - no disponible para este proyecto clock() - generalmente devuelve un entero de 4 bytes, lo que significa que es una capacidad baja, y después de un tiempo devuelve números negativos.

Prefiero crear mi propia clase y actualizar cada 10 milisegundos, de esta manera es más flexible, e incluso puedo mejorar para tener suscriptores.

class MyAlarm { 
static int64_t tiempo; 
static bool running; 
public: 
static int64_t getTime() {return tiempo;}; 
static void callback(int sig){ 
    if(running){ 
     tiempo+=10L; 
    } 
} 
static void run(){ running = true;} 
}; 

int64_t MyAlarm::tiempo = 0L; 
bool MyAlarm::running = false; 

para refrescar que utilizo setitimer:

int main(){ 
struct sigaction sa; 
struct itimerval timer; 

MyAlarm::run(); 
memset (&sa, 0, sizeof (sa)); 
sa.sa_handler = &MyAlarm::callback; 

sigaction (SIGALRM, &sa, NULL); 


timer.it_value.tv_sec = 0; 
timer.it_value.tv_usec = 10000; 



timer.it_interval.tv_sec = 0; 
timer.it_interval.tv_usec = 10000; 


setitimer (ITIMER_REAL, &timer, NULL); 
..... 

Mira setitimer y la ITIMER_VIRTUAL y ITIMER_REAL.

No utilice las funciones de alarma o uallarm, tendrá poca precisión cuando su proceso sea un trabajo duro.

0

Me gusta el método Hola Soy de no usar gettimeofday(). Me sucedió en un servidor en ejecución, el administrador cambió la zona horaria. El reloj se actualizó para mostrar el mismo valor local (correcto). Esto hizo que la función time() y gettimeofday() cambiaran 2 horas y todas las marcas de tiempo en algunos servicios se atascaron.

0

Escribí una clase C++ usando timeb.

#include <sys/timeb.h> 
class msTimer 
{ 
public: 
    msTimer(); 
    void restart(); 
    float elapsedMs(); 
private: 
    timeb t_start; 
}; 

funciones de miembro:

msTimer::msTimer() 
{ 
    restart(); 
} 

void msTimer::restart() 
{ 
    ftime(&t_start); 
} 

float msTimer::elapsedMs() 
{ 
    timeb t_now; 
    ftime(&t_now); 
    return (float)(t_now.time - t_start.time) * 1000.0f + 
      (float)(t_now.millitm - t_start.millitm); 
} 

Ejemplo de uso:

#include <cstdlib> 
#include <iostream> 

using namespace std; 

int main(int argc, char** argv) 
{ 
    msTimer t; 
    for (int i = 0; i < 5000000; i++) 
     ; 
    std::cout << t.elapsedMs() << endl; 
    return 0; 
} 

salida en mi equipo es '19'. La precisión de la clase msTimer es del orden de milisegundos. En el ejemplo de uso anterior, se realiza un seguimiento del tiempo total de ejecución tomado por el for -loop. Esta vez incluyó el sistema operativo que ingresa y sale del contexto de ejecución de main() debido a la multitarea.

3

con C++ 11 y std::chrono::high_resolution_clock usted puede hacer esto:

#include <iostream> 
#include <chrono> 
#include <thread> 
typedef std::chrono::high_resolution_clock Clock; 

int main() 
{ 
    std::chrono::milliseconds three_milliseconds{3}; 

    auto t1 = Clock::now(); 
    std::this_thread::sleep_for(three_milliseconds); 
    auto t2 = Clock::now(); 

    std::cout << "Delta t2-t1: " 
       << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() 
       << " milliseconds" << std::endl; 
} 

Salida:

Delta t2-t1: 3 milliseconds 

Enlace a la demo: http://cpp.sh/2zdtu

Cuestiones relacionadas