Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Podobne dokumenty
Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Programowanie kart graficznych

Programowanie Współbieżne

Programowanie kart graficznych

Programowanie kart graficznych. Architektura i API część 1

JCuda Czy Java i CUDA mogą się polubić? Konrad Szałkowski

CUDA obliczenia ogólnego przeznaczenia na mocno zrównoleglonym sprzęcie. W prezentacji wykorzystano materiały firmy NVIDIA (

Programowanie procesorów graficznych NVIDIA (rdzenie CUDA) Wykład nr 1

Programowanie CUDA informacje praktycznie i. Wersja

Programowanie procesorów graficznych GPGPU. Krzysztof Banaś Obliczenia równoległe 1

Porównanie wydajności CUDA i OpenCL na przykładzie równoległego algorytmu wyznaczania wartości funkcji celu dla problemu gniazdowego

Programowanie kart graficznych. Architektura i API część 2

Obliczenia na GPU w technologii CUDA

Programowanie aplikacji równoległych i rozproszonych

Programowanie CUDA informacje praktycznie i przykłady. Wersja

Tesla. Architektura Fermi

CUDA PROGRAMOWANIE PIERWSZE PROSTE PRZYKŁADY RÓWNOLEGŁE. Michał Bieńkowski Katarzyna Lewenda

Programowanie procesorów graficznych GPGPU

Programowanie Równoległe Wykład, CUDA praktycznie 1. Maciej Matyka Instytut Fizyki Teoretycznej

Procesory kart graficznych i CUDA wer

Programowanie Równoległe wykład, CUDA, przykłady praktyczne 1. Maciej Matyka Instytut Fizyki Teoretycznej

Programowanie procesorów graficznych w CUDA.

Przetwarzanie Równoległe i Rozproszone

Programowanie PKG - informacje praktycznie i przykłady. Wersja z Opracował: Rafał Walkowiak

CUDA. obliczenia na kartach graficznych. Łukasz Ligowski. 11 luty Łukasz Ligowski () CUDA 11 luty / 36

GTX260 i CUDA wer

Procesory kart graficznych i CUDA

Procesory kart graficznych i CUDA wer PR

CUDA. cudniejsze przyk ady

CUDA Median Filter filtr medianowy wykorzystujący bibliotekę CUDA sprawozdanie z projektu

Programowanie Równoległe wykład 12. OpenGL + algorytm n ciał. Maciej Matyka Instytut Fizyki Teoretycznej

Procesory kart graficznych i CUDA wer

CUDA ćwiczenia praktyczne

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Przygotowanie kilku wersji kodu zgodnie z wymogami wersji zadania,

Programowanie kart graficznych. Sprzęt i obliczenia

Zadania na zaliczenie przedmiotu Przetwarzanie równoległe Zebrał dla roku.ak. 2015/2016 Rafał Walkowiak,

Podstawy programowania komputerów

ZASADY PROGRAMOWANIA KOMPUTERÓW

Programowanie obiektowe W3

Struktura programu. Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem.

i3: internet - infrastruktury - innowacje

Lab 9 Podstawy Programowania

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Procesy i wątki. Krzysztof Banaś Obliczenia równoległe 1

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Programowanie procesorów graficznych GPGPU

Podstawy Programowania C++

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Programowanie równoległe Wprowadzenie do OpenCL. Rafał Skinderowicz

Wykład 3 Składnia języka C# (cz. 2)

Moc płynąca z kart graficznych

DYNAMICZNE PRZYDZIELANIE PAMIECI

ZARZĄDZANIE PAMIĘCIĄ W TECHNOLOGII CUDA

CUDA część 1. platforma GPGPU w obliczeniach naukowych. Maciej Matyka

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

typ y y p y z łoż o on o e n - tab a lice c e w iel e owym m ar a o r we, e stru r kt k ury

Organizacja pamięci w procesorach graficznych

KURS C/C++ WYKŁAD 6. Wskaźniki

Programowanie z wykorzystaniem technologii CUDA i OpenCL Wykład 1

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Tablice. Monika Wrzosek (IM UG) Podstawy Programowania 96 / 119

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Programowanie kart graficznych. Kompilator NVCC Podstawy programowania na poziomie API sterownika

Architektury komputerów Architektury i wydajność. Tomasz Dziubich

Tworzenie programów równoległych cd. Krzysztof Banaś Obliczenia równoległe 1

Dodatek A. CUDA. 1 Stosowany jest w tym kontekście skrót GPCPU (od ang. general-purpose computing on graphics processing units).

16. Taksonomia Flynn'a.

Stałe, tablice dynamiczne i wielowymiarowe

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Programowanie procesorów graficznych GPGPU. Krzysztof Banaś Obliczenia równoległe 1

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Hybrydowy system obliczeniowy z akceleratorami GPU

4 NVIDIA CUDA jako znakomita platforma do zrównoleglenia obliczeń

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Wskaźniki. Informatyka

Zaawansowane programowanie w języku C++ Zarządzanie pamięcią w C++

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Implementacja modelu FHP w technologii NVIDIA CUDA

Programowanie równoległe Wprowadzenie do programowania GPU. Rafał Skinderowicz

Język C zajęcia nr 11. Funkcje

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Tablice, funkcje - wprowadzenie

Akceleracja obliczeń algebry liniowej z wykorzystaniem masywnie równoległych, wielordzeniowych procesorów GPU Świerczewski Ł.

Rozdział 4 KLASY, OBIEKTY, METODY

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Programowanie w modelu równoległości danych oraz dzielonej globalnej pamięci wspólnej. Krzysztof Banaś Obliczenia równoległe 1

Wstęp do wskaźników w języku ANSI C

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 6. Karol Tarnowski A-1 p.

Podstawy algorytmiki i programowania - wykład 4 C-struktury

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Nowoczesne technologie przetwarzania informacji

Wykład 8: klasy cz. 4

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

Wstęp do obliczeń równoległych na GPU

Podstawy algorytmiki i programowania - wykład 2 Tablice dwuwymiarowe cd Funkcje rekurencyjne

Libra.cs.put.poznan.pl/mailman/listinfo/skisrkolo.

Programowanie w języku C++

Transkrypt:

Wprowadzenie do programowania w środowisku CUDA Środowisko CUDA 1

Budowa procesora CPU i GPU Architektura GPU wymaga większej ilości tranzystorów na przetwarzanie danych Control ALU ALU ALU ALU Cache DRAM DRAM CPU GPU Środowisko CUDA 2

Architektura SIMT SIMT single-instruction, multiple-thread Mamy wiele procesorów na których działa ten sam program. Dokładnie posiada strumieniowe multiprocesory (SM Streaming Multiprocessor), które zawierają 32 małe, szybkie procesory. Na jednym multiprocesorze wątki (grupę taką nazywamy warpem) muszą wykonywać tą samą instrukcję tego samego programu (instrukcję spod tego samego adresu). Wątki łączymy w bloki, które następnie łączymy w grid. Bloki/gridy stanowią jedno-, dwu- lub trzywymiarową kostkę. Środowisko CUDA 3

Warp itp. Wątki w ramach jednego bloku wykonywane są w podziale na warp-y. Jeden warp to 32 wątki. Półwarp (half-warp) to 16 wątków (pierwsze 16 spośród 32 lub drugie 16 spośród 32). Jeśli w bloku jest mniej niż 32 wątki, nie jest wykorzystywana pełna moc obliczeniowa procesora! W ramach warp-a wszystkie wątki muszą wykonywać tę samą instrukcję, jednak w tym samym czasie inny warp z tego samego bloku może być wykonywany na innym procesorze i te drugie 32 wątki mogą wykonywać wspólnie inną instrukcję. System zarządzający wykonywaniem warp-ów sam decyduje, który w danej chwili uruchomić. Jeśli chcemy zsynchronizować wszystkie wątki w ramach jednego bloku należy użyć metody syncthreads(). Nie ma możliwości synchronizacji wątków w ramach całego grid-u. Zamiast tego można wywoływać z kodu hosta kolejne metody kernela. Występuje problem ze zmiennymi lokalnymi oraz pamięcią współdzieloną. Środowisko CUDA 4

Podział na bloki i wątki Grid Block (0,0) Block (1,0) Block (2,0) Block (0,1) Block (1,1) Block (1,2) Block (1,1) Thread(0,0) Thread(1,0) Thread(2,0) Thread(3,0) Thread(0,1) Thread(1,1) Thread(2,1) Thread(3,1) Thread(0,2) Thread(1,2) Thread(2,2) Thread(3,2) Środowisko CUDA 5

Rodzaje pamięci Każdy z wątków ma dostęp do różnego rodzaju pamięci: Pamięć rejestrów pamięć najbliżej procesora, najszybsza, bardzo mała liczba rejestrów Pamięć lokalna szybka pamięć dostępna dla konkretnego wątku Pamięć współdzielona szybsza pamięć dostępna dla wszystkich wątków w bloku, niezbyt duża, chociaż większa niż lokalna Pamięć stała podobna do pamięci globalnej, jednak szybsza, gdyż nie można jej zapisywać (read-only) Pamięć tekstur podobna do pamięci stałej Pamięć globalna wolna pamięć dostępna dla wszystkich wątków w gridzie Środowisko CUDA 6

Hierarchia pamięci rejestry Wątek pamięć lokalna Blok pamięć współdzielna Grid pamięć globalna Pamięć stała i tekstur Środowisko CUDA 7

Architektura CUDA Środowisko CUDA 8

Architektura CUDA 1. Silnik przetwarzania równoległego wewnątrz NVIDIA GPU. 2. Wsparcie na poziomie kernela OS dla inicjalizacji sprzętu, konfiguracji itp. 3. Sterownik na poziomie użytkownika, który dostarcza API dla programisty na poziomie urządzenia. 4. PTX instruction set architecture (ISA) dla kerneli i funkcji przetwarzania równoległego Środowisko CUDA 9

Przydział bloków do multiprocesorów Środowisko CUDA 10

Wykonywanie kodu na GPU Komputer (lub inne urządzenie) na którym jest zainstalowana karta z CUDA nazywany jest Hostem. Karta graficzna nazwana jest device. Program działający na hoście wywołuje funkcję napisaną dla device. Funkcja taka nazywana jest kernelem (parallel kernel). Po powrocie z wywołania funkcji program na hoście kontynuuje wykonanie własnego kodu. Może również wywołać następny kernel. Środowisko CUDA 11

Wykonywanie programu // kod sekwencyjny Host Kernel0<<<>>>() Device Block Block Grid // kod sekwencyjny Host Kernel1<<<>>>() // kod sekwencyjny Device Grid Host Block Block Block Block Block Block Środowisko CUDA 12

Synchronizacja kodu dla host i device Dopóki nie nastąpi synchronizacja, program na hoście i program na device mogą działać niezależnie. Program na hoście czeka na zakończenie programu na device, gdy: Stara się wykonać kolejną funkcję na tym device Następuje kopiowanie danych pomiędzy pamięcią globalną a pamięcią na hoście. Środowisko CUDA 13

Grid, blok, wątek Wątki grupuje się dwupoziomowo. Funkcję na device uruchamia się dla gridu, który jako składowe posiada bloki. Każdy blok natomiast dzieli się na wątki. Dla wygody indeks wątku w ramach bloku opisany jest jako 3- elementowy wektor. Pozwala to w praktyce używać jedno-, dwu- i trzywymiarowego indeksowania wątku. Na obecnych GPU maksymalna liczba wątków na blok wynosi 512. Jest to uwarunkowane szybkością pamięci współdzielonej. Grid może być opisany jako jedno- lub dwuwymiarowa siatka bloków. Bloki muszą działać poprawnie, niezależnie czy będą wykonywane równolegle, sekwencyjnie (w dowolnej kolejności). Nie ma możliwości wpływania bezpośredniego na kolejność wykonywania bloków ani na ich synchronizację. Dokładne graniczne rozmiary gridu lub bloku mogą zależeć od karty GPU i zmieniać się w przyszłości. Środowisko CUDA 14

Ograniczenia na funkcję kernela Kernel funkcja działająca na device Nie może korzystać z rekurencji W ciele funkcji nie można deklarować zmiennych statycznych Nie może zwracać wartości Ilość parametrów musi być określona Łączny rozmiar parametrów nie może przekraczać 256 bajtów (w Compute Compability 1.x) lub 4KB (w Compute Compability 2.0) Środowisko CUDA 15

Program pisany jak w C/C++ Kompilator NVCC Istnieją dodatkowe specyfikatory oraz znaczniki dla funkcji kernela, rodzaju pamięci oraz wywoływania tych funkcji. Przykładowy Makefile: CODENAME=dodMacierz CC=nvcc FLAGS=-L $(CUDA_LIB_PATH) -L $(CUDA_SDK_PATH)/C/lib/ -I $(CUDA_SDK_PATH)/C/common/inc FLAGS+=$(CUDA_NVCC_MACHINE_FLAG) FLAGS+=-arch=sm_13 FLAGS+=-lcutil $(CODENAME): $(CODENAME).cu $(CC) $(FLAGS) $< -o $@ Środowisko CUDA 16

Numer wątku Ponieważ wątki są uruchamiane w ramach bloku, a blok w ramach gridu, każdemu wątkowi przydzielany jest trzyelementowy wektor określający miejsce wątku w ramach bloku (w zmiennej lokalnej threadidx o polach x,y,z), trzyelementowy wektor określający rozmiar bloku (w zmiennej lokalnej blockdim o polach x,y,z) oraz trzyelementowy wektor określający miejsce bloku w ramach gridu (w zmiennej lokalnej blockidx o polach x,y,z). Jeśli liczba rozmiarów bloku/gridu jest mniejsza niż 3, odpowiednie pola (y lub y,z)mają wartość 1 Środowisko CUDA 17

Kernel funkcje i ich wywołanie // Definicja kernela global void VecAdd(float* A, float* B, float* C) { int i = threadidx.x; C[i] = A[i] + B[i]; } int main() {... // wywołanie kernela VecAdd<<<1, N>>>(A, B, C); } global jest specyfikatorem funkcji urządzenia wywoływanej z hosta, natomiast potrójne znaki mniejszości i większości służą do zdefiniowania gridu oraz bloku w ramach tego gridu. W tym przypadku grid jest jednowymiarowy (pierwszy parametr jest liczbą) i w dodatku zawiera tylko jeden blok. Blok ten też jest jednowymiarową strukturą i zawiera N wątków. Powoduje to, że w funkcji kernela wystarczy używać tylko pola x ze zmiennej threadidx. Środowisko CUDA 18

// Kernel definition Blok dwuwymiarowy global void MatAdd(float A[N][N], float B[N][N], float C[N][N]) { int i = threadidx.x; int j = threadidx.y; C[i][j] = A[i][j] + B[i][j]; } int main() {... // Kernel invocation dim3 dimblock(n, N); MatAdd<<<1, dimblock>>>(a, B, C); } W tym przypadku blok ten też jest dwuwymiarową strukturą i zawiera N*N wątków. Powoduje to, że w funkcji kernela wystarczy użyć tylko pól x i y ze zmiennej threadidx. Jak widać w konstruktorze struktury dim3 można podać dwa wymiary (zamiast 3), ostatni wymiar wynosi wówczas 1. W tym przykładzie parametry funkcji kernela są tablicami również o wymiarach N*N, ale nie jest to konieczne, ani wymagane. Środowisko CUDA 19

Grid dwuwymiarowy // Kernel definition global void MatAdd(float A[N][N], float B[N][N],float C[N][N]) { int i = blockidx.x * blockdim.x + threadidx.x; int j = blockidx.y * blockdim.y + threadidx.y; if (i < N && j < N) C[i][j] = A[i][j] + B[i][j]; } int main() {... // Kernel invocation dim3 dimblock(16, 16); dim3 dimgrid((n + dimblock.x 1) / dimblock.x,(n + dimblock.y 1) / dimblock.y); MatAdd<<<dimGrid, dimblock>>>(a, B, C); } W tym przykładzie blok i grid są dwuwymiarowymi strukturami. Każdy blok jest siatką 16*16 wątków. Natomiast wymiary grida są tak dobrane, aby można było przetworzyć macierz N*N elementów. Jeśli N % 16 nie jest 0, to w blokach skrajnych nie wszystkie wątki powinny pracować i stąd warunek w funkcji kernela. Dla wyznaczenia który wątek odpowiada za obliczenia poszczególnych elementów macierzy należy odpowiednio użyć zmiennych lokalnych blockidx, blockdim, threadidx. Analogicznie będzie jeśli blok będzie strukturą 3-wymiarową, ale trzeba wtedy użyć dodatkowo pól z odpowiednich zmiennych. Środowisko CUDA 20

Deklaracje pamięci W celu korzystania (zarezerwowania/zwolnienia oraz kopiowania z/do) z pamięci globalnej z poziomu hosta należy korzystać z odpowiednich funkcji: cudamalloc(void** ptr, size) rezerwacja pamięci pod wskaźnikiem zwracanym przez ptr o rozmiarze size bajtów cudamemcpy(void *ptrto, void *ptrfrom, size, int tryb) kopiowanie między pamięcią hosta a pamięcią device. Kierunek kopiowania definiuje tryb: cudamemcpyhosttodevice cudamemcpydevicetohost cudafree(void *ptr) zwalnia pamięć zarezerwowaną poprzez cudamalloc. cudamallocpitch(), cudamalloc3d(), cudamemcpy2d(), cudamemcpy3d() analogiczne do powyższych metod, ale z wykorzystaniem wyrównania celem osiągnięcia większej efektywności dostępu do pamięci. Środowisko CUDA 21

Pamięć c.d. Istnieją jeszcze inne metody rezerwowania pamięci z wyrównaniem. Wskaźniki do pamięci w parametrach funkcji kernela muszą być wskaźnikami do pamięci globalnej device. Przykład: // Device code global void VecAdd(float* A, float* B, float* C) { int i = blockdim.x * blockidx.x + threadidx.x; if (i < N) C[i] = A[i] + B[i]; } Środowisko CUDA 22

Kod c.d. int main() // Host code { int N =...; size_t size = N * sizeof(float); // Allocate input vectors h_a and h_b in host memory float* h_a = malloc(size); float* h_b = malloc(size); // Allocate vectors in device memory float *d_a, *d_b, *d_c; cudamalloc((void**)&d_a, size); cudamalloc((void**)&d_b, size); cudamalloc((void**)&d_c, size); // Copy vectors from host memory to device memory cudamemcpy(d_a, h_a, size, cudamemcpyhosttodevice); cudamemcpy(d_b, h_b, size, cudamemcpyhosttodevice); // Invoke kernel int threadsperblock = 256; int blockspergrid = (N + threadsperblock 1)/threadsPerBlock; VecAdd<<<blocksPerGrid, threadsperblock>>>(d_a, d_b, d_c); // Copy result from device memory to host memory // h_c contains the result in host memory cudamemcpy(h_c, d_c, size, cudamemcpydevicetohost); cudafree(d_a); // Free device memory cudafree(d_b); cudafree(d_c); } Środowisko CUDA 23

Pamięć współdzielona Pamięć współdzieloną wskazuje się przez kwalifikator shared Zadeklarowanie zmiennej tego typu w procedurze urządzenia tworzy pamięć, do której dostęp mają wszystkie wątki w jednym bloku. Po deklaracji każdy wątek wypełnia pewną część tej pamięci (każdy inną). Najczęściej jest to kopiowanie komórek z pamięci globalnej. Następnie wątki wykonują operacje matematyczne na tej pamięci (zamiast pamięci globalnej), a po zakończeniu obliczeń przepisują wyniki z pamięci współdzielonej do pamięci globalnej (znów każdy wątek inną część pamięci współdzielonej) Pamięć współdzielona nie może być inicjowana w momencie deklaracji. Gdy używana jest pamięć współdzielona należy synchronizować działanie wątków. Gdyby tego zrobiono, pewna część pamięci współdzielonej może nie być jeszcze zainicjowana lub obliczona. Jest to spowodowane wykonywaniem się bloku w podziale na warpy. Środowisko CUDA 24

Klasyfikator device Procedury (wewnętrzne) w ramach urządzenia posiadają klasyfikator device. Pamięć globalna w ramach urządzenia (inna niż z parametrów) posiada również klasyfikator device. Środowisko CUDA 25