Hlavní navigace

Jak jsem lovil přestupnou sekundu

2. 7. 2015
Doba čtení: 6 minut

Sdílet

Jak Země neustále zpomaluje své otáčení, předbíhá se nám přesný čas a je třeba ho uměle zpomalovat přestupnými sekundami. Přinejmenším Evropané tuhle změnu většinou prospí, aniž by jakkoli ovlivnila jejich životy. Najdou se ale i takoví, co si jen kvůli ní přivstanou. Jeden takový napsal dnešní článek.

Je to za námi, mezi posledním červnem a prvním červencem se světový čas zase jednou zastavil, tentokrát už po dvacáté šesté. Zdá se, že tentokrát se to obešlo bez katastrofálních následků, na rozdíl od posledního podobného vkládání přestupné sekundy v roce 2012. Drobné problémy se však přesto objevily. Společnost Dyn Research na Twitteru například dokumentuje skokový nárůst zpráv směrovacího protokolu BGP kolem půlnoci UTC. Některé routery tedy zřejmě přestupnou sekundu bez úhony nepřežily.

Time.is na jedničku

Ačkoli jsem měl původně v plánu druhou hodinu ranní věnovat obvyklému spánku, nakonec jsem si přeci jen nastavil budík a podíval se na vlastní oči. Takhle vypadala plocha mého počítače, kde jsem postupně otevřel stránky time.is, cas.nebezi.cz a time.gov, který měl tou dobou evidentní výkonnostní problémy – stránka se načítala asi 10 sekund.

Time.is samozřejmě nezklamal, jeho autor Even Scharning si na podobných vychytávkách zakládá. Time.gov se choval vcelku zvláštně, ale asi to souviselo s přetížením serveru. U mých vlastních hodin, které jsou součástí projektu Neběží.cz, jsem nepředpokládal, že 60. sekundu budou umět zobrazit – vždyť jsou napsané v JavaScriptu a pracují pouze s unixovým časem – překvapilo mě ale, že se nezastavily na 59., ale až na nulté sekundě nové hodiny. Vypadá to, jako by si stihly nového času všimnout ještě předtím, než jádro vrátilo čas zpátky na 59. sekundu předchozí minuty.

Fyzické hodiny bez šedesátky

Kromě sledování softwarových hodin jsem připravil i kameru pro záznam hodin, které pohání router Turris (tyto hodiny jsem představoval na konferenci IT14.2). Předpokládal jsem, že tady zasáhne algoritmus kompenzace předběhnutí hodin a ručičky se jednoduše na sekundu zastaví. Nestalo se ale tak.

Kromě ručičkových hodin jsou v záběru vidět také komerční hodiny řízené rádiovým signálem DCF77 a ručně vyráběný přijímač téhož časového signálu. Komerční hodiny, jak jsem předpokládal, přestupnou sekundu ignorovaly a rozdíl kompenzovaly až někdy v průběhu noci. Drtivá většina rádiem řízených hodin se totiž z důvodu šetření baterie synchronizuje jen několikrát denně a ve zbylém čase běží autonomně. Proto nejsou takové hodiny schopné ani hladkého přechodu na letní čas nebo zpět.

Překvapilo mě ale, že stejným způsobem se chovaly i hodiny řízené Turrisem. Problém bude asi způsoben NTP démonem v Turrisu, který pochází z projektu BusyBox. Moje vysvětlení, které nemám nijak podložené, spočívá v tom, že odlehčený NTP server z BusyBoxu zřejmě informace o přestupné sekundě ignoruje. Když pak někdy po vložení přestupné sekundy kontaktuje časové servery, detekuje odchylku místních hodin a hodiny přestaví. K seřízení hodin tedy zřejmě došlo někdy uprostřed noci, když už jsem měl záznam kamery vypnutý (taky kdo by se na tak dlouhý záznam chtěl dívat, že).

Systémové hodiny pod drobnohledem

Problém přestupné sekundy je především v tom, že pro unixový čas není definovaná a danému okamžiku tak nelze přiřadit žádnou časovou značku. U systému, který používá NTP, je jádru správným nastavením funkce adjtimex(2) nastaven příznak, upozorňující na nutnost vložení přestupné sekundy. Jádro si takového příznaku všimne a těsně po překlopení do půlnoci vrátí hodiny o sekundu zpět a zaloguje:

Jul  1 02:01:07 oskarpc kernel: Clock: inserting leap second 23:59:60 UTC

Zkusil jsem sledovat stav systémových hodin, včetně řídicích proměnných, které vypisuje utilita adjtimex, pomocí jednoduché smyčky, spuštěné v inkriminovanou dobu:

$ while true; do /usr/sbin/adjtimex -p; LANG=C date; echo "===="; sleep 1; done
         mode: 0
       offset: -1694770
    frequency: 153174
     maxerror: 8779
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708797s 741418171us = 1435708797.741418171
 return value = 1
Wed Jul  1 01:59:57 CEST 2015
====
         mode: 0
       offset: -1688150
    frequency: 153174
     maxerror: 9279
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708798s 744044144us = 1435708798.744044144
 return value = 1
Wed Jul  1 01:59:58 CEST 2015
====
         mode: 0
       offset: -1681556
    frequency: 153174
     maxerror: 9779
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708799s 745997271us = 1435708799.745997271
 return value = 1
Wed Jul  1 01:59:59 CEST 2015
====
         mode: 0
       offset: -1674987
    frequency: 153174
     maxerror: 10279
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708799s 748679340us = 1435708799.748679340
 return value = 3
Wed Jul  1 01:59:59 CEST 2015
====
         mode: 0
       offset: -1668444
    frequency: 153174
     maxerror: 10779
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708800s 754907380us = 1435708800.754907380
 return value = 4
Wed Jul  1 02:00:00 CEST 2015
====
         mode: 0
       offset: -1661927
    frequency: 153174
     maxerror: 11279
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708801s 757271381us = 1435708801.757271381
 return value = 4
Wed Jul  1 02:00:01 CEST 2015
====
         mode: 0
       offset: -1655435
    frequency: 153174
     maxerror: 11779
     esterror: 1466
       status: 8209
time_constant: 6
    precision: 1
    tolerance: 32768000
         tick: 10000
     raw time:  1435708802s 758942030us = 1435708802.758942030
 return value = 4
Wed Jul  1 02:00:02 CEST 2015
====

Zajímavé je zejména sledování řádku return value, který se obvykle ve výpisu adjtimex -p vůbec nevyskytuje, protože je návratová hodnota nulová. Jeho hodnotu rozklíčujeme nahlédnutím do manuálové stránky, resp. hlavičkového souboru:

On success, adjtimex() returns the clock state:
#define TIME_OK   0 /* clock synchronized */
#define TIME_INS  1 /* insert leap second */
#define TIME_DEL  2 /* delete leap second */
#define TIME_OOP  3 /* leap second in progress */
#define TIME_WAIT 4 /* leap second has occurred */
#define TIME_BAD  5 /* clock not synchronized */

Vidíme tedy, že hodiny došly až do času 1435708799 s příznakem vkládání přestupné sekundy, po přechodu na další sekundu jádro vrátilo hodiny zpět na 1435708799 a změnilo příznak na „právě probíhá přestupná sekunda“. Po jejím uplynutí funkce ještě nějakou dobu vracela příznak, že k přestupné sekundě došlo. Až budu příště programovat hodiny, už vím, kde získat správný zdroj informace o přestupné sekundě.

Tenhle způsob řešení přestupné sekundy ale není jediný možný. Vývojáři Red Hatu před měsícem publikovali velmi podrobný blogpost, představující hned pět alternativ řešení problému s přestupnou sekundou. Tak například přidáním přepínače -x pro ntpd vyřadíte z činnosti kompenzaci přestupné sekundy v jádře a místo toho hodiny přejdou na nový čas pozvolným rozlaďováním rychlosti hodin. Při tomhle řešení však bude trvat dva dny, než se hodiny vrátí ke své obvyklé přesnosti.

Alternativní hodinový démon chronyd, který je Red Hatem preferován, umožňuje hodiny po přestupné sekundě srovnat pozvolným zpomalením už během dvanácti sekund. Také je možné si pomocí chronyd vyrobit, podobně jako Google, vlastní časový server, který přestupnou sekundu před svými klienty zatají a rozmaže ji do celého dne.

Přestupná sekunda ve vysílání Českého rozhlasu

Na samý závěr mě ještě napadlo podívat se do archivu, jak se s přestupnou sekundou vyrovnalo vysílání časového znamení Českého rozhlasu. Zdá se ale, že nijak zvlášť. Zde je záznam vysílání od 01:59:50 stanice Český rozhlas Dvojka:

Až později jsem si uvědomil, že jsem se měl také podívat na webové kamery, zda se přestupná sekunda korektně zobrazila alespoň na studiových hodinách Wharton, které byly předlohou pro čas.Neběží.cz. Musím si to zapsat na seznam, co mám zkontrolovat příště.

Chce to testovací platformu

Přestupná sekunda patří mezi několik málo věcí, které se dají jen velmi těžko otestovat. Přitom, jak se ukázalo před třemi lety, nemusí jít v počítačích vůbec o banalitu. Našel jsem pouze nabídku testování prostřednictvím GPS generátoru, což je jistě dobré řešení pro operátory primárních časových serverů, ale pro běžného programátora vcelku složitě dostupné.

CS24 tip temata

Představoval bych si něco jako Keyroller, veřejný alternativní DNS kořen, který mění kořenový klíč každých 90 minut. Kdokoli si tak na něm může otestovat chování svého DNSSEC validátoru při výměně kořenového klíče.

Na stejném principu by mohl fungovat veřejný NTP server, který by vkládal přestupnou sekundu třeba každý den. Divím se, že jsem takovou službu ještě nenašel. Zvedne někdo hozenou rukavici?

Autor článku

Ondřej Caletka vystudoval obor Telekomunikační technika na ČVUT a dnes pracuje ve vzdělávacím oddělení RIPE NCC, mezinárodní asociaci koordinující internetové sítě.