funkcionálně.cz

Přední český blog o funkcionálním programování, kde se o funkcionálním programování nepíše
««« »»»

Hyper-threading aneb "Jak sakra může běžet víc vláken na jednom jádře?"

21. 1. 2015

Nedávno jsem narazil na článek, který testoval, jak se pod zátěží chová procesor se zapnutým hyper-threadingem. Autor onoho textu na základě měření a vlastních předpokladů vyslovoval divoké domněnky a spekulace, které bohužel neměly příliš mnoho společného s chladnou realitou křemíku.

Otázka tedy zní: Jak je to vlastně s hyper-threadingem a simultaneous multithreading (SMT) obecně? Jak můžou běžet dvě vlákna na jednom procesorovém jádře zároveň?

Odpověď je jednoduchá: SMT se stará jenom o to, aby procesor měl stálý přísun nezávislých instrukcí k vykonání na out-of-order jádru.

Téměř všechna moderní CPU jsou pipelinované out-of-order superskalární procesory1 , které dokážou dělat mnoho věcí najednou. Nejde jen o souběžná vlákna běžící na různých jádrech multiprocesoru, ale také o schopnost naráz vykonávat několik instrukcí jednovláknového programu (jde o takzvaný instuction level parallelism, zkráceně ILP). Tohle je možné právě proto, že i když se současné procesory navenek tváří, jako kdyby plně respektovaly Von Neumannovu architekturu, jejich vnitřní fungování v mnohém připomíná data-flow model. Tento způsob práce se označuje jako out-of-order execution (OOO). CPU nezpracovává jednu instrukci za druhou, ale načítá a dekóduje2 jich několik v každém taktu. Tyto instrukce jsou poté umístěny do re-order bufferu (ROB), což je ve své podstatě fronta dekódovaných mikrooperací3 , které čekají na vykonání. Out-of-order jádro se poté snaží dynamicky tyto instrukce provést na dostupných funkčních jednotkách procesoru (nejnovější Intely, které je označují jako porty, jich mají osm) a zkouší vybrat co nejvíce instrukcí, které mohou běžet najednou. Když jsou operace nezávislé (tj. nezávisí na žádných předchozích) mohou být vykonány paralelně na různých portech. To je obzvláště výhodné, když jde o load4 instrukce načítající data z paměti. Než blok dat dorazí z RAM do cache CPU, může to trvat až několik stovek taktů. Pokud OOO engine dokáže zařídit, aby nezávislé load operace běžely paralelně, může tak dramaticky zrychlit program5 . Pokud ale instrukce A závisí na B, A musí počkat ve frontě re-order bufferu dokud B není plně uskutečněna a teprve poté dostane svojí nanosekundu slávy. Moderní procesory vynakládají velké úsilí, plochu a energii na to, aby zaručily, že ve frontě jsou pořád nějaké nezávislé instrukce připravené k vykonání - prefetchují data, odhadují podmíněné skoky a divoce spekulují, jen aby objevily tu další load instrukci a narazily na ten další cache-miss.

Bohužel ILP má své limity a v běžných programech je jen omezené množství nezávislých instrukcí. Ivan Godard z Mill Computing říká "Tajemství out-of-order procesorů je, jak málo out-of-order vlastně jsou"6 ". Každé jádro Haswellu je schopné načíst, dekódovat a vykonat 4 instrukce v každém taktu8 , mají re-order buffer délky 19212 a krotí smečku 168 virtuálních general purpose registrů7 , ale jen zřídka dokáže tyto prostředky naplno využít. Běžný kód zkrátka neobsahuje dost ILP na to, aby byl procesor plně vytížený. Některé zdroje uvádějí, že běžné maximum ILP je někde kolem 2.5.

Právě v tomto místě přichází ke slovu hyper-threading. Když máme velice paralelní procesory, které většinu času nejsou schopny zcela využít svůj potenciál, je jenom logické před jádro přidat druhý frontend, který načítá a dekóduje instrukce jiného vlákna a který zásobí out-of-order strojovnu novým proudem instrukcí, v němž je s trochou štěstí možné najít dostatečné množství nezávislých operací, které zužitkují kapacitu dostupného hardwaru.

Taková je podstata hyper-threadingu a SMT9 . Nejde o hardwarové context-switche10 , nejde o to, že se Von Neumannovský procesor maskuje za dva (jako je tomu v případě barell temporal multithreading nebo super-threading), jde jen o to využít všechny možnosti procesoru, které by jinak ležely ladem.11

Nevýhodou hyper-threadingu je skutečnost, že najednou běží víc nezávislých vláken, které sdílejí dostupnou cache. Každé hyper-vlákno má tedy k dispozici efektivně poloviční množství cache, než kdyby procesor neměl povolený HT. To může v některých případech mít značný vliv na rychlost programu. I tady platí staré rčení: "Když jsi s rozumem v koncích, použij perf".


Dále k tématu:


@kaja47, kaja47@k47.cz, deadbeef.k47.cz, starší články