2012-01-28 13 views
5

Sto provando a misurare intervalli di tempo brevi, nell'ordine di pochi millisecondi. Questo risulta essere un compito non banale, poiché l'onnipresente funzione time() funziona con precisione di interi secondi. Dopo alcune ricerche sono uscito con i quattro metodi visti nel codice di esempio riportato di seguito:Misurazione di intervalli di tempo brevi in ​​C su Ubuntu/VMware

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

int main(int argc, char *argv[]) 
{ 
    clock_t t0, t1; 
    double dt0; 

    struct timespec t2, t3; 
    double dt1; 

    struct timespec t4, t5; 
    double dt2; 

    struct timeval t6, t7; 
    double dt3; 

    volatile long long i; 

    t2.tv_sec = 0; 
    t2.tv_nsec = 0; 
    clock_settime(CLOCK_MONOTONIC, &t2); 
    clock_settime(CLOCK_REALTIME, &t2); 

    t0 = clock(); 
    clock_gettime(CLOCK_REALTIME, &t2); 
    clock_gettime(CLOCK_MONOTONIC, &t4); 
    gettimeofday(&t6, NULL); 

    getchar(); 
    for (i=0; i<1e9; i++) {}; 

    gettimeofday(&t7, NULL); 
    clock_gettime(CLOCK_MONOTONIC, &t5); 
    clock_gettime(CLOCK_REALTIME, &t3); 
    t1 = clock(); 

    dt0 = (double) (t1 - t0)/CLOCKS_PER_SEC; 
    dt1 = (double) (t3.tv_nsec - t2.tv_nsec)/1e9; 
    dt2 = (double) (t5.tv_nsec - t4.tv_nsec)/1e9; 
    dt3 = (double) (t7.tv_usec - t6.tv_usec)/1e6; 

    printf("1. clock():   [0]=%10.0f, [1]=%10.0f, [1-0]=%10.6f sec\n", (double) t0, (double) t1, dt0); 
    printf("2. clock_gettime(R): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t2.tv_nsec, (long) t3.tv_nsec, dt1); 
    printf("3. clock_gettime(M): [2]=%10ld, [3]=%10ld, [3-2]=%10f sec\n", (long) t4.tv_nsec, (long) t5.tv_nsec, dt2); 
    printf("4. gettimeofday(): [4]=%10ld, [5]=%10ld, [5-4]=%10f sec\n", (long) t6.tv_usec, (long) t7.tv_usec, dt3); 

    return 0; 
} 

Poi, ho compilato ed eseguito con:

gcc -lrt -o timer.e timer.c; time ./timer.e 

ho usato la chiamata getchar() di introdurre un paio di secondi di ritardo per vedere una differenza tra real e user report in tempo, e il risultato è stato:

1. clock():   [0]=   0, [1]= 3280000, [1-0]= 3.280000 sec 
2. clock_gettime(R): [2]= 823922476, [3]= 478650549, [3-2]= -0.345272 sec 
3. clock_gettime(M): [2]= 671137949, [3]= 325864897, [3-2]= -0.345273 sec 
4. gettimeofday(): [4]= 823924, [5]= 478648, [5-4]= -0.345276 sec 

real 0m6.659s 
user 0m3.280s 
sys  0m0.010s 

Come si può vedere, l'unico risultato significativo è la correlazione tra il metodo 1 e il tempo user riportato dal comando time.

Questo porta un paio di domande: 1. Perché i risultati 2-4 non hanno senso? 2. Come si misura il tempo reale trascorso durante l'esecuzione di un programma, ad esempio il numero report?

Il mio ambiente è Ubuntu 10.04 LTS 64-bit su VMware su Windows 7 su un laptop HP basato su AMD.

+0

Se questo è a scopo di test, si potrebbe trovare utile per aumentare il numero di iterazioni. Ciò ovviamente renderà il test più lungo, ma potrà utilizzare misure di temporizzazione a risoluzione più bassa. –

+0

@MichaelMior - è usato per un benchmarking molto approssimativo - Sto cercando di confrontare il tempo di esecuzione di un algoritmo che viene eseguito sull'host (linux) e su un acceleratore hardware che è connesso via USB. In entrambi i casi, il chiamante è lo stesso programma, il programma host, e ho bisogno di un modo per ottenere il tempo totale in cui "si siede e aspetta" solo perché l'hardware esterno finisca il suo lavoro. Questo è il motivo per cui clock() non è la risposta, b/c non conta per il tempo di attesa (come dimostrato qui dalla chiamata getchar()). – ysap

risposta

12

Sei sulla strada giusta con clock_gettime().

Tuttavia, è necessario sbarazzarsi di quelle chiamate clock_settime(): è sufficiente chiamare clock_gettime() prima e dopo un blocco di codice e osservare la differenza.

Inoltre, quando si calcola la differenza, è necessario prendere in considerazione sia tv_sec e tv_nsec; il tuo codice attuale guarda solo il componente del nanosecondo e ignora i secondi interi.

Sul mio sistema Ubuntu il seguente codice dà una misura abbastanza precisa del tempo necessario per eseguire il ciclo:

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

int main(int argc, char *argv[]) 
{ 
    struct timespec t2, t3; 
    double dt1; 

    volatile long long i; 

    clock_gettime(CLOCK_MONOTONIC, &t2); 
    for (i=0; i<1e9; i++) {}; 
    clock_gettime(CLOCK_MONOTONIC, &t3); 
    //time in seconds 
    dt1 = (t3.tv_sec - t2.tv_sec) + (double) (t3.tv_nsec - t2.tv_nsec) * 1e-9; 
    printf("%f\n", dt1); 

    return 0; 
} 
+0

Grazie! Questa correzione fa quello che sto cercando. Di tanto in tanto si manca solo di vedere l'ovvio. Ho pensato che i campi _sec e _nsec indurivano gli stessi dati con una precisione diversa, ma ora vedo che sono le parti intere e le parti nanometriche del timestamp. – ysap

1

Qualche suggerimento circa la misurazione del tempo verso il basso per micro e persino nano secondi http://en.wikipedia.org/wiki/Time_Stamp_Counter

+0

Grazie per aver indicato una spiegazione su rdtsc. Può essere utile in alcuni contesti, ma sto cercando di capire perché il codice che ho scritto non dia il risultato atteso. – ysap

1

Le tue chiamate clock_settime non corrispondono a ciò che pensi che facciano. Se avessi il permesso, imposterebbero semplicemente l'orologio del sistema su 0, probabilmente non quello che desideri. Quasi tutte le funzioni POSIX hanno un valore di ritorno che ti dice se la chiamata è riuscita. Di solito è una cattiva idea ignorare quel valore. Per il vostro caso, in particolare, penso che avrebbe dovuto dare questo valore come si può trovare nella pagina man:

EPERM clock_settime() non ha il permesso di impostare l'orologio indicato.

Per fortuna non hanno i permessi per impostare l'orologio nel modo più semplice questo :)

+0

Ho aggiunto il settime dopo aver ricevuto gli strani risultati di gettime. Apparentemente, non ha avuto alcun effetto sul risultato. – ysap

+0

@ysap, questo è esattamente quello che sto dicendo. Non ha alcun effetto sul risultato poiché ** fallisce **. Altrimenti avrebbe conseguenze drammatiche per la tua macchina, impostando il tuo orologio di sistema su qualcosa come il 1 gennaio 1970 o giù di lì. Non farlo. Controlla il ritorno delle chiamate di sistema per vedere se hanno successo o meno. –

+0

Sì, punto preso e il codice è stato rimosso dal programma. – ysap

Problemi correlati