2013-02-22 19 views
8

Per me è importante un tempismo accurato e ho studiato i 3 tipi di orologi specificati in C++ 11, ovvero , steady_clock e high_resolution_clock. La mia preoccupazione iniziale era verificare se ci sono differenze nell'overhead delle chiamate ai diversi tipi di clock e controllare la risoluzione di ciascun tipo di orologio. Ecco il mio programma di esempio:C++ 11 orologi: g ++ steady_clock :: is_steady == false?

#include <chrono> 
#include <cstdio> 
using namespace std; 
using namespace std::chrono; 

int main(int argc, char **argv) 
{ 
    size_t N = 1e6; 
    if(2 == argc) { 
    sscanf(argv[1], "%zu", &N); 
    } 

#if defined(hrc) 
    typedef high_resolution_clock clock; 
#warning "High resolution clock" 
#elif defined(sc) 
    typedef steady_clock clock; 
#warning "Steady clock" 
#elif defined(sys) 
    typedef system_clock clock; 
#warning "System clock" 
#endif 

    const double resolution = double(clock::period::num)/double(clock::period::den); 

    printf("clock::period: %lf us.\n", resolution*1e6); 
    printf("clock::is_steady: %s\n", clock::is_steady ? "yes" : "no"); 
    printf("Calling clock::now() %zu times...\n", N); 

    // first, warm up 
    for(size_t i=0; i<100; ++i) { 
    time_point<clock> t = clock::now(); 
    } 

    // loop N times 
    time_point<clock> start = clock::now(); 
    for(size_t i=0; i<N; ++i) { 
    time_point<clock> t = clock::now(); 
    } 
    time_point<clock> end = clock::now(); 

    // display duration 
    duration<double> time_span = duration_cast<duration<double>>(end-start); 
    const double sec = time_span.count(); 
    const double ns_it = sec*1e9/N; 
    printf("That took %lf seconds. That's %lf ns/iteration.\n", sec, ns_it); 

    return 0; 
} 

compilo con

$ g++-4.7 -std=c++11 -Dhrc chrono.cpp -o hrc_chrono 
chrono.cpp:15:2: warning: #warning "High resolution clock" [-Wcpp] 
$ g++-4.7 -std=c++11 -Dsys chrono.cpp -o sys_chrono 
chrono.cpp:15:2: warning: #warning "System clock" [-Wcpp] 
$ g++-4.7 -std=c++11 -Dsc chrono.cpp -o sc_chrono 
chrono.cpp:15:2: warning: #warning "Steady clock" [-Wcpp] 

ho compilato con G ++ 4.7.2, e corse su

  • SUSE Linux, il kernel v3.1.10 , CPU i7
  • Sistema embedded Angstrom Linux, kernel v3.1.10, MCU Tegra 2 (ARM Cortex A9).

La prima cosa sorprendente è che i 3 tipi di orologio sono apparentemente sinonimi. Hanno tutti lo stesso periodo (1 microsecondo) e il tempo/chiamata è praticamente lo stesso. Che senso ha specificare 3 tipi di orologi se sono tutti uguali? È solo perché l'implementazione G ++ di chrono non è ancora matura? O forse il kernel 3.1.10 ha solo un orologio accessibile all'utente?

La seconda sorpresa, e questo è enorme, è che steady_clock :: is_steady == false. Sono abbastanza certo che, per definizione, quella proprietà dovrebbe essere vera. Cosa dà ?? Come posso aggirarlo (vale a dire, ottenere un orologio costante)?

Se è possibile eseguire il programma semplice su altre piattaforme/compilatori, sarei molto interessato a conoscere i risultati. Se qualcuno si chiede, è di circa 25 ns/iterazione sul mio Core i7, e 1000 ns/iterazione del Tegra 2.

+0

Umm, sì. Sto solo compilando il codice 3 volte, una volta per ogni tipo di orologio, che è specificato dal flag '-DXXX'. L'ultimo argomento per 'g ++' è solo il nomefile dell'eseguibile, che non importa una leccata. (anche se ho riflettuto sia sul tipo di orologio che sul fatto che il programma stia esercitando la libreria chrono.) –

+0

Mi spiace, ho completamente letto male la riga di comando –

risposta

8

steady_clockè supportato per GCC 4.7 (come indicato dai documenti per il 4.7 rilascio: http://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/manual/manual/status.html#status.iso.2011) e stead_clock::is_steady è vero, ma solo se si costruisce GCC con --enable-libstdcxx-time=rt

Vedi https://stackoverflow.com/a/12961816/981959 per i dettagli di tale opzione di configurazione.

Per GCC 4.9 che verrà attivata automaticamente se il sistema operativo e la libreria C supporta POSIX orologi monotone per clock_gettime (che è vero per GNU/Linux con glibc 2.17 o successiva e per Solaris 10, IIRC)

Qui ci sono i risultati con GCC 4.8 configurati con --enable-libstdcxx-time=rt su un AMD Phenom II X4 905E, 2,5 GHz, ma penso che sia strozzato a 800MHz in questo momento, con Linux 3.6.11, glibc 2,15

$ ./hrc 
clock::period: 0.001000 us. 
clock::is_steady: no 
Calling clock::now() 1000000 times... 
That took 0.069646 seconds. That's 69.645928 ns/iteration. 
$ ./sys 
clock::period: 0.001000 us. 
clock::is_steady: no 
Calling clock::now() 1000000 times... 
That took 0.062535 seconds. That's 62.534986 ns/iteration. 
$ ./sc 
clock::period: 0.001000 us. 
clock::is_steady: yes 
Calling clock::now() 1000000 times... 
That took 0.065684 seconds. That's 65.683730 ns/iteration. 

E con GCC 4.7 senza--enable-libstdcxx-time (quindi lo stesso re sults per tutti e tre i tipi di clock) su ARMv7 Exynos5 con Linux 3.4.0, glibc 2.16

clock::period: 1.000000 us. 
clock::is_steady: no 
Calling clock::now() 1000000 times... 
That took 1.089904 seconds. That's 1089.904000 ns/iteration. 
+1

Vedo in una tua email archiviata (http://gcc.gnu.org/ml/libstdc++/2012-05/msg00085.html) che "Per ottenere la massima risoluzione di clock su GNU/Linux è ancora necessario per usare --enable-libstdcxx-time = rt, _causing un colpo di performance nel codice a thread singolo che usa libstdC++ ._ "Puoi specificare cosa intendi (cioè, quali operazioni avranno un impatto sulle prestazioni?) e come sei arrivato alla conclusione (ad esempio, hai un profilo?)? –

+2

Vedere il primo paragrafo di quella mail: _La ragione è che alcune o tutte quelle chiamate sono definite in librt, ma su GNU/Linux se libstdC++. Quindi collega a librt.so quindi si collega anche a libpthread.so e quindi __gthread_active_p () restituirà sempre true, causando un blocco aggiuntivo nelle app a thread singolo. Il conteggio dei riferimenti in libstdC++ utilizzerà op atomici o mutex nei programmi che utilizzano più thread, in base al fatto che il programma si colleghi a libpthread o meno. –

7

Se è possibile eseguire il semplice programma su altre piattaforme/compilatori, io sarei molto interessato a conoscere i risultati.

Mac OS X 10.8, clang ++/libC++, -O3, 2,8 GHz Core i5:

High resolution clock 

clock::period: 0.001000 us. 
clock::is_steady: yes 
Calling clock::now() 1000000 times... 
That took 0.021833 seconds. That's 21.832827 ns/iteration. 

System clock 

clock::period: 1.000000 us. 
clock::is_steady: no 
Calling clock::now() 1000000 times... 
That took 0.041930 seconds. That's 41.930000 ns/iteration. 

Steady clock 

clock::period: 0.001000 us. 
clock::is_steady: yes 
Calling clock::now() 1000000 times... 
That took 0.021478 seconds. That's 21.477953 ns/iteration. 

steady_clock e system_clock sono tenuti a essere tipi distinti. steady_clock::is_steady è richiesto per essere true. high_resolution_clock può essere un tipo distinto o un alias di steady_clock o system_clock. system_clock::rep deve essere un tipo firmato.

4

In base a GNU's site, GNU libstdC++ non supporta ancora steady_clock. Ecco perché steady_clock::is_steady è falso.

Ecco relativa sezione della lista supporto:

20.11.7.1 Class system_clock   Y 
20.11.7.2 Class steady_clock   N Support old monotonic_clock spec instead 
20.11.7.3 Class high_resolution_clock Y 
+0

Ah, ok, sospettavo qualcosa del genere. Almeno è ancora monotono se leggo bene. –

+2

Questi documenti non sono aggiornati, 'steady_clock' _is_ supportato per GCC 4.7 ma solo se si crea GCC con' --enable-libstdcxx-time' –

+3

Il commento _non dice che è monotono, dice che la classe ha il vecchio nome 'monotonic_clock' da precedenti bozze di C++ 0x ... in effetti non è vero per GCC 4.7 e successivi, i documenti sono mesi non aggiornati, la classe è chiamata' steady_clock' ma 'is_steady' è vera solo quando' - enable-libstdcxx-time' è usato –

Problemi correlati