garoeda | god damn, too late |
garoeda | dezelfde code lijkt op |
garoeda | for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid) |
wli | if (p->session == current->session) |
wli | goto ok_pgid; |
garoeda | vraag: misschien een domme vraag, wat bevatten deze hash tabellen, wat is de key bedoel ik |
garoeda | ok, deze vraag helpt om te begrijpen wat er gaande is in de code |
garoeda | er is een "struct pid" die een gegeven "proces" id voorstelt |
garoeda | het begrip "process id" is een veralgemening, dus het betekent niet alleen PID, het bevat ook PID, PGID, TGID, en SID. |
garoeda | de struct pid heeft een lijst in zich die alle tasks bevat die een zelfde ID delen |
garoeda | bijvoorbeeld, stel dat er 20 tasks zijn in een zeker process groep |
garoeda | de struct pid voor die pgrp is te vinden in de hashtable bucket lijst, je kijkt naar de struct pid en bezoekt de lijst erin |
garoeda | dit zou je een idee moeten geven van wat er al in _each_task_pid() al is |
garoeda | #define for_each_task_pid(who, type, task, elem, pid) \ |
wli | if ((pid = find_pid(type, who))) \ |
wli | for (elem = pid->task_list.next, \ |
wli | prefetch(elem->next), \ |
wli | task = pid_task(elem, type); \ |
wli | elem != &pid->task_list; \ |
wli | elem = elem->next, prefetch(elem->next), \ |
wli | task = pid_task(elem, type)) |
garoeda | pid = find_pid(type, who) /* find_pid() doet de opzoeking in de hashtabel en zoekt de struct pid die overeenkomt |
garoeda | meer specifiek, find_pid() neemt als eerste argument het soort pid (PGID/SID/etc.), en als tweede argument de waard |
garoeda | e |
garoeda | dit wordt gebruikt om de loop te starten |
garoeda | de code tijdens de loop kijkt naar pid->task_list |
garoeda | en is eigenlijk een list_for_each_entry() |
garoeda | je zal opmerken dat in stuct pid er 2 verzamelingen van list links zijn |
garoeda | een voor de hashtabel en een voor de lijst van tasks, dit help met de sharing |
garoeda | dit is het punt waar het principe van state changing vs state examination in het spel komt |
garoeda | deze hashtabellen moeten geupdated worden tijdens fork(), exec() en exit() |
garoeda | er is ook een andere klasse van neveneffecten |
garoeda | de locking veranderingen in sommige (minder belangrijke) gevallen |
garoeda | sys_setpgid() is zo een van die gevallen |
garoeda | in 2.4.x was er geen structuur geassocieeerd met pgrp's die veranderd moest worden wanneer de pgrps veranderen, dus 2.4.x nam de tasklist_lock om te lezen |
garoeda | dit is wel het geval in 2.5.x dus de tasklist_lock moet geschreven worden |
garoeda | dit heeft een andere weerslag, sommige operaties zijn nu minder paralleliseerbaar maar ze zijn snell in serie |
garoeda | de algemene trend van de operaties die geserialiseerdd werden in 2.5 is dat ze 'ongewoon' waren, het soort die niet vaak gevraagd werden of niet als levensbelangrijk voor de performantie beschouwd werden terwijl de operaties die versneld werden niet echt last hadden van de accounting overhead of enorm versneld werden daar ze al reeds serieel werden uitgevoerd |
garoeda | (vertaler: wat ne zin) |
garoeda | er was een ander neveneffect, het werd gebruikt om promotie te maken voor deze infrastructuur in de kernel |
garoeda | de accounting geeeft een expliciete waarschuwing wanneer een pid niet langer gebruikt wordt |
garoeda | op het eerste zicht lijkt dit niet enorm belangrijk maar er is een andere specifieke operatie die we zouden willen weten |
garoeda | tijdens fork() krijgt een proces een uniek ID, dit wordt 'pid allocation' genoemd |
garoeda | de 2.4 pid allocator heeft volgende werkwijze: overloop de tasklist en kijk of het ID dat ik gegokt heb in het begin echt goed is |
garoeda | in werkelijkheid is het meer specifiek maar toch blijft het een niet erg deterministisch algoritme |
garoeda | 2.4 pid allocater gebruikt een 'venster' met veilige pids dat beweegt, groeit en verkleint naarmate er pids toegewezen worden en de tasklist onderzocht wordt |
garoeda | in het 'beste' geval resulteert dit in O(tasks) performantie maar in het slechtste geval O(tasks**2). Men kan bewijzen dat na een reeks operaties alles uitgemiddeld wordt zodat gevallen met O(tasks**2) toch naar O(tasks) gaan, gemiddeld gezien |
garoeda | het probleem is dat het slechtste geval erg genoeg kan zijn wanneer er voldoende tasks zijn zodat het deadlock detectie mechanisme in werking treedt, zoals de NMI watchdog, door taken die elk proberen write_lock_irq(&tasklist_lock). |
garoeda | de 2.5.x pid allocator gebruikt hashtable updates om hierbij te helpen |
wli | void detach_pid(task_t *task, enum pid_type type) |
wli | { |
wli | int nr = __detach_pid(task, type); |
wli | if (!nr) |
wli | return; |
wli | for (type = 0; type < PIDTYPE_MAX; ++type) |
wli | if (find_pid(type, nr)) |
wli | return; |
wli | free_pidmap(nr); |
wli | } |
garoeda | de for() loop is het belangrijke deel hier |
garoeda | het doet het volgende: "voor alle types van process ID's, als we vinden dat dit ID nummer al in gebruik is, keer terug zonder iets te doen" |
garoeda | als het ID nummer compleet ongebruikt is wordt het van de bitmap geschrapt |
garoeda | de bitmap heeft een plaats voor ieder mogelijk pid nummer en als de bit er staat is het ID nummer in gebruik, als er geen bit staat is het nummer niet in gebruik |
garoeda | vraag: een 32k bitmap voor pids? |
garoeda | eigenlijk nee |
garoeda | de PID ruimte was eveneens vergroot zodat het mogelijk is om meer processen te draaien |
garoeda | de maximum toegelaten PID ruimte is 4M groot en de grootte is controleerbaar via sysctl |
garoeda | er zijn eigenlijk 2 niveaus in de map: |
garoeda | het eerste niveau wijst naar pagina's met een telling van de vrije pid's in die pagina |
garoeda | de tweede is een pagina waarvan de bits gebruikt worden om de individuele pids te volgen |
garoeda | vraag: uint32 |
garoeda | vraag: waarom dat niet gebruiken :) |
garoeda | de enige reden is dat de overhead in geheugen voor genoeg genoeg taken om een PID space van die grootte te gebruiken het onwerkbaar wordt, tenminste op 32bit |
garoeda | voor 64 bit machines met veel geheugen en een voldoende aantal tasks is het doenbaar maar het is niet nuttig wegens overhead |
garoeda | het is groot genoeg om de al de nummers van de tasks te bevatten voor een reele workload, die meestal niet meer is dan 100k in het grootste geval en sinds het scannen O(1) is (ik kom daar straks nog op terug) is de geheugenruimte willekeurig |
garoeda | je zal dat zienin alloc_pidmap() |
garoeda | scan_more: |
wli | offset = find_next_zero_bit(map->page, BITS_PER_PAGE, offset); |
wli | if (offset >= BITS_PER_PAGE) |
wli | goto next_map; |
wli | if (test_and_set_bit(offset, map->page)) |
wli | goto scan_more; |
garoeda | dit betekent dat het echt over de bitmap gaat en (in theorie) O(sizeof(pidspace)) nodig heeft, in praktijk domineren de cache effecten en het algoritme domineert direct tasklist scannen en is zoals verwacht O(1° |
garoeda | met enige extra indexeringsruimte kan met het O(1) maken voor het slechtste geval maar de algemene winst is is marginaal |
garoeda | toekomst: |
garoeda | de overblijvende tasklist scans zijn niet zo belangrijk voor de performantie als bovenstaand |
garoeda | in de core is er een weinig voorkomende operatie die de prioriteit van alle tasks die tot een bepaalde user behoren, en verschillende error paths die scannen naar taken die een zekere mm hebben |
garoeda | eveneens global capability mask setting en het versturen van een signaal naar alle tasks |
garoeda | het mm scannen teneinde core dumps te doen en OOM killing is niet beschouwd als zeer nuttig om te optimiseren (door mij) en het uid scannens is een zodanig zeldzame operatie dat het niet duidelijk is of het winst zou hebben bij het onderhouden van list links |
garoeda | enkele 'miscellaneous' andere gevallen komen ook voor |
garoeda | de ipt_owner_module van netfilter scant de tasklist om een taak te vinden die overeenkomt met task->comm |
garoeda | dit kan een nadelige invloed hebben op de prestatie voor machines die een netwerk intensieve workload hebben en ipt_owner maar er is niet voldoende infrastructuur om het als module te zien |
garoeda | er is ook een zeer slechte quadratisch werkdende tasklist scan in /proc om het lezen van de root /proc/ directery te simuleren, daar is nog geen goed oplossing voor gevonden |
garoeda | van een ding weten we zeker hoe we moeten werken: task validation |
garoeda | er is een nieuw mechanisme om reference counting te doen van de task structures zodat men garanties kan hebben of een task structure geldig blijft |
garoeda | er zijven verschillende delen in de kernel, met name vm86 en SBUS omgeving control drivers die referenties naar tasks behouden, maar de enige manier waarop ze (denken) dat te kunnen doen is taks structure pointers vergelijken in een tasklist scan |
garoeda | dit werkt niet echt omdat omdat de structures slab allocated zijn en kunnen hergebruikt worden door andere taken |
garoeda | de oplossing is nu: ofwel houden we een reference count bij van de task strcucture ofwel plaatsen we een hook in release_thread() |
garoeda | dit zijn duidelijke bugfixes dus er kan geen twijfel zijn dat deze strategie nuttig is |
garoeda | er is een extra infrastructure dat de potentie heeft om netfilter te laten werken met het hashtable update probleem |
garoeda | dat is, register functies die opgeroepen worden bij fork(), exec() en exit() en andere nuttige task gerelateerde events |
garoeda | op het moment zijn er niet echt veel verschillende gebruikers en gezien de uitzonderlijke toestand van dingen die het het nodig hebben zullen er waarschijnlijk nooit veel gebruikers zijn |
garoeda | maar het biedt de mogelijkheid om een infrastructure te hebben die toelaat om SBUS environment control, vm86, and netfilter modules te laten zijn en toch zeer efficient te zijn |
garoeda | vraag: ben je nog steeds een generische scanfunctie te voorzien met een callback ter vergelijking? |
garoeda | mijn intentie was om een zeer strikte controle van de gebruikers van die interface te doen en en het gebruik ervan enkel in op voorhand goedgekeurde catastrofische momenten toe te laten |
garoeda | zodat we reintroducties van tasklist scanning algoritmen of algehel slechte code kunnen voorkomen. ik ben er minder mee bezig de laatste tijd en ik betwijfel het of zulke toeganscontrole ooit populair zou zijn |
garoeda | vraag: LSM heeft hooks in die plaatsen die de updates zouden kunnen doen (gelijkaardige task ornaments zouden helpen, denk ik) |
garoeda | ik was bezig met task ornaments te schrijven voor deze dingen =) |
garoeda | de LSM hooks hergebruiken voor dit soort events lijkt heel interessant maar het is moeilijk te verdedigen dat je zoiets als ipt_owner's ->comm hashing in iets wat verondersteld is een security model te zijn, een hernoemingschema zou misschien handig zijn om dit probleem op te lossen |
garoeda | een toekomstige onderzoeksrichting die zeer zeker zal gebeuren is een methode zoeken die de statisch gealloceerde geheugenruimte van de pidhashes reduceert |
garoeda | een toekomstige richting zou zijn om een vergelijking te doen van iets deterministischere multilevel bitmap aanpak met de methode die we nu gebruiken |
garoeda | zodat we kunnen bepalen of de gemiddelde performantie in reele workloads negatief beinvloedt wordt door de cache effecten van altijd te updaten tot het punt waarop de winst in determinisme in de slechtste gevallen van het huidige algortime niet meer de moeite waard is |
garoeda | ik ben niet echt van plan dat verder te onderzoeken, tenzij ik echt verveeld ben, de slechtste gevallen waren onmogelijk te produceren |
garoeda | merk ook op dat op 32 bit machines met PAE (die 3 niveaus pagetables nodig heeft) de 2de niveau pagetables (pmd's) altijd geinstantieerd worden |
garoeda | dit betekent 12KB geheugenoverhead per task |
garoeda | 32K tasks * 12 KB == 786MB, dus pmd's gebruiken op dat punt al het lowmem, dus voor een zeer belangrijk geval is 32K ruimte al genoeg |
garoeda | last but not least, wens ik Ingo Molnar te bedanken, zijn bugfixes en cleanups en promotie van deze methodes hebben ze in de kernel gekregen |
garoeda | okee, bedankt voor iedereen die is komen opdagen en die geluisterd heeft ook =) |
garoeda | (einde spreekbeurt en applaus) |
erikm | garoeda: goede vertaling |
garoeda | thnx erikm :-) |
garoeda | ik ga nu nog proberen het begin te vertalen dat ik gemist heb |
erikm | garoeda: ik had het niet nodig (ik heb geen problemen met engels), maar ik was nieuwsgierig naar de vertaling |
* erikm vraagt zich af of sarnold *enig* idee heeft waar wij het over hebben |
garoeda | erikm: hehe, ik vond deze moeilijk om te vertalen |
Geryon | idd nice job garoeda :) |