Aktuality  |  Články  |  Recenze
Doporučení  |  Diskuze
Grafické karty a hry  |  Procesory
Storage a RAM
Monitory  |  Ostatní
Akumulátory, EV
Robotika, AI
Průzkum vesmíru
Digimanie  |  TV Freak  |  Svět mobilně

DirectX 12 Multi-engine: asynchronní shadery v praxi

20.11.2015, Pavel Šantrůček, recenze
DirectX 12 Multi-engine: asynchronní shadery v praxi
Co jsou to asynchronní shadery a k čemu vlastně slouží? Jak zapadají do kontextu DirectX 12? Které grafické karty je podporují, které zase ne a proč? V dnešním článku odpovíme právě na takovéto otázky.

Simultánní Multi-threading


Příkazy, které jsou na výpočetní jednotky grafické karty zasílány z různých enginů, je tedy zapotřebí spouštět na těchto jednotkách GPU co nejefektivněji. Proto je třeba plánovat poněkud pečlivěji, a jak později uvidíte, správné plánování (sheduling) je základem všeho a u asynchronních shaderů to platí dvojnásobně.

Následující obrázky jste sice už asi viděli mnohokrát, ale nedá se nic dělat, použít je musíme znovu, protože jsou opravdu klíčové. Tentokrát si je ale popíšeme trochu podrobněji.

Předpokládejme, že chceme na výpočetních jednotkách grafické karty spustit dvě úlohy. Jednu grafickou úlohu, kterou zaslal engine GCP a druhou úlohu výpočetní, kterou chce spustit zase engine ACE.

1. Simple task switching

Task switch


Obrázek představuje asi ten nejjednodušší způsob plánování. Přístup k výpočetním zdrojům GPU zde dostávají obě úlohy střídavě. Určitý časový úsek má ke zdrojům GPU přístup úloha jedna, další časový úsek pak zase úloha druhá. Jedná se tedy o jednoduché přepínání úloh, a jak už asi sami tušíte, vlastně se nejedná o paralelní zpracování úloh, ale o čistě sériové. Rozdíl je pouze v tom, že exekuce těchto úloh je prováděna buďto jedna po druhé (když skončí úloha jedna, je spuštěna úloha druhá), nebo je exekuce úloh časově rozdělena (k výpočetním zdrojům mají úlohy přístup v pevných časových intervalech).

Pokud tedy jedna úloha zabere čas 20 ms a druhá zase 10 ms, pak při tomto typu shedulingu, výsledný čas bude vždy dán jejich součtem, tedy 30 ms a nic na tom nezmění ani rychlé přepínání úloh v intervalech řekněme 1 ms. Ba co víc, častým přepínáním úloh vznikají ještě další prodlevy dané takzvaným Context Switch, kdy je třeba nejdříve jednu úlohu zastavit a uložit její pracovní data (Working set), nastavit data úlohy nové a teprve nakonec tuto novou úlohu konečně spustit.

2. Pre-emption

Preemption


Druhý způsob plánování je velmi podobný tomu prvnímu, pouze s tím rozdílem, že každá úloha má nastavenu svou exekuční prioritu. Pokud se tedy v některé z příkazových front objeví úloha s nastavenou prioritou vyšší, druhá úloha, která je zrovna na řadě, jí musí dát přednost a počkat, dokud se úloha s vyšší prioritou nedokončí.

Opět vidíte, že obě úlohy z různých enginů nejsou zpracovávány paralelně, ale opět jedna po druhé. Výhodou tohoto řešení je pouze to, že pokud potřebujeme nějakou úlohu spustit přednostně (urychlit spuštění), pak nastavením její vyšší priority toho také docílíme. Opět zde ale hrozí „nebezpečí“ další režie v podání Context switch.

3. Fine-grained sheduling

SMT


Tento způsob plánování jako jediný přináší kýžený efekt asynchronního zpracování úloh. Jedná se vlastně o způsob práce velmi podobný SMT (Simultaneous Multi-threading), kdy jedna významnější úloha běží na výpočetních jednotkách grafické karty, a druhá jednodušší úloha čeká na okamžik, kdy se zpracovávání první úlohy z nějakého důvodu přeruší (vznikne stall). Plánovač úloh této „bubliny“ ve zpracovávání první úlohy okamžitě využije a na výpočetní jednotky, které by za normálních okolností stály a nic nedělaly, spustí exekuci úlohy druhé. Konečným výsledkem je pak lepší (vyšší) využití výpočetních zdrojů GPU a samozřejmě také zkrácení latence snímku.

A kde se tyto „bubliny“ berou? Nejvíce těchto „bublin“ vzniká při zpracovávání grafických úloh. Při grafických operacích pomocí standardní grafické pipeline nejsou prakticky nikdy vytíženy naráz všechny zdroje (výpočetní jednotky) grafické karty a značnou částí těchto zdrojů je tak poměrně zbytečně plýtváno. Ačkoliv je totiž práce na GPU výsostně paralelní záležitostí, grafická pipeline a její jednotlivé zastávky (Stages) jsou prováděny sériově a když se věcem nedaří, tak poměrně značná část výpočetních jednotek musí čekat na dokončení stage předchozí nebo naopak stage následující, která ještě není dokončena

Za správné plánování řazení úloh na výpočetní jednotky GPU je odpovědný nejen samotný konkrétní engine, v případě AMD pak GCP nebo ACE, ale i další podřízené hardwarové jednotky (Dispatch processor). Samozřejmě také samotné výpočetní jednotky musí být schopné reagovat rychle a nově zařazenou úlohu spustit bez zbytečného prodlení. V každém případě, všechny tyto jednotky na grafickém čipu zabírají nějaké to místo, konzumují nějaký ten počet tranzistorů a samozřejmě nezbytně také vyžadují více energie.

Toliko tedy k teorii kolem asynchronních shaderů a Multi-engine. Pokud bychom mohli vše shrnout do pár vět, znělo by to asi následovně.
  1. Pokud mluvíme o asynchronních shaderech, máme tím na mysli souběžné zpracování úloh grafických a výpočetních. Souběžné zpracování pouze výpočetních shaderů není nic nového, to už známe z minulých verzí DirectX.
  2. Abychom mohli grafické a výpočetní úlohy pod DirectX 12 spustit souběžně, jsou k tomu zapotřebí dvě základní věci:
    • Multi-engine, tedy autonomní jednotky (enginy) na grafické kartě, které se umějí postarat zvlášť o frontu příkazů grafických a zvlášť o fronty (může jich být více) příkazů výpočetních.
    • Grafické i výpočetní enginy, společně s dalšími plánovacími jednotkami (obecně GPU Sheduler), musí umět plánovat a řadit grafické a výpočetní úlohy na výpočetní jednotky GPU tak, aby pracovaly souběžně, tedy pomocí simultánního multi-threadingu.

API paralel

Pokud jediná z těchto podmínek není splněna, žádné souběžné zpracování grafických a výpočetních úloh se nekoná, vše je prováděno sériově a latence finálního snímku narůstá.

Na závěr teorie kolem asynchronních shaderů je třeba poznamenat, protože lidé si to stále vysvětlují jinak, že Multi-engine jsou pevnou součástí DirectX 12 a jeho exekučního modelu.

Jedinou otázkou tedy je, jak dobře, či jak špatně, Multi-engine podporují jednotliví výrobci grafických čipů.
Doporučujeme náš velký přehled desktopových grafických čipů.