C ++ che ottiene il tempo di millisecondi su Linux - clock () non sembra funzionare correttamente


102

Su Windows, clock()restituisce il tempo in millisecondi, ma su questa macchina Linux su cui sto lavorando, lo arrotonda al 1000 più vicino in modo che la precisione sia solo al livello "secondo" e non al livello dei millisecondi.

Ho trovato una soluzione con Qt usando la QTimeclasse, istanziando un oggetto e chiamandolo start()poi chiamando elapsed()per ottenere il numero di millisecondi trascorsi.

Sono stato fortunato perché sto lavorando con Qt per cominciare, ma mi piacerebbe una soluzione che non si basi su librerie di terze parti,

Non esiste un modo standard per farlo?

AGGIORNARE

Per favore, non consigliare Boost ..

Se Boost e Qt possono farlo, sicuramente non è magia, deve esserci qualcosa di standard che stanno usando!


2
A proposito di modifica, ma farlo in modo portatile è un po 'difficile.
Anonimo

Risposte:


37

Potresti usare gettimeofday all'inizio e alla fine del tuo metodo e quindi differenziare le due strutture di ritorno. Otterrai una struttura come la seguente:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

EDIT: Come suggeriscono i due commenti seguenti, clock_gettime (CLOCK_MONOTONIC) è una scelta molto migliore se lo hai disponibile, che dovrebbe essere quasi ovunque in questi giorni.

EDIT: qualcun altro ha commentato che puoi anche usare il moderno C ++ con std :: chrono :: high_resolution_clock, ma non è garantito che sia monotono. Usa invece steady_clock.


38
terribile per un lavoro serio. Grandi problemi due volte l'anno, quando qualcuno fa appuntamenti e, naturalmente, la sincronizzazione NTP. Usa clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: l'ora di UNIX non cambia due volte all'anno. O anche una volta all'anno. Ma sì, CLOCK_MONOTONICè ottimo per evitare aggiustamenti dell'ora di sistema localizzati.
Gare di leggerezza in orbita

138
#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
Perché aggiungi +0,5 alla differenza?
Mahmoud Al-Qudsi,

19
@Computer Guru, è una tecnica comune per arrotondare i valori positivi. Quando il valore viene troncato a un valore intero, qualsiasi valore compreso tra 0,0 e 0,4999 ... prima che l'addizione venga troncata a 0 e tra 0,5 e 0,9999 ... viene troncato a 1.
Mark Ransom

8
tv_usec non è millisecondi, è microcsecondi.
NebulaFox

13
terribile per un lavoro serio. Grandi problemi due volte l'anno, quando qualcuno fa appuntamenti e, naturalmente, sincronizzazione NTP
AndrewStone

14
@AndrewStone ha ragione, usa clock_gettime (2) con CLOCK_REALTIME per confrontare i tempi sullo stesso computer. Dalla manpage gettimeofday (2): POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, potresti aggiornare l'esempio cambiando struct timevalin struct timespec, e gettimeofday(&start, NULL)in in clock_gettime(CLOCK_MONOTONIC, &start)modo che le persone non abbiano problemi?
Bobby Powers

58

Si prega di notare che clocksi fa non misurano il tempo orologio da parete. Ciò significa che se il tuo programma impiega 5 secondi, clocknon misurerà necessariamente 5 secondi, ma potrebbe di più (il tuo programma potrebbe eseguire più thread e quindi potrebbe consumare più CPU del tempo reale) o meno. Misura un'approssimazione del tempo di CPU utilizzato. Per vedere la differenza considera questo codice

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

Emette sul mio sistema

$ difference: 0

Perché tutto ciò che abbiamo fatto è stato dormire e non utilizzare il tempo della CPU! Tuttavia, utilizzando gettimeofdayotteniamo ciò che vogliamo (?)

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

Uscite sul mio sistema

$ difference: 5

Se hai bisogno di maggiore precisione ma desideri ottenere il tempo della CPU , puoi considerare di utilizzare la getrusagefunzione.


⁺¹ sulla menzione a sleep()- Ho già pensato di fare una domanda (perché funziona bene per tutti tranne me ?!) , quando ho trovato la tua risposta.
Hi-Angel

18

Consiglio anche gli strumenti offerti da Boost. O il menzionato Boost Timer, o hackerare qualcosa da Boost.DateTime o c'è una nuova libreria proposta nella sandbox - Boost.Chrono : Quest'ultima sarà una sostituzione per il Timer e presenterà:

  • Le utilità temporali della libreria standard C ++ 0x, tra cui:
    • Modello di classe duration
    • Modello di classe time_point
    • orologi:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Modello di classe timer, con typedef:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Orologi e timer di processo:
    • process_clock, catturando i tempi reali, CPU utente e CPU di sistema.
    • process_timer, catturando i tempi reali, CPU utente e CPU di sistema trascorsi.
    • run_timer, comodo rapporto di | process_timer | risultati.
  • Aritmetica razionale in fase di compilazione della libreria standard C ++ 0x.

Ecco la fonte dell'elenco delle caratteristiche


Per ora puoi utilizzare il Boost Timer e quindi migrare con grazia a Chrono quando viene esaminato / accettato.
Anonimo

13

Ho scritto una Timerlezione basata sulla risposta di CTT . Può essere utilizzato nel modo seguente:

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

Ecco la sua implementazione:

#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
Questo è bello ma il "nseconds" è fuorviante perché timeval non contiene nanosecondi, contiene microsecondi, quindi suggerirei alle persone di chiamarlo "useconds".
pho0

Grazie. Correzione effettuata.
Chris Redford,

9

Se non hai bisogno che il codice sia trasferibile ai vecchi Unix, puoi usare clock_gettime (), che ti darà il tempo in nanosecondi (se il tuo processore supporta quella risoluzione). È POSIX, ma dal 2001.


4

clock () ha una risoluzione spesso piuttosto scadente. Se vuoi misurare il tempo a livello di millisecondi, un'alternativa è usare clock_gettime (), come spiegato in questa domanda.

(Ricorda che devi collegarti a -lrt su Linux).


4

Con C ++ 11 e std::chrono::high_resolution_clockpuoi farlo:

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

Produzione:

Delta t2-t1: 3 milliseconds

Link alla demo: http://cpp.sh/2zdtu


2

clock () non restituisce millisecondi o secondi su linux. Di solito clock () restituisce microsecondi su un sistema Linux. Il modo corretto di interpretare il valore restituito da clock () è dividerlo per CLOCKS_PER_SEC per capire quanto tempo è passato.


non nella scatola su cui sto lavorando! inoltre, sto dividendo per CLOCKS_PER_SEC, ma è inutile perché la risoluzione è solo al secondo
hasen

beh, per essere onesti, le unità sono microsecondi (CLOCKS_PER_SEC è 1000000 su tutti i sistemi POSIX). Ha solo una risoluzione in secondi. :-P.
Evan Teran,

1

Questo dovrebbe funzionare ... testato su 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ì ... eseguilo due volte e sottrai ...


1

Nello standard POSIX clockha il suo valore di ritorno definito in termini del simbolo CLOCKS_PER_SEC e un'implementazione è libera di definirlo in qualsiasi modo conveniente. Sotto Linux, ho avuto fortuna con la times()funzione.


1

gettimeofday - il problema è che può avere valori più bassi se cambi il tuo orologio hardware (con NTP per esempio) Boost - non disponibile per questo progetto clock () - di solito restituisce un numero intero di 4 byte, il che significa che è una capacità bassa, e dopo qualche tempo restituisce numeri negativi.

Preferisco creare la mia classe e aggiornare ogni 10 millisecondi, quindi in questo modo è più flessibile e posso persino migliorarla per avere abbonati.

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;

per aggiornarlo utilizzo 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); 
.....

Guarda setitimer e ITIMER_VIRTUAL e ITIMER_REAL.

Non utilizzare le funzioni di allarme o ualarm, avrai una bassa precisione quando il tuo processo diventa un duro lavoro.



0

Come aggiornamento, sembra che su Windows clock () misuri il tempo dell'orologio da parete (con precisione CLOCKS_PER_SEC)

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

mentre su Linux misura il tempo della CPU tra i core utilizzati dal processo corrente

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

e (sembra, e come notato dal poster originale) in realtà con meno precisione di CLOCKS_PER_SEC, anche se forse questo dipende dalla versione specifica di Linux.


0

Mi piace il metodo Hola Soy di non usare gettimeofday (). A me è successo su un server in esecuzione l'amministratore ha cambiato il fuso orario. L'orologio è stato aggiornato per mostrare lo stesso valore locale (corretto). Ciò ha causato lo spostamento di 2 ore delle funzioni time () e gettimeofday () e tutti i timestamp in alcuni servizi si sono bloccati.


0

Ho scritto una C++lezione usando timeb.

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

Funzioni membro:

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

Esempio di utilizzo:

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

L'output sul mio computer è "19". La precisione della msTimerclasse è dell'ordine dei millisecondi. Nell'esempio di utilizzo sopra, forviene tracciato il tempo totale di esecuzione occupato dal loop. Questa volta includeva il sistema operativo che entrava e usciva dal contesto di esecuzione a main()causa del multitasking.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.