Portál AbcLinuxu, 17. května 2024 06:01

Jaderné noviny - 30. 8. 2006

15. 9. 2006 | Robert Krátký
Články - Jaderné noviny - 30. 8. 2006  

Aktuální verze jádra: 2.6.17.13. Jak dosáhnout začlenění kódu. API pro určení limitu latence. Pracovní fronty a zvyklosti interního API. Zdroje: má dáti, dal.

Aktuální verze jádra: 2.6.17.13

link

Aktuální předverze je 2.6.18-rc5, vydaná 27. srpna. Jak se dalo očekávat v této fázi vývoje 2.6.18, obsahuje tento patch jen několik oprav a nic moc dalšího. Vizte podrobnosti v dlouhém changelogu.

Od vydání verze -rc5 se do hlavního repozitáře dostalo jen pár patchů.

Aktuální verze -mm stromu je 2.6.18-rc4-mm3; jde především o opravy chyb a menší aktualizace.

26. srpna vyšlo stabilní jádro 2.6.16.28. V poměrně dlouhém seznamu oprav byly přinejmenším čtyři týkající se bezpečnostních chyb.

Jak dosáhnout začlenění kódu

link

Rik van Riel sepsal průvodce pro ty, kdo chtějí dosáhnout začlenění svého kódu do jádra, a vystavil jej na kernelnewbies.org. Někteří lidé však těžko nesou názory a návrhy těch, kdo si našli hodiny času na kontrolu jejich kódu. Někteří je dokonce flamují až na uhel. Když proti sobě v konferenci popudíte většinu 'smetánky', bude velmi obtížné začlenění kódu dosáhnout. Mimo jiné proto, že nikdo už nebude plýtvat časem při kontrole další verze vašeho kódu.

API pro určení limitu latence

link

Moderní procesory podporují množství energetických režimů. Když se zrovna neděje nic zajímavého, mohou být instruovány, aby snížily příjem energie na jednu z potenciálně mnoha různých úrovní. Protože jsou na většině systémů procesory často nevytížené, může být tato schopnost využita k výraznému snížení spotřeby. Omezení spotřeby energie je nejvíce k užitku na systémech s limitovanými zdroji - notebooky, přenosné hudební přehrávače, linuxoví robotičtí tučňáci atp. - ale hodí se i ve většině jiných prostředí.

Utlumení CPU je ještě více užitečné, pokud se využije dynamický tik/čas [tick] - což by mělo být možné u i386 verze Linuxu v jádře 2.6.19. Zrušení periodického hodinového přerušení umožní procesoru spát delší dobu, není-li nic na práci. Delší uspání umožní úspornější režimy, což spotřebu ještě sníží.

Může se však objevit problém způsobený tím, že čím budou režimy správy napájení agresivnější, tím déle bude procesoru trvat, než se dostane do provozního stavu. Takže uložením procesoru k odpočinku se zvýší latence systému při reakcích na externí události. V některých situacích by latence mohla způsobit selhání systému. Audio nebo video by nebylo zpracováno, síťový adaptér by začal chybovat a robotický tučňák by včas nezareagoval na hrozbu blížícího se kyber-mrože. Běžným řešením takového problému je - kromě vyhlazení mrožů - vypnutí úsporných opatření. Ale tak drastická reakce možná není nutná.

Různá zařízení v systému budou při provozu v určitých režimech potřebovat od systému reakci v daném čase. Ovladače těchto zařízení mají přehled o tom, jakým způsobem zařízení ve všech situacích pracují, takže vědí, jaké jsou požadavky na latenci. Kdyby měl takovou informaci systém jako celek, mohl by svůj provoz přizpůsobit minimálním požadavkům na latenci v danou chvíli a se změnou požadavků měnit i režim provozu. Ale systém nemá žádný mechanismus, který by mohl tyto informace zpracovávat a reagovat na ně.

Arjan van de Ven se to rozhodl napravit prostřednictvím infrastruktury pro sledování latencí. Jde o sadu nových funkcí, které mohou ovladače využívat k oznamování svých požadavků na latenci:

    #include <linux/latency.h>

    void set_acceptable_latency(char *identifier, int usecs);
    void modify_acceptable_latency(char *identifier, int usecs);
    void remove_acceptable latency(char *identifier);

Když se ovladač dostane do stavu, ve kterém má určité požadavky na latenci (například ovladač kamery začne ukládat snímky), může systému pomocí set_acceptable_latency() říci o maximální latenci, kterou ještě ustojí. Parametr identifier se používá pouze pro pozdější identifikaci požadavku; usecs je maximální latence v mikrosekundách. Požadavek lze upravit pomocí modify_acceptable_latency() nebo úplně zrušit zavoláním remove_acceptable_latency().

Na druhém konci infrastruktury je oznamovač, který dá dotčeným subsystémům o změně maximální přijatelné latence vědět. V současné době tuto informaci využívá ACPI subsystém pro upravení odpočinkového stavu procesoru na úroveň vyhovující požadavku. Lze si představit, že by tuto informaci mohla využívat i šikovná implementace dynamického času.

V aktuální verzi patche oznamuje své požadavky na latenci pouze jeden subsystém (ovladač bezdrátových síťových adaptérů IPW2100). Tato verze patche však byla navržena pro začlenění do jádra -mm s tím, že by funkci mohli začít využívat i další správci ovladačů. Nestane-li se něco neočekávaného, vypadá dost pravděpodobně, že se infrastruktura pro správu latencí stane součástí jádra 2.6.19.

Pracovní fronty a zvyklosti interního API

link

Pro interní jaderné API se za léta ustálily různé zvyklosti. Jedna z těch trvanlivějších se týká návratových hodnot funkcí. V mnoha případech vrátí funkce nulu jako indikátor úspěchu nebo záporný chybový kód při selhání. Taková zvyklost jde proti běžným zvyklostem jazyka C, který používá boolean hodnoty - hodnota "false" v jádře znamená, že je vše OK. Ale vystihuje to situaci v tom smyslu, že zatímco všechny veselé funkce jsou stejné, každá nešťastná je nešťastná svým vlastním způsobem. Je užitečné mít možnost vracet množství různých chybových kódů.

Jsou však výjimky. Mezi ty známější patří copy_to_user() a copy_from_user(), které obě při selhání vrátí počet nezkopírovaných bajtů. V roce 2002 prověřil Rusty Russell 5500 volání těchto funkcí a zjistil, že 415 z nich interpretuje návratovou hodnotu nesprávně. Navrhl rozhraní změnit tak, aby odpovídalo jaderným zvyklostem, ale nepochodil. O této epizodě více v May 23, 2002 LWN Kernel Page.

Nedávno se Alan Stern spálil při práci s rozhraním pracovní fronty [workqueue]. Funkce jako queue_work() vrací "normální" boolean hodnotu - nulu při selhání, nenulovou hodnotu, pokud byla práce skutečně do fronty zařazena. Alan navrhl změnit tyto funkce a nabídl se, že při té příležitosti opraví i ty tři případy, které funkce volají. Dostalo se mu odpovědi, že by sice bylo dobré opravit návratové kódy, ale funkce by měly být přejmenovány. Jinak by si kód, který není spravován v rámci jádra, mohl návratovou hodnotu vyložit nesprávně, aniž by o tom programátor věděl.

Výsledný patch tedy dělá přesně to. S tímto patchem budou funkce pro přidávání práce do libovolné fronty následující:

    int add_work_to_q(struct workqueue_struct *queue, 
                      struct work_struct *work);
    int add_delayed_work_to_q(struct workqueue_struct *queue,
                              struct work_struct *work,
			      unsigned long delay);
    int add_delayed_work_to_q_on(int cpu,
                                 struct workqueue_struct *queue,
				 struct work_struct *work,
				 unsigned long delay);

Jak by se dalo očekávat, tyto funkce vrací při úspěchu nulu a při selhání záporný chybový kód (-EBUSY). Takový návratový kód dává smysl, protože jediným důvodem, proč by operace mohla selhat, je, že už daná work_struct v pracovní frontě je.

Podobné změny byly provedeny u funkcí, které pracují s obecnými, sdílenými frontami (schedule_work() a přátelé). Teď vypadají takto:

    int add_work(struct work_struct *work);
    int add_delayed_work(struct work_struct *work, unsigned long delay);
    int add_delayed_work_on(int cpu, struct work_struct *work,
                            unsigned long delay);

Pro každý případ jsou připraveny i wrapper funkce se starými názvy, takže neaktualizovaný kód spravovaný mimo jádro nepřestane fungovat. Tedy, alespoň většinou. Ukázalo se, že většina volajících funkcí spravovaných v jádře se nikdy neobtěžovala s kontrolou návratové hodnoty, a Alan usoudil, že ostatní se pravděpodobně chovají stejně. Takže nové verze starých funkcí jsou deklarovány jako void a nevracejí vůbec žádnou hodnotu. V důsledku toho pak kód, který návratovou hodnotu kontroluje, nepůjde zkompilovat a dá se očekávat, že jej autor aktualizuje, aby využíval funkce nové. Všechno ostatní poběží jako obvykle.

Alan také navrhl doplnit zmínku do dokumentu o stylu psaní jaderného kódu:

Je-li v názvu funkce akce nebo příkaz, měla by funkce vracet chybový kód jako celé číslo. Je-li název tvrzení nebo vlastnost, měla by funkce vracet boolean "úspěch".

Nevypadá to, že by se proti tomuto návrhu někdo postavil, takže tak to pravděpodobně zůstane. Pro copy_to_user() a copy_from_user() to však asi ani nadále platit nebude.

Zdroje: má dáti, dal

link

Pamatuji dobu, kdy byl "počítač" jediný veliký stroj, který sdílelo mnoho uživatelů. Tento stroj nebyl tak silný jako systémy, na kterých pracujeme nyní - nebo nosíme v kapse pro přehrávání hudby - takže sdílení mnoha desítkami (nebo i více) lidí zákonitě vedlo ke konfliktům. Kvůli tomu také většina systémů pro plánování sdílení zdrojů implementovala komplexní kvótové mechanismy, aby udržela uživatele na uzdě. Když tyto systémy fungovaly dobře, pomohly lidem udělat práci a zároveň minimalizovaly násilí na chodbách.

Dá se pravděpodobně prohlásit, že většina nasazených linuxových systémů stráví nejvíce času prací pro jednoho uživatele nebo úkol. Není příliš potřeba se starat o to, aby si uživatelé nepřekáželi v rámci jednoho systému; místo toho se mohou poprat o používání externích zdrojů, např. o šířku pásma. Takže patche implementující takový mechanismus (třeba třídový systém pro správu jaderných zdrojů - class-based kernel resource management system, CKRM) se většinou moc daleko nedostaly. Prostě se neprojevila nutnost stavět uživatelům ploty mezi částmi systémových zdrojů.

Virtualizace a kontejnery by však situaci mohly změnit. Účelem těchto systémů je izolovat uživatele od sebe. Ale pokud by jeden kontejner mohl využívat neúměrné množství nějakého vitálního systémového zdroje, ostatní by jeho přítomnost pocítily. Iluze o tom, že máte stroj pro sebe, ztrácí na své hodnověrnosti, když takový stroj například nemá žádnou volnou paměť. Jak tyto projekty nabírají rychlost, představují motivaci k novému posouzení struktur pro správu využití zdrojů.

CKRM, teď nazývané resource groups, možná zažije zmrtvýchvstání. Mezitím se však objevil návrh dalšího přístupu: cifršpión zdrojů [resource beancounters]. Vývojáři beancounters se patrně snaží o jednodušší přístup, ale přesto se patch dotýká mnoha míst v jádře.

Hlavním objektem mechanismu je, ano, "beancounter". Každý beancounter v systému sleduje využití zdrojů skupinou procesů - nejspíše všech procesů spuštěných v rámci určitého kontejneru. Beancountery obsahují referenční číslo, unikátní ID a pole hodnot zdrojů; pro každý sledovaný zdroj obsahuje pole dva limity, aktuální využití, historická minima a maxima a počet, kolikrát byl odmítnut pokus o navýšení užití daného zdroje. Každý proces v systému obsahuje ukazatel na svůj (pravděpodobně sdílený) beancounter objekt. Existuje také druhý beancounter nazývaný fork_bc, který se používá pro všechny procesy vytvořené pomocí fork().

Nové systémové volání get_bcid() vrací ID číslo beancounter objektu aktuálního procesu. Uživatel s příslušnými právy může provést:

    int set_bcid(bcid_t id);

čímž změní aktuální ID a ID forku na novou hodnotu. Privilegované procesy také mohou změnit limity kteréhokoliv procesu:

    int set_bclimit(bcid_t id, unsigned long resource, unsigned long *limits);

resource zde identifikuje měněný limit zdroje a limits ukazuje na pole dvou hodnot držící "hraniční" a "limitní" hodnoty. Hraniční hodnota je zamýšlena jako jistý druh volného limitu, kde některé alokace selžou, ale jiným je povoleno pokračovat.

Poslaný patch sleduje zatím jen jediný zdroj: jadernou paměť. U tohoto zdroje se hraniční limit vztahuje na většinu aplikací; jak je dosaženo hranice, pokusy o alokaci selžou. Alokace tabulek stránek a příslušných struktur však může pokračovat až do "limitní" hodnoty. Takže ačkoliv procesům začnou selhávat operace v důsledku přílišného využití jaderné paměti, pořád by měly být schopné se o své "chyby stránek" [page faults] postarat normálně (až se budou pokoušet o ozdravení).

Jádro paměť alokuje na mnoha místech a ne všechny tyto alokace by měly být přičteny procesu, který právě běží. Aby bylo rozlišení jasné, přidává Beancounter dva nové GFP parametry. Ve výchozím případě nejsou alokace přičítány žádnému beancounteru. Je-li však zavolána alokační funkce s parametrem __GFP_BC, bude naúčtována aktuálnímu beancounteru. Další parametr (__GFP_BC_LIMIT) určuje, že se má použít vyšší limitní hodnota. Pak je tu ještě parametr SLAB_BC, který může nařídit přičítání všech alokací s dané slab keše. A nakonec nová funkce vmalloc_bc(), která provádí příslušné počítání.

Je jistě zřejmé, že vystopovat každou alokaci, která by měla být beancounteru přičtena, by dalo hodně práce. Současná verze patche se o to ani nesnaží; místo toho označuje dost specifických alokací na to, aby zachytila větší využití paměti a ukázala, jak celý systém funguje. A lepší to možná nebude; přinutit například autory ovladačů, aby uvažovali o tom, jestli mají být jejich alokace přičítány, se zdá jako hodně těžký úkol.

Jestli se tento patch dostane dále než CKRM (pardon, "resource groups"), to se teprve ukáže. Není zcela jasné, jak by se řešilo účtování u sdílených procesů - bylo by vše přičteno skupině procesů, která v C knihovně první chybuje, a ostatní by se svezly zadarmo? Mnoho vývojářů také bude i nadále přesvědčeno, že taková účtovací struktura není vůbec potřeba. Rostoucí využití virtualizačních technik by však mohlo být faktorem, který podobný druh patche nakonec protlačí do jádra.

Související články

Jaderné noviny - 23. 8. 2006
Jaderné noviny - 16. 8. 2006
Jaderné noviny - 9. 8. 2006

Odkazy a zdroje

Kernel coverage at LWN.net: August 30, 2006

Další články z této rubriky

Jaderné noviny – přehled za duben 2024
Jaderné noviny – přehled za březen 2024
Jaderné noviny – přehled za únor 2024
Jaderné noviny – přehled za leden 2024
Jaderné noviny – přehled za prosinec 2023

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.