Nvidias kontextbekymmer

Den stora skillnaden i prestanda mellan Nvidia Maxwell och AMD GCN kan till viss del tillskrivas optimeringen för AMD:s hårdvara, men en fundamental skillnad i hur Maxwell-arkitekturen hanterar köer av beräkningsuppgifter spelar också in. Eftersom Maxwell exekverar beräkningsköer sekventiellt måste ett kontextbyte ske för att hårdvaran ska kunna växla från en uppgift till en annan.

Vid ett kontextbyte måste alla nya beräkningar associerade med den nuvarande uppgiften stoppas, de nuvarande beräkningarna i kön måste slutföras, kontext-data som hör till den nya uppgiften måste ersätta data från föregående och beräkningar för den nya uppgiften ska börja matas till hårdvaran. Ett sätt att hantera detta utan Asynchronous Compute är att använda prioriteringsordningar för beräkningsköerna och låta uppgifter med hög prioritet pausa andra med lägre prioritet.

Pascal blir dynamisk

Detta kan minska latensen för de uppgifter som är viktiga för stunden, men det ökar inte utnyttjandet av hårdvarans tillgängliga resurser mer effektivt. I och med att AMD:s GCN-arkitektur är utrustad med ACE-enheter som administrerar den parallella exekveringen av rendering och compute uppstår inte behovet av att utföra prestandamässigt kostsamma kontextbyten, något som Nvidias Maxwell-arkitektur blir tvungen att göra eftersom den saknar hårdvara för att hantera parallell asynkron exekvering av olika typer av köer.

Nvidia - Statisk partitionering.jpg
Nvidia - Dynamisk partitionering.jpg

Nvidias Mark Aevermann bekräftar problematiken och menar att det åtgärdats med arkitekturen Pascal. Där introduceras en teknik som kallas dynamisk partitionering, eller dynamisk lastbalansering, som gör det möjligt för grafikkretsen att dynamiskt fördela resurserna efter behoven. Om spelmotorn kräver många grafikjobb men färre compute-jobb fördelas resurserna i enlighet med detta, och vice versa om behoven för compute-jobb eller datakopieringsjobb är större.

Detta ser till att grafikkretsens beräkningsenheter hålls sysselsatta konstant, något som inte var fallet med tidigare statiska partitionering i föregående generationer. Mark Aevermann förklarar att problematiken dyker upp när balansen mellan de statiska partitionerna inte matchar behoven.

Statisk partitionering påverkar inte prestanda för kontextuella byten. Det kan däremot leda till outnyttjade hårdvaruresurser om en samling arbetsuppgifter slutförs före en annan. Om ett grafikjobb exempelvis slutförs tidigt medan ett compute-jobb fortsätter att beräknas inom ramarna för den resurspartition den tilldelats så kommer grafikjobbets resurspartition att sitta inaktiv till dess att compute-jobbet är klart. Inaktiva hårdvaruresurser innebär så klart sämre prestanda än vad som finns tillgängligt i hårdvaran, och därför lade vi till dynamisk lastbalansering i Pascal.

Pixelperfekt förutseende

Att kunna partitionera upp grafikkretsens beräkningsresurser är dock bara en del i vad som krävs för asynkrona beräkningar. Att beräkningsresurserna kan partitioneras om dynamiskt efter behov gör det möjligt att utnyttja dessa bättre och uppnå bättre prestanda, men för att reducera latensnivåer behöver utvecklarna kunna styra över prioriteringen av olika jobb.

Ett enda renderingskommando kan innehålla hundratals uppritningskommandon (eng. draw calls), och varje kan innehålla hundratals trianglar som individuellt består av hundratals pixlar vilka ska bearbetas och renderas. I en traditionell lösning för detta, som använts i Maxwell och tidigare Nvidia-arkitekturer, måste alla dessa beräkningar utföras innan ett byte till ett annat jobb kan ske. I Pascal har Nvidia löst detta med något som kallas Pixel Level Preemption.

Pixel_Level_Preemption.jpg
Thread_Level_Preemption.jpg

Det innebär att arkitekturen på hårdvaru- och mjukvarunivå övervakar processen för rendering. Kommer det en begäran om företräde (eng. preemption) i kön kan Pascal pausa en uppgift på pixelnivå, för att sedan återuppta arbetet när den högprioriterade uppgiften är slutförd. Detta innebär att det redan utförda jobbet på den pausade uppgiften inte går förlorat när den prioriterade släpps förbi i kön.

Ett liknande system används även för compute. Detta kallas Thread-Level Preemption och fungerar på så sätt att compute-jobb delas upp i ett antal rutnät av trådblock, där varje block består av ett antal programtrådar. När systemet får en begäran om företräde slutförs arbetet på trådarna som för tillfället beräknas på grafikkretsens beräkningskluster, så kallade Stream Multiprocessor (SM:s) i Nvidias arkitekturer.

Övriga trådar pausas och information om hur långt de kommit i arbetsuppgiften sparas, vilket gör det möjligt att återuppta arbetet senare. Kombinationen av Pixel-Level Preemption och Thread-level Preemption med ska enligt Nvidia ge Pascal det fulla stöd för Asynchronous Compute som Maxwell-generationen saknade.