2013-02-22 24 views
8

Tak dokładne ustawienie jest dla mnie ważne, a ja badałem 3 typy zegarów określone w C++ 11, a mianowicie system_clock, steady_clock i high_resolution_clock. Moją początkową obawą było sprawdzenie, czy istnieje różnica w obciążeniu połączenia dla różnych typów zegarów i sprawdzenie rozdzielczości każdego typu zegara. Oto mój przykładowy program:C++ 11 zegarów: 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; 
} 

skompilować go z

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

skompilowany zg ++ 4.7.2, a prowadził ją na

  • SUSE Linux kernel v3.1.10 , CPU i7
  • Wbudowany system Angstrom Linux, jądro v3.1.10, MCU Tegra 2 (ARM Cortex A9).

Pierwszym zaskoczeniem było to, że 3 rodzaje zegara są najwyraźniej synonimami. Wszystkie mają ten sam okres (1 mikro sekunda), a czas/połączenie są praktycznie takie same. Jaki jest sens określania 3 typów zegarów, jeśli wszystkie są takie same? Czy to dlatego, że implementacja G ++ z chrono nie jest jeszcze dojrzała? A może jądro 3.1.10 ma tylko jeden zegar dostępny dla użytkownika?

Drugą niespodzianką, która jest ogromna, jest to, że steady_clock :: is_steady == false. Jestem prawie pewien, że z definicji ta własność powinna być prawdziwa. Co daje?? Jak mogę obejść to (tj. Osiągnąć stały zegar)?

Jeśli możesz uruchomić prosty program na innych platformach/kompilatorach, byłbym bardzo zainteresowany poznaniem wyników. Jeśli ktoś zastanawia się, to około 25 ns/iteracji na moim Core i7 i 1000 NS/iteracja na Tegra 2.

+0

Umm, tak. Właśnie kompiluję kod 3 razy, raz dla każdego typu zegara, który jest określony przez flagę '-DXXX'. Ostatnim argumentem na 'g ++' jest nazwa pliku wykonywalnego, która nie ma znaczenia. (chociaż mam to odzwierciedla zarówno typ zegara, jak i fakt, że program wykonuje bibliotekę chrono). –

+0

Przepraszamy, całkowicie błędnie przeczytałem wiersz polecenia –

Odpowiedz

8

steady_clockjest obsługiwane GCC 4,7 (jak pokazano przez Dokumenty do 4.7 Release: http://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/manual/manual/status.html#status.iso.2011) i stead_clock::is_steady jest prawdą, ale tylko jeśli budować GCC z --enable-libstdcxx-time=rt

Zobacz https://stackoverflow.com/a/12961816/981959 o szczegóły tej opcji konfiguracji.

Dla GCC 4.9 zostanie włączona automatycznie, gdy system operacyjny i C biblioteka obsługuje POSIX monotoniczne zegary dla clock_gettime (co jest prawdą dla GNU/Linux z glibc 2.17 lub nowszej oraz Solaris 10, IIRC)

Oto wyniki z GCC 4.8 skonfigurowany --enable-libstdcxx-time=rt na AMD Phenom II X4 905e, 2.5GHz, ale myślę, że to zdławiony do 800MHz teraz, systemem 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. 

I z GCC 4.7 bez--enable-libstdcxx-time (czyli ten sam re na wszystkich trzech typach zegara) na ARMv7 Exynos5 z systemem 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

Widzę w twoim zarchiwizowanym e-mailu (http://gcc.gnu.org/ml/libstdc++/2012-05/msg00085.html), że "Aby uzyskać maksymalną rozdzielczość zegara na GNU/Linux nadal jest konieczne, aby użyć --enable-libstdcxx-time = rt, _causing hit wydajności w jednowątkowego kodu, który używa libstdC++ ._ "Czy możesz określić, co masz na myśli (np. Jakie operacje będą miały działanie?) i jak doszedłeś do wniosku (np. czy profilowałeś?)? –

+2

Zobacz pierwszy akapit tej wiadomości: _ Powód jest taki, że niektóre lub wszystkie z tych połączeń są zdefiniowane w librt, ale na GNU/Linux, jeśli libstdC++., Więc linki do librt.so, to także linki do libpthread.so, a więc __gthread_active_p () zawsze zwróci wartość true, powodując dodatkowe blokowanie w aplikacjach jednowątkowych. Liczenie odwołań w bibliotece libstdC++ będzie używało opcji atomowych lub muteksów w programach używających wielu wątków, zależnie od tego, czy program łączy się z libpthread, czy nie. –

7

jeśli można uruchomić prosty program na innych platformach/kompilatory, chciałbym być bardzo zainteresowani poznaniem wyników.

Mac OS X 10.8, dzyń ++/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 i system_clock muszą być odrębne rodzaje. steady_clock::is_steady musi być true. high_resolution_clock może być odrębnym rodzajem lub aliasem steady_clock lub system_clock. system_clock::rep musi być typem podpisanym.

4

Zgodnie z GNU's site, GNU libstdC++ nie obsługuje jeszcze steady_clock. Dlatego steady_clock::is_steady jest fałszywe.

Oto odpowiedniej sekcji nośnej kontrolnej:

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 Podejrzewałem coś takiego. Przynajmniej to jest monotoniczne, jeśli dobrze to rozumiem. –

+2

Dokumenty te są nieaktualne, 'steady_clock' _is_ jest obsługiwany w GCC 4.7, ale tylko wtedy, gdy kompilujesz GCC z opcją' --enable-libstdcxx-time' –

+3

Komentarz nie mówi, że jest monotoniczny, mówi, że klasa ma starą nazwę 'monotonic_clock' z wcześniejszych wersji C++ 0x ... w rzeczywistości nie jest to prawdą w GCC 4.7 i późniejszych, dokumenty są miesiące przestarzałe, klasa nazywa się' steady_clock', ale 'is_steady' jest prawdziwe tylko gdy' - enable-libstdcxx-time' jest używany –