Hoe u een contextswitch effectief kunt begrijpen
Als je je verdiept in de wereld van CPU’s, is het best bizar hoe ze meerdere taken tegelijk aankunnen zonder de bal te laten vallen. Vroege CPU’s draaiden volledig om die rechtlijnige verwerking, wat simpel klinkt, maar de snelheid ernstig beperkte omdat ze moesten wachten op data van het RAM-geheugen of, erger nog, de harde schijf. Je zat daar maar te kijken hoe je CPU inactief was omdat hij wachtte op data die gewoon niet direct beschikbaar was. En als de harde schijf erbij betrokken is? Ja, dan wordt je systeem nog trager, omdat de snelheid van de schijf ervoor zorgt dat RAM op een Ferrari lijkt, terwijl het meer op een fiets lijkt.
Gelukkig zijn processoren tegenwoordig geen makkelijke prooien meer – ze doen allerlei slimme dingen, zoals out-of-order-uitvoering en multithreading. Out-of-order betekent dat de CPU vooruitkijkt en de instructies herschikt zodat hij altijd bezig blijft, in plaats van te wachten. Multithreading betekent dat het meerdere threads kan uitvoeren, waardoor het lijkt alsof er veel werk tegelijk wordt gedaan – ook al kan het technisch gezien niet twee dingen tegelijk doen. Achter de schermen schakelt het razendsnel tussen threads om alle cores bezig te houden, wat een contextswitch wordt genoemd. Eerlijk gezegd is het best bizar hoe snel het allemaal gebeurt – de meeste gebruikers merken de korte pauzes niet, maar die wisselingen vinden wel constant op de achtergrond plaats.
Hoe werkt een contextswitch?
Dit is waar de magie ontstaat – of misschien een beetje chaos, afhankelijk van je configuratie. In principe moet de CPU de status van de oude thread opslaan, zodat deze later verder kan waar hij gebleven was. Dat betekent dat alle belangrijke informatie – registerwaarden, programmatellers, enz.– wordt opgeslagen in een datastructuur die een Process Control Block of een switchframe wordt genoemd. In Windows kun je dit soms in actie zien door Taakbeheer te openen en details zoals threadinformatie te bekijken, hoewel dit meestal automatisch achter de schermen wordt afgehandeld. In Linux tonen tools zoals htop of `top` de threadstatus en helpen ze te begrijpen wat er onder de motorkap gebeurt.
Zodra de oude thread veilig is opgeslagen, kiest de CPU de volgende thread. Meestal gooit de scheduler er eentje uit een wachtrij – zie het als een rij taken die klaar zijn om te starten – of krijgt hij een seintje van een interrupt, zoals een hardwaresignaal dat iets voltooid is of aandacht nodig heeft. De data voor deze nieuwe thread wordt teruggeladen in de CPU-registers, en het is alsof er een schakelaar wordt omgezet. Die thread gaat dan verder waar hij gebleven was, wat voor de gebruiker naadloos lijkt, maar achter de schermen razendsnel is.
Prestatie-impact
Nu komt het addertje onder het gras: elke keer dat er een contextwisseling plaatsvindt, kost het wat tijd. Niet veel, aangezien modern geheugen behoorlijk snel is, maar genoeg om van belang te zijn in omgevingen met hoge prestaties. Bij het wisselen bevatten de cache en buffers van de CPU – die kleine snelheidsboosters – niet langer de juiste gegevens voor de nieuwe thread, wat leidt tot cachemissers. Het delen van gegevens binnen hetzelfde proces houdt dit verlies minimaal, maar schakelen tussen verschillende processen of niet-gerelateerde threads? Ja, dan heb je het over meer cachemissers en TLB-flushings, die alles nog verder vertragen. In sommige configuraties kan dat leiden tot merkbare lag of vertragingen.
Nog iets vreemds: hoewel hardware contextswitches kan uitvoeren, geven de meeste besturingssystemen de voorkeur aan softwarematige, omdat ze slimmer kunnen bepalen wat er moet worden opgeslagen en hersteld. Hardware weet niet wat belangrijk is, wat betekent dat het een soort voorhamer is: alle registers opslaan, ongeacht de relevantie. Dus het besturingssysteem grijpt in en zorgt voor het daadwerkelijke opslaan en herstellen, inclusief zaken als floating-point data, die hardwarematige switching mogelijk overslaat. Daarom zijn softwarematige contextswitches de norm; ze zijn over het algemeen efficiënter, maar gaan wel ten koste van de prestaties.
Conclusie
Al met al is een contextswitch een fundamenteel onderdeel van multitasking: CPU’s laten meerdere threads tegelijk draaien zonder taken te laten vallen. Het houdt in dat de status van de huidige thread wordt opgeslagen en de volgende wordt geladen, wat, ondanks de supersnelheid, toch wat prestaties kost. Die kleine vertragingen stapelen zich op als je veel schakelt, vooral tussen verschillende processen of zware workloads. Toch is het de prijs die je betaalt voor een moderne multi-core CPU die alles aankan, van gamen tot het verwerken van gegevens in een browser.