Programowanie Współbieżne Agnieszka Łupińska 5 października 2016
Hello World! helloworld.cu: #include <cstdio> global void helloworld(){ int thid = (blockidx.x * blockdim.x) + threadidx.x; printf("hello World! thread #%d\n", thid); } int main(){ int NUM_BLOCKS = 4; int NUM_THREADS = 5; helloworld<<<num_blocks, NUM_THREADS>>>(); cudadevicesynchronize(); return 0; } aga@ubuntu$ nvcc -arch=sm 20 helloworld.cu
Hello World! - Output Hello World! thread #5 Hello World! thread #6 Hello World! thread #7 Hello World! thread #8 Hello World! thread #9 Hello World! thread #0 Hello World! thread #1 Hello World! thread #2 Hello World! thread #3 Hello World! thread #4 Hello World! thread #15 Hello World! thread #16 Hello World! thread #17 Hello World! thread #18 Hello World! thread #19 Hello World! thread #10 Hello World! thread #11 Hello World! thread #12 Hello World! thread #13 Hello World! thread #14
Model programowania CUDA Host - działa na CPU - wątek główny programu - obsługuje Device Device - działa na GPU - jest koprocesorem Hosta - fizycznie oddzielony od Hosta - obsługuje CUDA wątki - wykonuje funkcje zwane kernelami Host i Device mają odzielną, niezależną pamięć.
Deklaracja CUDA funkcji device int DeviceFunc() - wykonywana na Device, wywoływana z Device (przez CUDA wątki) global void KernelFunc() - wykonywana na Device, wywoływana z Hosta, zawsze jest void host int HostFunc() - wykonywana na Hoscie, wywoływana z Hosta, można pominąć host, chyba, że jest używana razem z device
Zmienne wbudowane griddim.x griddim.y griddim.z blockdim.x blockdim.y blockdim.z blockidx.x blockidx.y blockidx.z threadidx.x threadidx.y threadidx.z int thid = (blockidx.x * blockdim.x) + threadidx.x;
Zarządzanie pamięcią Host - tak jak w C/C++ Device: local memory - każdy wątek ma swoją własną prywatną pamięć, niewidoczną dla pozostałych wątków shared memory - pamięć współdzielona przez wszystkie wątki w bloku, nietrwała - czas życia taki jak bloku global memory - pamięć globalna, współdzielona przez wszystkie wątki działające w programie, trwała. cache - pamięć podręczna, dwa poziomy: L1 - jeden dla każdego multiprocesora, L2 - współdzielony między wszystkie multiprocesory. Keszują dostęp do pamięci lokalnej i globalnej. Cache i shared memory używają pamięci on-chip, więc dostęp tam jest bardzo szybki. Local memory jest pamięcią off-chip i dostęp kosztuje tyle samo co dostęp do pamięci globalnej.
Synchronizacja Wątki wewnątrz bloku można synchronizować za pomocą funkcji: syncthreads() Nie powinno się synchronizować wątków w obrębie gridu, ale można to zrobić za pomocą zmiennych globalnych. Poza tym kod, który wymaga synchronizacji wszystkich wątków w gridzie można podzielić w miejscu synchronizacji na dwa osobne kernele i wykonać najpierw jeden, potem drugi.
Compute Capability Compute Capability karty graficznej jest zadany przez dwie liczby: znaczący i mniej znaczący numer wersji. Urządzenia o tym samym znaczącym numerze mają tą samą architekturę rdzeni. Na przykład, cc dla kart z architekturą Fermi to 2.x (znaczący wynosi 2). Karty z architekturą Maxwell mają cc 5.x. cc sprzętu na Satori: 2.x. cc sprzętu na Miracle: 5.x. Jak sprawdzić architekturę sprzętu? Najlepiej skorzystać z SDK Nvidii i uruchomić devicequery:./nvidia GPU Computing SDK/C/bin/linux/release/deviceQuery Przykłady z SDK /usr/local/cuda/samples/
devicequery Device 0: GeForce GTX 560 Ti CUDA Driver Version / Runtime Version 5.0 / 4.2 CUDA Capability Major/Minor version number 2.1 Total amount of global memory: 1023 MBytes (1072889856 ( 8) Multiprocessors x ( 48) CUDA Cores/MP: 384 CUDA Cores GPU Clock rate: 1800 MHz (1.80 GHz) Memory Clock rate: 2004 Mhz Memory Bus Width: 256-bit L2 Cache Size: 524288 bytes Max Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536,6 Max Layered Texture Size (dim) x layers 1D=(16384) x 2048, 2D=( Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 32768 Warp size: 32 Maximum number of threads per multiprocessor: 1536 Maximum number of threads per block: 1024 Maximum sizes of each dimension of a block: 1024 x 1024 x 64 Maximum sizes of each dimension of a grid: 65535 x 65535 x 65535
Maximum memory pitch: Texture alignment: Concurrent copy and execution: Run time limit on kernels: Integrated GPU sharing Host Memory: Support host page-locked memory mapping: Concurrent kernel execution: Alignment requirement for Surfaces: 2147483647 bytes 512 bytes Yes with 1 copy engine(s) Yes No Yes Yes Yes
Specyfikacja według Compute Capability
Specyfikacja według Compute Capability
Interfejsy programowania w CUDA CUDA Driver API - niskopoziomowe CUDA Runtime - zaimplementowane powyżej CUDA Driver API