2013-02-22 19 views
8

So genaues Timing ist wichtig für mich, und ich war die Untersuchung der drei Arten von Uhren angegeben in C++ 11, nämlich system_clock, steady_clock und high_resolution_clock. Meine erste Sorge war zu testen, ob es einen Unterschied im Anruf-Overhead zu den verschiedenen Arten von Uhren gibt, und um die Auflösung von jedem Typ von Uhr zu überprüfen. Hier ist mein Beispielprogramm:C++ 11 Takte: 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; 
} 

ich kompilieren es mit

$ 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] 

ich mit G ++ kompiliert 4.7.2, und es lief auf

  • SUSE Linux Kernel v3.1.10 , CPU i7
  • Angstrom Linux eingebettetes System, Kernel v3.1.10, MCU Tegra 2 (ARM Cortex A9).

Die erste überraschende Sache war, dass die 3 Arten der Uhr anscheinend Synonyme sind. Sie alle haben die gleiche Periode (1 Mikrosekunde), und die Zeit/Anruf ist praktisch gleich. Was ist der Sinn der Angabe von 3 Arten von Uhren, wenn sie alle gleich sind? Ist das nur, weil die G ++ - Implementierung von chrono noch nicht ausgereift ist? Oder vielleicht hat der 3.1.10 Kernel nur eine benutzerzugängliche Uhr?

Die zweite Überraschung, und das ist riesig, ist, dass steady_clock :: is_steady == false. Ich bin ziemlich sicher, dass diese Eigenschaft per Definition wahr sein sollte. Was gibt?? Wie kann ich das umgehen (dh eine stabile Uhr erreichen)?

Wenn Sie das einfache Programm auf anderen Plattformen/Compilern ausführen können, wäre ich sehr interessiert, die Ergebnisse zu kennen. Wenn jemand fragt, es ist etwa 25 ns/Iteration auf meinem Core i7 und 1000 ns/Iteration auf den Tegra 2.

+0

Umm, yeah. Ich kompiliere den Code nur 3 Mal, einmal für jede Art von Uhr, die durch das '-DXXX'-Flag spezifiziert wird. Das letzte Argument zu 'g ++' ist nur der Dateiname der ausführbaren Datei, was keinen Unterschied macht. (obwohl ich es sowohl die Art der Uhr und die Tatsache reflektieren, dass das Programm die Chrono-Bibliothek ausübt.) ​​ –

+0

Sorry, ich habe die Befehlszeile komplett falsch gelesen –

Antwort

8

steady_clockwird für GCC 4.7 unterstützt (wie durch die Dokumentation für die 4 gezeigt.7 Release: http://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/manual/manual/status.html#status.iso.2011) und stead_clock::is_steady gilt aber nur, wenn Sie GCC bauen mit --enable-libstdcxx-time=rt

Siehe https://stackoverflow.com/a/12961816/981959 für Einzelheiten dieser Konfigurationsoption.

Für 4,9 GCC wird es automatisch aktiviert werden, wenn Ihr Betriebssystem und C-Bibliothek unterstützt POSIX monotone Uhren für clock_gettime (die für GNU/Linux mit glibc 2.17 oder höher und für Solaris 10, IIRC wahr ist)

Hier sind die Ergebnisse mit GCC 4.8 mit --enable-libstdcxx-time=rt auf einem AMD Phenom II X4 905e, 2,5 GHz konfiguriert, aber ich denke, es ist jetzt zu 800 MHz gedrosselt ist, Linux 3.6.11, 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. 

Und mit GCC 4.7 ohne glibc --enable-libstdcxx-time (also das gleiche re sult für alle drei Uhrentypen) auf ARMv7 Exynos5 mit Linux 3.4.0, glibc 2.16

+1

Ich sehe in einer archivierten E-Mail von Ihnen (http://gcc.gnu.org/ml/libstdc++/2012-05/msg00085.html), dass "Um maximale Uhrzeitauflösung auf GNU/Linux ist es immer noch notwendig, verwenden --enable-libstdcxx-time = rt, _causing einen Leistungstreffer in single-threaded-Code, der libstdC++ verwendet. "Können Sie angeben, was Sie meinen (dh welche Operationen werden einen Leistungseinbruch haben?) und wie bist du zu dem Schluss gekommen (dh, hast du dich profiliert?)? –

+2

Siehe den ersten Absatz dieser Mail: _Der Grund ist, dass einige oder alle dieser Aufrufe in librt definiert sind, aber auf GNU/Linux, wenn libstdC++. So Links zu librt.so dann auch Links zu libpthread.so und so __gthread_active_p () gibt immer true zurück, was in single-threaded apps zu einer zusätzlichen Sperre führt. _ Die Referenzzählung in libstdC++ verwendet atomare Ops oder Mutexe in Programmen, die mehrere Threads verwenden, abhängig davon, ob das Programm mit libpthread verknüpft ist oder nicht. –

7

Wenn Sie das einfache Programm auf anderen Plattformen/Compiler laufen, ich wäre sehr interessiert, um die Ergebnisse zu wissen.

Mac OS X 10.8, Klirren ++/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 und system_clock erforderlich sind verschiedene Typen sein. steady_clock::is_steady muss true sein. high_resolution_clock kann ein eindeutiger Typ oder ein Alias ​​von steady_clock oder system_clock sein. system_clock::rep muss ein signierter Typ sein.

4

Nach unterstützt GNU libstdC++ steady_clock noch nicht. Deshalb ist steady_clock::is_steady falsch.

Hier ist der entsprechende Abschnitt des Stütz Prüfliste:

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 ich vermute so etwas. Zumindest ist es immer noch monoton, wenn ich das richtig lese. –

+2

Diese Dokumente sind veraltet, 'steady_clock' _is_ wird für GCC 4.7 unterstützt, aber nur wenn man GCC mit' --enable-libstdcxx-time' erstellt –

+3

Der Kommentar _doesnot_ sagt, dass es monoton ist, es besagt, dass die Klasse den alten Namen hat 'monotonic_clock' aus früheren C++ 0x Drafts ... in der Tat gilt das nicht für GCC 4.7 und später, die Dokumente sind Monate veraltet, die Klasse heißt' steady_clock', aber 'is_steady' ist nur wahr wenn' - enable-libstdcxx-time' wird verwendet –