OpenACC a OpenMP pro GPU

Využití výpočetního výkonu grafických karet (GPU, též accelerators nebo devices) bylo odedávna snem mnohých. Porovnání teoretických floating-point operations per second (FLOPS) obdobně drahých CPUs a GPUs (list of Intel CPUs, list of Nvidia GPUs) ukazuje na až dvouřádový rozdíl ve prospěch GPUs. (Pro získání FLOPS lze násobit u CPU počet cores, resp. threads, některou z frekvencí z tabulek v odkazech, u GPU je to už provedeno ve sloupcích Processing power.) Jako první nabídla své GPUs pro obecné počítání (GPGPU neboli GPU offloading) společnost Nvidia a zůstává dodnes v čele dalších výrobců (AMD, Intel). Z produktových řad Nvidia GPUs jsou cenově nejdostupnější GeForce, přinášející plnohodnotný výkon v single precision (SP) reálné aritmetice a bohužel řádově slabší výkon v double precision (DP) – ten řeší až ryze výpočetní GPUs z produktové řady Tesla. Vývoj Nvidia GPUs prošel řadou generací, popisovaných jednak slavnými jmény, jednak numericky pomocí compute capability (cc): mezi dnes podporované generace patří Kepler (cc 6.1), Turing (7.5), Ampere (8.6) a Ada Lovelace (8.9).

Klíčovou částí Nvidia GeForce GPUs jsou multiprocesory (streaming multiprocessors, SM), obsahující mj. výpočetní jádra (typicky 64 nebo 128 pro SP) a specifické druhy paměti (např. registry, cache, sdílenou paměť). GPU běžně obsahuje jednotky až desítky multiprocesorů (např. 36 v RTX 2070/Turing, 46 v RTX 3070/Ampere a 60 v RTX 4070 Ti/Ada Lovelace). Součástí GPU je i samostatná paměť (GDDR) o typické velikosti jednotek až desítek GB. Nvidia GeForce GPUs se vkládají do PCI Express rozhraní základních desek – tudy musí projít všechny vstupy a výstupy počtů prováděných na GPUs.

Softwarová platforma pro Nvidia GPU počítání se nazývá CUDA. Její klíčovou součástí je nízkoúrovňový C překladač nvcc funkcí (kernelů) do strojového kódu GPU. Ve volně dostupném balíku Nvidia HPC SDK jsou pak nabízeny překladače, knihovny a další nástroje pro pohodlnější programování Nvidia GPUs. Nvidia překladač Fortranu nvfortran (dříve pgfortran firmy Portland Group) rozumí modernímu Fortranu 2003 a 2008 a jeho součástí je např. CUDA Fortran pro překlad fortransky zapsaných kernelů. Nejsnazší cestou ke GPU počítání se ovšem jeví API systémy OpenACC a OpenMP. První z nich uchopil téma dříve a je poněkud přímočařejší, OpenMP jako dlouho existující vzor pro vláknovou paralelizaci na CPU rozšířil svou specifikaci pro GPU později. Překladač nvfortran podporuje OpenACC už řadu let, OpenMP pro CPU samozřejmě odedávna, a nově se hlásí i k OpenMP pro GPU (s compute capability 7+). Nvidia překladače stojí na bázi LLVM, přičemž fortranský front-end je úzce spojen s projektem Flang. Sdílí s ním bohužel aktuální nedostupnost pro Windows – GPU počítání si tedy užijeme především na Linuxu. (Na desktopu s Windows lze vytěžit WSL, viz mj. náš návod.)

K podpoře OpenACC a OpenMP direktiv pro Nvidia a AMD GPUs se hlásí i gfortran (viz offloading support in GCC). Daří se takto překlad a běh OpenACC programů v Linuxu, jejich výkon bývá mírně pozadu za výkonem programů přeložených Nvidia překladačem. OpenMP direktivy pro své GPU implementoval Intel ve fortranském překladači ifx, součásti Intel HPC Toolkitu.

Syntaxi OpenACC lze čerpat z podkladů na stránce OpenACC Specifications a podobně pro OpenMP: OpenMP Specifications.

Paralelizace indexovaného cyklu

Typickým úkolem při přenosu výpočtů na GPU je určit, která data mají být přenesena mezi CPU a GPU (snahou je datové přenosy minimalizovat) a obložit direktivami paralelizovatelné cykly. V OpenACC lze použít direktivy !$ACC DATA a !$ACC PARALLEL LOOP, v OpenMP direktivy !$OMP TARGET MAP a !$OMP TEAMS DISTRIBUTE PARALLEL DO.

Zdrojový kód updatující v cyklu prvky pole (první ukázku ze stránky OpenMP pro CPU) můžeme paralelizovat v alternativách OpenACC a OpenMP takto:

integer,parameter :: nmax=10
real a(nmax)
!$ACC DATA COPY (a)
!$ACC PARALLEL LOOP
!$OMP TARGET MAP (TOFROM:a)
!$OMP TEAMS DISTRIBUTE PARALLEL DO
! do n=1,nmax; a(n)=n; print *,a(n); enddo  ! nvfortran only
  do n=1,nmax; a(n)=n; enddo                ! nvfortran & gfortran
!$ACC END PARALLEL LOOP
!$ACC END DATA
!$OMP END TEAMS DISTRIBUTE PARALLEL DO
!$OMP END TARGET
print '(x,f0.0$)',a; print *
end program

Překladače překládají zdrojový kód implicitně pro sekvenční běh na CPU:

nvfortran 01.f90
gfortran 01.f90

Výpis: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

Překlad OpenACC direktiv pro GPU se aktivuje explicitní volbou, jejímž vhodným doplňkem je volba pro výstup informací o překladu. nvfortran navíc dává možnost interpretovat OpenACC direktivy pro vícevláknový běh na CPU (-acc=multicore) nebo upřesnit, pro kterou compute capability překládat (např. -gpu=ccall).

nvfortran -acc -Minfo=acc 01.f90                    (OpenACC GPU)
nvfortran -acc=multicore -Minfo=accel 01.f90        (OpenACC CPU)
gfortran -fopenacc -fopt-info-optimized-omp 01.f90  (OpenACC GPU)

S OpenMP direktivami je to podobné, jen nvfortran vyžaduje uvést cíl explicitně (-mp=gpu).

nvfortran -mp=gpu -Minfo=mp 01.f90                  (OpenMP GPU)
nvfortran -mp -Minfo=mp 01.f90                      (OpenMP CPU)
gfortran -fopenmp -fopt-info-optimized-omp 01.f90   (OpenMP GPU)

Programy jsou typicky překládány tak, aby běžely na GPU, je-li to možné, a v opačném případě na CPU. Je proto vhodné sledovat, zda požadované části kódu skutečně běží na GPU. U Nvidia překladačů se informační výpisy aktivují pomocí proměnných prostředí NVCOMPILER_ACC_NOTIFY (s přiřazeným součtem z hodnot 1, 2, 4, 8 a 16, viz Nvidia HPC Compilers User’s Guide) a NVCOMPILER_ACC_TIME (pro informaci o době běhu kernelů v mikrosekundách). Počet vláken při vícevláknovém běhu na CPU řídí proměnná ACC_NUM_CORES. GNU překladač používá proměnnou GOMP_DEBUG.

nvfortran -acc 01.f90; NVCOMPILER_ACC_NOTIFY=1 NVCOMPILER_ACC_TIME=1 ./a.out  (GPU)
nvfortran -acc=multicore 01.f90; ACC_NUM_CORES=16 ./a.out                     (CPU)
gfortran -fopenacc 01.f90; GOMP_DEBUG=1 ./a.out                               (GPU)

Jak je ze zdrojového kódu patrné, nvfortran dokáže zprostředkovat výpis zevnitř kernelu, i když jen bez formátových specifikací (print *). Tak je pak s OpenACC možno sledovat pomíchané pořadí výpisů.

Verze: 10. 4. 2024