pretoceny uptime :)

Pavel Kankovsky peak na argo.troja.mff.cuni.cz
Neděle Duben 14 14:08:33 CEST 2002


On Sat, 13 Apr 2002, Pavel Kankovsky wrote:

> 2. kod, ktery potrebuje obe hodnoty, je muze precist nasledujicimi
> prikazy (v praxi by to muselo byt v asembleru, nebo by se tam muselo
> rozhodit par volatile, aby to kompilator nevyoptimalizoval do
> ztracena):
> 
>          uint32_t jlo, jhi;
>          do {
>              jhi = jiffies_high;
>              jlo = jiffies_low;
>          }
>          while (jhi != jiffies_high);
> 

Uff...tak to se trochu nepovedlo. Omlouvame se ctenemu publiku za
snizenou kvalitu citovaneho prispevku zpusobenou zkratem v mentalnim
procesu autora. Tohle by fungovalo pouze za predpokladu, ze zapisujici
CPU zapisuje dost rychle. Coz je asi ponekud odvazny predpoklad. Spravne
reseni (snad <g>), ktere je o neco slozitejsi, je nasledujici:

A. Mame 32-bitove tri promenne: jiffies_low, jiffies_high a jiffies_low2
   inicializovane na zacatku nulami (pripadne jinymi hodnotami, ale musi
   na zacatku platit, ze j_low == j_low2).

B. Zapis probiha takto:
   1. inkrementuje se jiffies_low,
   2. inkrementuje se jiffies_high, pokud se jiffies_low pretocilo,
   3. inkrementuje se jiffies_low2 (nebo ze zkopiruje hodnota z j_low).

   Pritom musi platit, ze ctenari vidi zapisy provedene ve stejnem poradi,
   v jakem jsou tady uvedeny, coz muze vyzadovat pridani nejakych
   barierovych instrukci zde a mozna i behem cteni (*).

C. Cteni probiha takto:
   1. precte se jiffies_low2 a ulozi do lokalni promenne,
   2. precte se jiffies_high a ulozi do lokalni promenne,
   3. precte se jiffies_low a ulozi do lokalni promenne,
   4. porovnaji se prectene hodnoty jiffies_low a jiffies_low2, a pokud
      jsou ruzne, pak se opakuje od kroku 1.

   Predpoklada se, ze proces provadejici cteni se nemuze zablokovat na
   dost dlouho, aby se mezitim pretocila dolni pulka. Zaroven se
   predpoklada, ze je zanedbatelna pravdepodobnost, ze se opakovane
   strefi do aktualizace jiffies (asi by ale slo zeslabit predpoklad na
   rovnost j_low a j_low2 na neco jako j_low2 <= j_low, aby se opakovalo
   jen v pripade, ze to zrovna preteklo, protoze jindy k zadne zmene
   j_high nedochazi).

Dukaz spravnosti: Oznacme zapisy do jiffies_* pro strucnost wlo, whi, wl2
(low2) a cteni rlo, rhi, rh2. Relace < necht popisuje poradi, ve kterem
jsou operace provadeny (za jiz zminovanych predpokladu atomicnosti a
zachovani poradi zapisu vzhledem ke cteni; pokud nas zaroven nezajima
vzajemne poradi cteni v ruznych procesech, muzeme operace povazovat za
jednoznacne serializovatelne). Pak z popisu zapisu a cteni plati, ze:
a) wlo < whi < wl2, b) rl2 < rhi < rlo. Predpokladejme dale splneni
predpokladu uvedeneho u popisu cteni, tj. toho, ze lze zanedbat moznost,
ze mezi rl2 a rlo dojde k pretoceni jiffies_low*. Pak muze proces cteni
vydat nespravny (nekonzistentni) vysledkem pouze jsou-li vzhledem k zapisu
splneny nasledujici predpoklady: a1) wlo < rlo & wl2 < rl2 (zapisy j_low i
j_low2 probehnout drive nez cteni), a2) rhi < whi (zapis do j_hi probehne
pozdeji nez cteni), nebo b1) rlo < wlo & rl2 < wl2, b2) whi < rhi 
(tj. zrcadlove). V obou pripadech lze snadno dojit ke sporu:
ad a) wl2 < rl2, & rl2 < rhi ==> wl2 < rhi, & rhi < whi ==> wl2 < whi!
ad b) rlo < wlo, & wlo < whi ==> rlo < whi, & whi < rhi ==> rlo < rhi!
Jeste by se melo ukazat, ze problemy nemohou nastat kvuli kolizi jednoho
cteni s vice zapisy (avsak mene nez 2^32), ale to se mi uz nechce delat a
stejne je to intuitivne jasne. :)

Jak vidno, je to trochu komplikovanejsi (zapis vyzaduje dve aritmeticke
operace navic a pripadne i dve bariery), ale porad by to melo byt znatelne
levnejsi nez spinlocky.

(*) Mam ale dojem, ze na i386 (aspon na modelech dost starych, aby 
se tam vyskytoval problem uptime >= 500 dni <g>) nejsou potreba zadne.

--Pavel Kankovsky aka Peak  [ Boycott Microsoft--http://www.vcnet.com/bms ]
"Resistance is futile. Open your source code and prepare for assimilation."



Další informace o konferenci Linux