OpenMP


podle Blaise Barney, Lawrence Livermore National Laboratory

Struktura:
  1. Základní informace
    1. Co je to OpenMP?
    2. Jak OpenMP funguje?
    3. Jak udělat program vícevláknový ?
    4. Váš úkol
    5. Co zde chybí?
    6. Odkazy dále
  2. OpenMP direktivy
    1. Obecná pravidla pro zápis
    2. Ukázka principu zápisu OpenMP direktivy
    3. Direktiva "parallel"
    4. Direktiva "for"
    5. Direktiva "single"
    6. Direktiva "master"
    7. Direktiva "critical"
    8. Direktiva "atomic"
  3. OpenMP vlastnosti
    1. Co to je?
    2. Vlastnost "shared"
    3. Vlastnost "private"
    4. Vlastnost "firstprivate"
    5. Vlastnost "lastprivate"
    6. Vlastnost "default"
    7. Vlastnost "reduction"
  4. OpenMP operace
    1. Operace "barrier"
    2. Operace "flush"
    3. Operace s vlákny
    4. Operace s časem
    5. Operace se OpenMP zámky
  5. Ukázkové OpenMP kódy
    1. Hello World (ukázka direktivy parallel)
    2. Vektorový součet (ukázka direktivy parallel a for)
    3. Vektorový součet (ukázka direktivy parallel for)
    4. Kritická sekce(ukázka direktivy critical)

Základní informace

Co je to OpenMP?
sjednocené API pro programování vícevláknových aplikací.
více viz zde

Jak OpenMP funguje?
Ve vybraných částech kódu (dále označovaných jako paralelní bloky = parallel regions) je pomocí fork-join mechanismu vytvořen daný počet vláken a tak je tento paralelní blok řešen vícevláknově. Mimo tyto paralelní bloky existuje pouze jedno vlákno hlavního procesu.
Pozn. Nedoporučuje se míchat tento způsob vytváření a zániku threadů s tím jak byl probírán v předmětu OSY (POSIX thready = pthread_create, pthread_join, pthread_exit).
více viz zde

Jak udělat program vícevláknový ?
Stačí dodržet tyto 4 kroky
  1. Stanovit si, které části kódu (nejčastěji cykly) chci aby běžely vícevláknově, toto udělám pomocí OpenMP direktiv = vytvoříme paralelní bloky. Díky tomu, že vytvoření a zánik vláken má jistou režii, je snaha paralelizovat co časově největší části kódu.
  2. Stanovit pro jednotlivé proměnné jejich OpenMP vlastnosti. Je snaha co nejvíce se vyhybat sdíleným proměnným.
  3. V rámci paralelních bloků se vyhnout "thead-unsafe" operacím.
  4. Zkompilovat program pomocí "gcc -fopenmp -O3", první volba je pro zpracování OpenMP, druhá zapíná optimalizace kompilátoru.
Jaký je váš úkol?
Pro každý výpočetní uzel vytvořit sdílenou frontu nebo zásobník, kterou budou využívat jednotlivá vlákna (jejich počet volte rovných 4) v daném výpočetním uzlu. Pro vzájemné vyloučení vláken při přístupu využijte OpenMP zámky, kritické sekce nebo atomické operace.
Co zde chybí?
Tento text slouží jako úvod do OpenMP proto zde chybí popis pokročilejší mechanismů jako direktiva sections, dynamicky měnitelný počet vláken nebo vnořené paralelní bloky (nested parallel regions).

Odkazy dále

OpenMP direktivy

Obecná pravidla pro zápis
Před každým paralelním blokem je na jedné programované řádce uvede jediná OpenMP direktiva a dále volitelný počet jejich parametrů.
Pozn. Jedna programová řádka může obsahovat i více řádek v kódu, pokud je předchozí řádka ukončena pomocí znaku zpětné lomítko("\").
více viz zde

Ukázka principu zápisu OpenMP direktivy

C / C++ - General Code Structure
#include <omp.h>

main ()  {

int var1, var2, var3;

 zde pracuje jen hlavni vlakno procesu (serial code) 
      .
      .
      .

nasleduje paralelni blok (Beginning of parallel section. Fork a team of threads.
Specify variable scoping) 

#pragma omp parallel private(var1, var2) shared(var3)
  {
  Uvnitr paralelniho bloku pracuje vice vlaken (Parallel section executed by all threads) 
        .
        .
        .
  Promenne var1, var2 jsou privatni = kazde vlakno v tomto bloku ma vlastni 
  Promenna var3 je sdilena vsemi vlakny      
        .
        .
        .
        
  Na konci bloku se nove vznikla vlakna zrusi (All threads join master thread and disband) 
  }  
 opet pracuje jen hlavni vlakno procesu (serial code) 
      .
      .
      .

}

Direktiva "parallel"

Možné parametry jsou: Pokud je podmínka splněna (když není uvedena, je splněna), je vytvořen
daný počet vláken, jinak se bude paralelní blok provádět sekvenčně. V tomto paralelním bloku budou mít proměnné tyto OpenMP vlastnosti.
Přesné chování
Omezení
Počet vláken u direktivy "parallel"
Počet vzniklých vláken je řízen těmito výrazy (v tomto pořadí, důležitý je první platný výraz)
  1. pokud je uvedena, vyhodnotí se if. Pokud není splněna, bude provádět jako sekvenční kód.
  2. pokud je uvedena, provede se dle nastavení num_threads
  3. pokud bylo uvedeno, provede se dle nastavení při posledním volání fci omp_set_num_threads()
  4. pokud je uvedena, provede se dle nastavení proměnné prostředí OMP_NUM_THREADS
  5. v závisloti na implementaci nebo dynamicky.
Pozn: Direktivu "parallel" a "for" je mozno spojit do "parallel for" viz
zde
více viz zde

Direktiva "for"

Konstrukce pro paralelizaci for-cyklu uvniř paralelního bloku, možné parametry jsou: Pokud je podmínka splněna (když není uvedena, je splněna), je vytvořen
daný počet vláken, jinak se bude paralelní blok provádět sekvenčně. V tomto paralelním bloku budou mít proměnné tyto vlastnosti (TODO viz)
Přesné chování
Omezení:
Pozn: Direktivu "parallel" a "for" je mozno spojit do "parallel for" viz zde
více viz zde

Direktiva "single"

Specifikuje část paralelního bloku, kterou provádí pouze jedno vlákno
Možné parametry jsou: Omezení
více viz zde

Direktiva "master"

Specifikuje část paralelního bloku, kterou provádí pouze master vlákno (to s číslem vlákna rovným 0), ostatní vlákna zpracovávají kód následující po této části bloku. Omezení

Direktiva "critical"

Specifikuje část paralelního bloku, kterou může současně provádět pouze jedno vlákno (kritická sekce).
Možné parametry jsou: Omezení
Ukázka zde

Direktiva "atomic"

Specifikuje paměťové operace, které mají být atomické.
více viz zde
Ukázka zde

vlastnosti proměnných

Co to je?
Určují vlastnosti proměnných vzhledem k paměťovým operacím. Pozor !!! Pokud budou vlastnosti použity na pointer, aplikují se pouze na tento pointer nikoliv na data na která ukazuje.
vlastnost shared
Určuje, že daná proměnná bude sdílena všemi vlákny.
více viz zde
vlastnost private
Určuje, že daná proměnná bude lokální ve vlákně, tozn. že každé vlákno bude mít nezávislou instanci této proměnné. Proměnná je vytvořena jako neinicializovaná.
více viz zde
vlastnost firstprivate
Určuje, že daná proměnná bude lokální ve vlákně, tozn. každé vlákno bude mít nezávislou instanci této proměnné. Proměnná je vytvořena s původní hodnotou, kterou mělqa před vstupem do paralelního bloku.
více viz zde
vlastnost lastprivate
Určuje, že daná proměnná bude lokální ve vlákně, tozn. že každé vlákno bude mít nezávislou instanci této proměnné. Hodnota proměnná z poslední iterace bude překopírována do proměnné hlavního vlákna procesu (bude platná po skončení paralelního bloku).
vlastnost default
Určuje, jakou vlastnost budou mít defaultně všechny proměnné použité v paralelním bloku (pokud nebude uvedeno jinak).
Možné parametry jsou:
vlastnost reduction
Určuje, že daná proměnná bude lokální ve vlákně, tozn. že každé vlákno bude mít nezávislou instanci této proměnné. Po skončení bloku se na všechny instance použije redukční operace a výsledek bude zapsán do proměnné hlavního vlákna procesu (bude platný po skončení paralelního bloku).
Možné operace jsou: +, *, -, &, ^, |
Omezení:
více viz zde
Ukázka zde
podrobněji a další ukázka zde

OpenMP operace

Operace "barrier"
Specifikuje bariéru (část kódu,kde na sebe všechny vlákna "počkají" a dále jdou zase všechny)
více viz zde
Operace "flush"
Násilně vyvolá čtení a zápis daných proměných do/z paměti.
Možné parametry jsou:
vysvětlení zde
Operace "omp_set_num_threads(int i)"
Programově změní počet vytvořených vláken v následujích paralelních blocích. Musí být volán ze sekvenční části předcházející paralelnímu bloku. Efekt zůstává v platnosti do dalšího volání. Parametrem je požadovaný počet vláken.
Operace "omp_get_num_threads"
Vrátí počet vláken v aktuálním paralelním bloku. V sekvenční části vrací 1.
Operace "omp_get_wtime"
Vrátí číslo (typu double), které udává uběhnutý čas od nějakém (impementačně závislého) okamžiku v minulosti. Nejčastěji se používá jako párové volání pro zjištění např. doby trvání cyklu, doba trvání programu.
Operace "omp_init_lock(omp_lock_t *x)"
Inicializuje OpenMP zámek (mutex) s počáteční hodnotou odemčeno.
Operace "omp_destroy_lock(omp_lock_t *x)"
Zruší (inicializovaný) OpenMP zámek (mutex).
Operace "omp_set_lock(omp_lock_t *x)"
Pokusí se zamknout OpenMP zámek (mutex). V případě neúspěchu se vlákno zablokuje.
Operace "omp_test_lock(omp_lock_t *x)"
Pokusí se zamknout OpenMP zámek (mutex). V případě neúspěchu vrací 0.
Operace "omp_unset_lock(omp_lock_t *x)"
Odemkne OpenMP zámek (mutex).

Ukázkové OpenMP kódy

  1. Hello World (ukázka direktivy parallel)
  2. Vektorový součet (ukázka direktivy parallel a for)
  3. Vektorový součet (ukázka direktivy parallel for)
  4. Kritická sekce(ukázka direktivy critical)
  5. Atomická operace(ukázka direktivy atomic)
  6. Operace redukce(ukázka direktivy reduction)