Automatická paralelizace a automatická vektorizace

Auto-Parallelizer a Auto-Vectorizer jsou navrženy tak, aby poskytovaly automatické zvýšení výkonu smyčky ve vašem kódu.

Automatický paralelizátor

Přepínač kompilátoru /Qpar umožňuje automatické paralelizaci smyček v kódu. Když tento příznak zadáte beze změny existujícího kódu, kompilátor vyhodnotí kód tak, aby našel smyčky, které by mohly těžit z paralelizace. Protože může najít smyčky, které moc nefungují, a proto nebudou mít prospěch z paralelizace, a protože každý nepotřebný paralelizace může zakreslit vytvoření fondu vláken, další synchronizace nebo jiného zpracování, které by se místo jeho vylepšování chýlilo ke zpomalení výkonu, je kompilátor konzervativnější při výběru smyček, které paralelizuje. Představte si například následující příklad, ve kterém horní mez smyčky není v době kompilace známá:

void loop_test(int u) {
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

Protože u může být malá hodnota, kompilátor nebude tuto smyčku automaticky paralelizovat. Přesto ale můžete chtít, aby byla paralelizovaná, protože víte, že u bude vždy velká. Pokud chcete povolit automatické paralelizace, zadejte smyčku #pragma(hint_parallel(n)), kde n je počet vláken, která se mají paralelizovat napříč. V následujícím příkladu se kompilátor pokusí paralelizovat smyčku napříč 8 vlákny.

void loop_test(int u) {
#pragma loop(hint_parallel(8))
   for (int i=0; i<u; ++i)
      A[i] = B[i] * C[i];
}

Stejně jako u všech direktiv pragma se podporuje také alternativní syntaxe __pragma(loop(hint_parallel(n))) pragma.

Existuje několik smyček, které kompilátor nemůže paralelizovat, i když ho chcete. Tady je příklad:

#pragma loop(hint_parallel(8))
for (int i=0; i<upper_bound(); ++i)
    A[i] = B[i] * C[i];

Funkce upper_bound() se může změnit při každém zavolání. Protože horní mez nemůže být známa, kompilátor může vygenerovat diagnostickou zprávu, která vysvětluje, proč nemůže paralelizovat tuto smyčku. Následující příklad ukazuje smyčku, kterou lze paralelizovat, smyčku, kterou nelze paralelizovat, syntaxi kompilátoru pro použití na příkazovém řádku a výstup kompilátoru pro každou možnost příkazového řádku:

int A[1000];
void test() {
#pragma loop(hint_parallel(0))
    for (int i=0; i<1000; ++i) {
        A[i] = A[i] + 1;
    }

    for (int i=1000; i<2000; ++i) {
        A[i] = A[i] + 1;
    }
}

Kompilace pomocí tohoto příkazu:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:1

vrátí tento výstup:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized

Kompilace pomocí tohoto příkazu:

cl d:\myproject\mylooptest.cpp /O2 /Qpar /Qpar-report:2

vrátí tento výstup:

--- Analyzing function: void __cdecl test(void)
d:\myproject\mytest.cpp(4) : loop parallelized
d:\myproject\mytest.cpp(4) : loop not parallelized due to reason '1008'

Všimněte si rozdílu ve výstupu mezi dvěma různými možnostmi /Qpar-report (úroveň generování sestav automatického paralelizátoru). /Qpar-report:1 výstupy zprávy paralelizátoru pouze pro smyčky, které jsou úspěšně paralelizovány. /Qpar-report:2 výstupy zprávy paralelizátoru pro úspěšné i neúspěšné paralelizace smyčky.

Další informace o kódech důvodů a zprávách naleznete v tématu Vectorizer a Parallelizer Messages.

Automatický vektorizátor

Auto-Vectorizer analyzuje smyčky v kódu a pomocí vektorových registrů a instrukcí v cílovém počítači je spustí, pokud je to možné. To může zlepšit výkon kódu. Kompilátor cílí na instrukce SSE2, AVX a AVX2 v procesorech Intel nebo AMD nebo NEON na procesorech ARM podle přepínače /arch .

Auto-Vectorizer může generovat jiné instrukce, než je určeno přepínačem /arch . Tyto pokyny jsou chráněny kontrolou modulu runtime, aby se zajistilo, že kód stále běží správně. Například při kompilaci /arch:SSE2může být vygenerován příkaz SSE4.2. Kontrola modulu runtime ověří, jestli je na cílovém procesoru k dispozici SSE4.2, a pokud procesor tyto pokyny nepodporuje, přeskočí na verzi smyčky jiné než SSE4.2.

Ve výchozím nastavení je povolen automatický vektorizátor. Pokud chcete porovnat výkon kódu při vektorizaci, můžete pomocí smyčky #pragma(no_vector) zakázat vektorizaci jakékoli dané smyčky.

#pragma loop(no_vector)
for (int i = 0; i < 1000; ++i)
   A[i] = B[i] + C[i];

Stejně jako u všech direktiv pragma se podporuje také alternativní syntaxe __pragma(loop(no_vector)) pragma.

Stejně jako u automatického paralelizátoru můžete určit možnost příkazového řádku /Qvec-report (úroveň generování sestav auto vektorizátoru) a hlásit buď úspěšně vektorizované smyčky ,/Qvec-report:1 nebo úspěšně i neúspěšně vektorizované smyčky/Qvec-report:2).

Další informace o kódech důvodů a zprávách naleznete v tématu Vectorizer a Parallelizer Messages.

Příklad znázorňující, jak vektorizátor funguje v praxi, viz Project Austin Část 2 ze 6: Page Curling

Viz také

loop
Paralelní programování v nativním kódu
/Qpar (automatická paralelizace)
/Qpar-report (úroveň generování sestav s automatickou paralelizací)
/Qpar-report (úroveň generování sestav s automatickou vektorizací)
Zprávy nástrojů pro vektorizaci a paralelní zpracování