Виміряйте час в Linux - час проти годинника проти getrusage проти clock_gettime vs gettimeofday vs timespec_get?


148

Серед тимчасових функцій, time, clock getrusage, clock_gettime, gettimeofdayі timespec_getя хочу , щоб чітко зрозуміти , як вони реалізуються , і які їхні повернені значення для того , щоб знати , в якій ситуації я повинен використовувати їх.

Спочатку нам потрібно класифікувати функції, що повертають значення настінного годинника, порівняти з функціями, що повертають значення або значення потоку . gettimeofdayповертає значення настінного годинника, clock_gettimeповертає значення настінного годинника або значення процесу чи потоку залежно від Clockпараметра, переданого йому. getrusageі clockповертати значення процесу.

Тоді друге питання стосується реалізації цих функцій і, як наслідок, їх точності. Який апаратний чи програмний механізм використовує ці функції.

Здається, що getrusageвикористовується лише галочка ядра (зазвичай довжиною 1 мс) і, як наслідок, не може бути більш точним, ніж мс. Це право? Тоді getimeofdayфункція, здається, використовує найточніше наявне обладнання. Як наслідок, його точність зазвичай є мікросекундою (не може бути більше через API) на останніх апаратних засобах. Про що clock, сторінка man говорить про "наближення", що це означає? А як щодо того clock_gettime, API знаходиться в наносекунді, чи це означає, що він може бути таким точним, якщо базове обладнання дозволяє це? А як щодо монотонності?

Чи є якісь інші функції?

Відповіді:


198

Проблема полягає в тому, що в C та C ++ доступні кілька різних часових функцій, і деякі з них відрізняються за поведінкою між реалізаціями. Також багато плаває напіввідповідей. Складання списку функцій годин разом із їх властивостями відповість належним чином на питання. Для початку давайте запитаємо, які саме властивості ми шукаємо. Переглядаючи вашу посаду, пропоную:

  • Який час вимірюється годинником? (справжній, користувальницький, системний або, сподіваємось, ні, настінний годинник?)
  • Яка точність годинника? (s, мс, мкс або швидше?)
  • Через скільки часу годинник обертається? Або існує якийсь механізм, щоб цього уникнути?
  • Чи годинник одноманітний, чи зміниться він із зміною системного часу (через NTP, часовий пояс, літній час, користувачем тощо)?
  • Як вищезазначене змінюється між реалізаціями?
  • Чи конкретна функція застаріла, нестандартна тощо?

Перш ніж розпочати список, я хотів би зазначити, що час настінного годинника рідко є правильним часом використання, тоді як він змінюється зі змінами часового поясу, зміною літнього часу або якщо настінний годинник синхронізується NTP. Жоден із цих речей не є добрим, якщо ви використовуєте час для планування подій або для порівняльної оцінки ефективності. Це дійсно добре лише те, що говорить назва, годинник на стіні (або на робочому столі).

Ось що я знайшов поки що для годинників в Linux та OS X:

  • time() повертає час роботи настінного годинника з ОС, з точністю до секунд.
  • clock()здається, повертає суму користувачів та системний час. Він присутній у C89 та пізніших версіях. Свого часу це повинен був бути час процесора в циклах, але сучасні стандарти, такі як POSIX, вимагають, щоб CLOCKS_PER_SEC становила 1000000, забезпечуючи максимально можливу точність 1 мкс. Точність в моїй системі дійсно становить 1 мкс. Цей годинник загортається, як тільки він вивернеться (зазвичай це відбувається після ~ 2 ^ 32 тиків, що не так довго для тактової частоти 1 МГц). man clockговорить, що оскільки glibc 2.18 реалізований clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)в Linux.
  • clock_gettime(CLOCK_MONOTONIC, ...)забезпечує наносекундну роздільну здатність, є монотонним. Я вважаю, що "секунди" та "наносекунди" зберігаються окремо, кожен у 32-бітових лічильниках. Таким чином, будь-яке перекручування відбуватиметься після багатьох десятків років тривалості роботи. Це виглядає як дуже хороший годинник, але, на жаль, він ще не доступний в OS X. POSIX 7 описується CLOCK_MONOTONICяк додаткове розширення .
  • getrusage()виявився найкращим вибором для моєї ситуації. Він звітує про час користувача та системи окремо і не обертається. Точність в моїй системі - 1 мкс, але я також тестував її в системі Linux (Red Hat 4.1.2-48 з GCC 4.1.2), і там точність становила лише 1 мс.
  • gettimeofday()повертає час настінного годинника (номінально) µs точністю. У моїй системі, схоже, цей годинник має µs точність, але це не гарантується, оскільки "роздільна здатність системного годинника залежить від обладнання" . POSIX.1-2008 говорить про це . "Програми повинні використовувати clock_gettime()функцію замість застарілої gettimeofday()функції", тому вам слід триматися подалі від неї. Linux x86 і реалізує його як системний виклик .
  • mach_absolute_time()є варіантом часу з дуже високою роздільною здатністю (ns) на ОС X. У моїй системі це дійсно дає ns дозвіл. У принципі цей годинник обертається, однак він зберігає ns за допомогою 64-бітового цілого числа без підпису, тому обертання навколо не повинно бути проблемою на практиці. Переносимість сумнівна.
  • Я написав гібридну функцію на основі цього фрагмента, який використовує clock_gettime при компіляції в Linux, або таймер Mach при компіляції в OS X, щоб отримати точність ns як для Linux, так і для OS X.

Все вищезазначене існує як в Linux, так і в OS X, за винятком випадків, коли зазначено інше. "Моя система" у вищесказаному - це Apple, що працює під керуванням ОС X 10.8.3 з GCC 4.7.2 від MacPorts.

Нарешті, ось перелік посилань, які я знайшов корисними на додаток до посилань вище:


Оновлення : для OS X clock_gettimeвпроваджено станом на 10.12 (Sierra). Крім того, як платформи на базі POSIX, так і BSD (як OS X) поділяють rusage.ru_utimeполе структури.


Mac OS X не має clock_gettime, отже, використання gettimeofday()трохи більш універсальне, ніжclock_gettime()
bobobobo

1
Ви не згадали times()(з s), що існує в POSIX з випуску 1. Що стосується GNU / Linux: За даними сторінки годинника (3), clock()від glibc 2.17 і раніше було впроваджено поверх неї, але для покращення точність, тепер він реалізується поверх clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...), що також вказано в POSIX, але необов'язково.
vinc17

2
@starflyer Точність годинника частково обмежена кількістю часу, яке потрібно для опитування годинника. Це тому, що якщо я зателефоную на годинник, і для повернення знадобиться 1 мкс, то час звітних годин буде "вимкнено" на 1 мкс з точки зору абонента. Це означає, що високоточний годинник також повинен мати низьку затримку. Тому, як правило, у вас не буде компромісу, про який ви говорите: найдешевші годинники також будуть найточнішими.
Дуглас Б. Степлер

3
Також більшість годин не піклуються про перехід на літній час / часові пояси, навіть якщо вони вважаються настінними . І те, timeі gettimeofdayповернення, принаймні в наші дні, секунди з епохи (він же unix-часові позначки). Це не залежить від часових поясів / DST. Вистрибні секунди - інша історія ...
Зулан

2
Для користувачів Android використання CLOCK_MONOTONIC може бути проблематичним, оскільки додаток може бути призупинено разом із годинником. Для цього Android додав таймер ANDROID_ALARM_ELAPSED_REALTIME, доступний через ioctl. деякі відомості про ці та інші пов'язані з тимчасовою інформацією інформації можна знайти тут
Itay Bianco

17

С11 timespec_get

Приклад використання за адресою: https://stackoverflow.com/a/36095407/895245

Максимально можлива повернута точність - це наносекунд, але фактична точність визначена та може бути меншою.

Він повертає час стіни, а не використання процесора.

glibc 2.21 реалізує його під sysdeps/posix/timespec_get.cі передає безпосередньо на:

clock_gettime (CLOCK_REALTIME, ts) < 0)

clock_gettimeі CLOCK_REALTIMEє POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html , і man clock_gettimeговорить, що цей захід може мати розриви, якщо ви зміните деякі системні налаштування часу під час роботи програми.

C ++ 11 хроно

Оскільки ми це робимо, давайте також висвітлимо їх: http://en.cppreference.com/w/cpp/chrono

GCC 5.3.0 (C ++ stdlib знаходиться всередині джерела GCC):

  • high_resolution_clock псевдонім для system_clock
  • system_clock пересилає до першого з наступних:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock пересилає до першого з наступних:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

На запитання: Різниця між std :: system_clock та std :: steady_clock?

CLOCK_REALTIMEvs CLOCK_MONOTONIC: різниця між CLOCK_REALTIME та CLOCK_MONOTONIC?


1
Прекрасна відповідь, яка демістифікує типові варіанти. Це те, що насправді потрібно знати людям.
Безкоштовний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.