Різниця між CLOCK_REALTIME та CLOCK_MONOTONIC?


206

Чи можете ви пояснити різницю між CLOCK_REALTIMEта CLOCK_MONOTONICтактовими годинниками, що повертаються clock_gettime()в Linux?

Що є кращим вибором, якщо мені потрібно обчислити минулий час між часовими позначками, виробленими зовнішнім джерелом, та поточним часом?

Нарешті, якщо у мене демон NTP періодично коригує системний час, то як ці коригування взаємодіють з кожним з CLOCK_REALTIMEі CLOCK_MONOTONIC?

Відповіді:


238

CLOCK_REALTIMEвідображає найкращі здогадки машини про поточний настінний годинник, час доби. Як кажуть Ігнасіо та MarkR , це означає, що CLOCK_REALTIMEможна стрибати вперед і назад, коли змінюється годинний режим системи, включаючи NTP.

CLOCK_MONOTONICявляє собою абсолютний минулий час настінного годинника з деякої довільної, фіксованої точки в минулому. На це не впливають зміни системного годинника.

Якщо ви хочете обчислити минулий час між двома подіями, що спостерігаються на одній машині, без перезавантаження, що втручається, CLOCK_MONOTONICце найкращий варіант.

Зауважте, що в Linux CLOCK_MONOTONICне вимірюється час, який витрачається на призупинення, хоча за визначенням POSIX це повинно бути. Ви можете використовувати для Linux CLOCK_BOOTTIMEмонотонні годинники, які постійно працюють під час призупинення.


11
Зауважте, що на нових ядрах доступний CLOCK_MONOTONIC_RAW, що ще краще (відсутність коригування NTP).
Джозеф Гарвін

14
@JosephGarvin для деякого значення "кращого", можливо - CLOCK_MONOTONIC_RAW може працювати швидко або повільно в режимі реального часу на кілька (або кілька сотень) частин на мільйон, і його швидкість може змінюватися в залежності від умов навколишнього середовища, таких як температура або напруга (або час крадіжки на віртуальні машини). На правильно працюючій машині NTP робить все можливе, щоб пом’якшити всі ці фактори, і тому CLOCK_MONOTONIC більш детально відображає справжній пройшов час.
панно

23
Зрозуміло, це може бути цікаво мати CLOCK_MONOTONIC_PARBOILED, який вплинув на намагання NTP виправити помилки частоти, але це не вплинуло на його зусилля з виправлення фазових помилок, але це дуже складно для сумнівної вигоди :)
варення

1
Мені подобається те, що підказує @hobbs. Що робити, якщо ви стурбовані програмами, на які може вплинути переміщення годин? Був CLOCK_MONOTONICби найкращий вибір у такому сценарії? наприклад, Ракетна система "Патріот"
sjagr

3
Я думаю, що також важливо зазначити, що CLOCK_REALTIME впливає на високосні секунди. Це означає , що він буде робити подвійну мітку часу кожен раз , коли вставляються стрибок другий. Востаннє це траплялося 30 червня 2012 року, і досить багато програмного забезпечення зіткнулися з проблемою .
user1202136

38

Книга Роберта Лава 2-го видання LINUX System Programming , спеціально вирішує ваше запитання на початку глави 11, стор 363:

Важливим аспектом монотонного джерела часу є НЕ поточне значення, а гарантія того, що джерело часу суворо лінійно збільшується, і, таким чином, корисно для обчислення різниці у часі між двома вибірками

При цьому, я вважаю, що він припускає, що процеси запущені на одному і тому ж екземплярі ОС, тому вам може знадобитися періодична калібрування, щоб мати можливість оцінювати дрейф.


25

CLOCK_REALTIMEвпливає НТП і може рухатися вперед і назад. CLOCK_MONOTONICнемає, а аванси по одному галочку за тик.


15
CLOCK_MONOTONIC впливає на регулювання часу NTP (зменшення часу). Однак вона не стрибне.
дероберт

3
Але на нових ядрах є CLOCK_MONOTONIC_RAW, на який дійсно не впливає NTP.
Джозеф Гарвін

1
"галочка" - будь-яка груба ідея, наскільки великими / довгими / інструкціями процесора є галочка на Linux / amd64? Або де я можу отримати документи про щось із цього?
kevinarpe

@kevinarpe Не впевнений, але я думаю, що тик визначається як частка часу, а не кількість циклу процесора, часто це 1/100 секунди.
Стефан

@ Stéphane: Напевно, я повинен бути жорсткішим за 10 мс. Я думаю, що Java System.nanoTime()використовує CLOCK_MONOTONICі може виміряти тривалість 1000ns або менше. Можливо, ви думаєте про системний час, який іноді обмежується мілісекундами?
кевінарпе

20

Окрім відповіді Ігнасіо , CLOCK_REALTIMEможе йти вперед стрибками, а іноді й назад. CLOCK_MONOTONICне робить ні; він просто продовжує рухатися вперед (хоча він, мабуть, скидається при перезавантаженні).

Надійний додаток повинен мати можливість терпіти CLOCK_REALTIMEстрибки вперед періодично (а може бути, дуже злегка і дуже зрідка, хоча це скоріше крайній випадок).

Уявіть, що станеться, коли ви призупиняєте ноутбук - CLOCK_REALTIMEстрибки вперед після резюме, CLOCK_MONOTONICне так. Спробуйте його на VM.


3
CLOCK_MONOTONIC починається з 0 при запуску програми; це не для міжпроцесорного використання.
Benubird

18
@Benubird: не починається з 0 при запуску програми. Ось так CLOCK_PROCESS_CPUTIME_ID. Швидкий тест: $ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279. Це число відповідає часу роботи системи в Linux, але стандарт говорить про довільність.
дероберт

4
Як осторонь, я не вірю, що поведінка Linux, коли CLOCK_MONOTONICзупиняється над тимчасовим призупиненням / відновленням, відповідає POSIX. Це, мабуть, минув час із фіксованої точки в минулому, але зупинка годинника над призупиненням / відновленням порушує це.
caf

15

POSIX 7 цитат

POSIX 7 визначає обидві сторінки на сторінці http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html :

CLOCK_REALTIME:

Цей годинник являє собою годинник, який вимірює реальний час для системи. Для цього годинника значення, повернені clock_gettime () та задані clock_settime (), представляють кількість часу (у секундах та наносекундах) з часу епохи.

CLOCK_MONOTONIC (додаткова функція):

Для цього годинника значення, повернене clock_gettime (), являє собою кількість часу (в секундах і наносекундах) з часу невизначеної точки в минулому (наприклад, час запуску системи або епоха). Цей момент не змінюється після часу запуску системи. Значення годинника CLOCK_MONOTONIC не можна встановити через clock_settime ().

clock_settime()дає важливий натяк: POSIX-системи здатні довільно змінюватись CLOCK_REALITME, тому не покладайтеся на те, що він протікає ні постійно, ні вперед. NTP може бути реалізований з використанням clock_settime()та може вплинути лише на нього CLOCK_REALITME.

Реалізація ядра Linux, здається, займає час завантаження як епоха для CLOCK_MONOTONIC: Початкова точка для CLOCK_MONOTONIC


0

Вибачте, немає репутації, щоб додати це як коментар. Тож це є додатковою відповіддю.

Залежно від того, як часто ви будете телефонувати clock_gettime(), вам слід пам’ятати, що лише деякі з «годинників» надаються Linux у VDSO (тобто не потрібно систематичний виклик з усіма накладними витратами - який тільки погіршився, коли додано Linux засоби захисту від нападів, схожих на Привид).

Хоча clock_gettime(CLOCK_MONOTONIC,...), clock_gettime(CLOCK_REALTIME,...)і gettimeofday()завжди буде надзвичайно швидким (прискорюється VDSO), це не відповідає дійсності, наприклад, CLOCK_MONOTONIC_RAW або будь-який з інших годин POSIX.

Це може змінитися у версії ядра та архітектурі.

Хоча більшості програм не потрібно на це звертати увагу, можуть спостерігатись затримки у затримках годин, прискорених VDSO: якщо ви потрапляєте на них прямо, коли ядро ​​оновлює область спільної пам’яті за допомогою лічильників годин, йому доведеться чекати, коли ядро для закінчення.

Ось "доказ" (GitHub, щоб ботів не було на kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7

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