2013-02-22 5 views
8

Для меня важно точное время, и я изучал 3 типа часов, указанных в C++ 11, а именно system_clock, steady_clock и high_resolution_clock. Моя первоначальная проблема заключалась в тестировании, если есть какая-либо разница в накладных расходах на разные типы часов и проверка разрешения каждого типа часов. Вот мой пример программы:C++ 11 clocks: g ++ stable_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; 
} 

я скомпилировать его с

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

I скомпилированные с G ++ 4.7.2, и побежал на

  • SUSE Linux, ядро ​​v3.1.10 , CPU i7
  • Встроенная система Angstrom Linux, ядро ​​v3.1.10, MCU Tegra 2 (ARM Cortex A9).

Первое, что удивило то, что 3 типа часов, по-видимому, являются синонимами. Все они имеют одинаковый период (1 микросекунду), а время/звонок практически одинаковы. Какой смысл указывать 3 типа часов, если они все одинаковые? Это только потому, что реализация G ++ chrono еще не созрела? Или, может быть, у ядра 3.1.10 есть только один доступный пользователю чат?

Второй сюрприз, и это огромный, является то, что stable_clock :: is_steady == false. Я вполне уверен, что по определению это свойство должно быть истинным. Что дает?? Как я могу обойти это (т. Е. Добиться постоянных часов)?

Если вы можете запустить простую программу на других платформах/компиляторах, мне было бы очень интересно узнать результаты. Если кто-то интересно, это около 25 нс/итерацию на моем Core i7, и 1000 нс/итерация на Tegra 2.

+0

Умм, да. Я просто компилирую код 3 раза, один раз для каждого типа часов, который указан флагом '-DXXX'. Последний аргумент 'g ++' - это только имя исполняемого файла, что не имеет значения. (хотя я думаю, что он отражает как тот тип часов, так и тот факт, что программа использует библиотеку хроно.) –

+0

Извините, я полностью неправильно прочитал командную строку –

ответ

8

steady_clockявляется поддерживается для GCC 4.7 (как показано на документы 4.7 релиз: http://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/manual/manual/status.html#status.iso.2011) и stead_clock::is_steady это верно, но только если вы строите GCC с --enable-libstdcxx-time=rt

См https://stackoverflow.com/a/12961816/981959 подробности этой опции конфигурации.

Для GCC 4.9 будет включена автоматически, если ваша ОС и библиотека C поддерживает POSIX монотонные часы для clock_gettime (что верно для GNU/Linux с Glibc 2,17 или более поздней версии и для Solaris 10, IIRC)

Здесь находятся результаты с GCC 4.8 сконфигурировано с --enable-libstdcxx-time=rt на AMD Phenom II X4 905e, 2.5GHz, но я думаю, что задушил 800МГц сейчас работает 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. 

И с GCC 4.7 без--enable-libstdcxx-time (так же, sults для всех трех типов часов) на ARMv7 Exynos5 под управлением 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

Я вижу в архиве вашего письма (http://gcc.gnu.org/ml/libstdc++/2012-05/msg00085.html), что «Чтобы получить максимальное разрешение часов на GNU/Linux по-прежнему необходимо использовать --enable-libstdcxx-time = rt, _causing для достижения производительности в однопоточном коде, который использует libstdC++ ._ «Можете ли вы указать, что вы имеете в виду (то есть, какие операции будут иметь производительность?) и как вы пришли к заключению (т. е. профиль?)? –

+2

См. Первый абзац этой почты: Причина в том, что некоторые или все эти вызовы определены в librt, но на GNU/Linux, если libstdC++, поэтому ссылки на librt.so затем также ссылаются на libpthread.so и поэтому __gthread_active_p () всегда будет возвращать значение true, что приведет к дополнительной блокировке в однопоточных приложениях. _ Счетчик ссылок в libstdC++ будет использовать атомарные ops или мьютексы в программах, которые используют несколько потоков, как определено, связана ли программа с libpthread или нет. –

7

Если вы можете запустить простую программу на других платформ/компиляторов, я бы очень заинтересованы знать результаты.

Mac OS X 10.8, лязг ++/LibC++, -O3, 2,8 ГГц 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 и system_clock должны быть различные типы. steady_clock::is_steady должен быть true. high_resolution_clock может быть отдельным типом или псевдонимом steady_clock или system_clock. system_clock::rep должен быть подписанным типом.

4

Согласно GNU's site, GNU libstdC++ не поддерживает steady_clock. Вот почему steady_clock::is_steady является ложным.

Вот соответствующий раздел поддержки контрольного списка:

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

А, ок, я подозревал что-то в этом роде. По крайней мере, это все еще монотонно, если я читаю это право. –

+2

Эти документы устарели, 'stable_clock' _is_ поддерживается для GCC 4.7, но только если вы создаете GCC с' --enable-libstdcxx-time' –

+3

Комментарий _doesn't_ говорит, что он монотонен, он говорит, что класс имеет старое имя 'monotonic_clock' из более ранних проектов C++ 0x ... на самом деле это неверно для GCC 4.7 и более поздних версий, документы являются устаревшими месяцами, класс называется' stable_clock', но 'is_steady' - это только true, когда' - enable-libstdcxx-time' –