• Nie Znaleziono Wyników

Przetwarzanie danych w GPU

W dokumencie Index of /rozprawy2/10612 (Stron 109-112)

A.2 Biblioteka CUDA

A.2.1 Przetwarzanie danych w GPU

Podstawy przetwarzania danych przez zunifikowane procesory graficzne zostan ˛a omówione na przykładzie pierwszej generacji procesorów graficznych kompatybilnych z architektur ˛a CUDA. Rysunek A.8 przedstawia schemat blokowy pierwszej generacji procesorów graficz-nych (architektura G80). Procesor graficzny tego typu zbudowany jest z du˙zej liczby skalargraficz-nych

rdzeni strumieniowych (ang. Stream Processor — SP), które oznaczono na rysunku kolorem

zielonym. Rdzenie SP s ˛a bardzo wydajnymi jednostkami skalarnymi, które umo˙zliwiaj ˛a prac˛e strumieniow ˛a — wyj´scie jednego rdzenia mo˙ze stanowi´c wej´scie kolejnego. Ka˙zdy rdze ´n SP umo˙zliwia jednoczesne wykonywanie operacji MAD (mno˙zenie i dodawania) i MUL (mno˙ze-nie) na liczbach całkowitych oraz zmiennoprzecinkowych zgodnych ze standardem IEEE 754.

Rdzenie SP s ˛a grupowane w tzw. multiprocesory (ang. Streaming Multiprocessor — SM), w skład których wchodz ˛a dodatkowo: niewielkich rozmiarów pami˛e´c współdzielona (ang.

sha-red memory), pami˛e´c podr˛eczna pierwszego poziomu (L1), specjalizowane jednostki

odpowie-dzialne za adresowanie (ang. Texture Address unit — TA) i filtrowanie tekstów (ang. Texture

Filtering unit — TF) oraz specjalizowane jednostki „super-funkcjonalne” (ang. Super Func-tion Units — SFU), umo˙zliwiaj ˛ace obliczanie cz˛esto wyst˛epuj ˛acych funkcji matematycznych, takich jak np. pierwiastek kwadratowy, odwrotno´s´c, sinus czy cosinus k ˛ata, w kilku taktach

zegara. W kolejnych wersjach architektury GPU do multiprocesorów dodano mi˛edzy innymi jednostki umo˙zliwiaj ˛ace obliczenia na liczbach zmiennoprzecinkowych o podwójnej precyzji (ang. double-precision).

Rysunek A.8: Schemat blokowy procesora graficznego pierwszej generacji (G80), główne ozna-czenia: SP – skalarne rdzenie strumieniowe, MP – multiprocesor, TF – bloki filtrowania tekstur, L1 i L2 – pami˛e´c podr˛eczna, FB – pami˛e´c obrazu (tzw. bufor ramki) (NVIDIA, 2011b)

Dane graficzne przetwarzane przez GPU maj ˛a zazwyczaj charakter wektorowy — s ˛a to np. trójwymiarowe współrz˛edne lub te˙z czterokomponentowy opis koloru (RGBA). Dzi˛eki mo˙zli-wo´sci ł ˛aczenia na poziomie kodu pojedynczych procesorów w grupy, mo˙zliwe jest „dora´zne tworzenie” jednostek wektorowych, które s ˛a w stanie bardzo wydajnie przetwarza´c dane za-równo skalarne, jak i wektorowe, praktycznie niezale˙znie od wymiaru.

Jak ju˙z wspomniano, procesor graficzny realizuje przetwarzanie równoległe na poziomie danych, co sprowadza si˛e do tego, ˙ze w jednym momencie du˙za liczba rdzeni wykonuje ten sam kod programu. Na rysunku A.9 zaprezentowano w jaki sposób uruchamiane s ˛a programy (kernels) z poziomu CPU (Host) na procesorze GPU kary graficznej (Device).

Akceleracja oblicze ´n z u˙zyciem GPU mo˙zliwa jest praktycznie w dowolnej aplikacji i polega na: przesłaniu danych do pami˛eci karty graficznej, a nast˛epnie wywołaniu specjalnej wersji programu (kernel), która zostaje uruchomiona na wielu rdzeniach GPU, realizuj ˛ac obliczenia w sposób równoległy. Wyniki działania kernel znajduj ˛a si˛e w pami˛eci karty graficznej. W celu ich dalszego u˙zycia w aplikacji nale˙zy je skopiowa´c do pami˛eci operacyjnej. Biblioteka CUDA udost˛epnia funkcje interfejsu programistycznego, które umo˙zliwiaj ˛a: alokowanie pami˛eci na karcie graficznej, przesył danych, jak równie˙z umo˙zliwiaj ˛a skompilowanie programu (kernel) z uwzgl˛ednieniem ogranicze ´n konkretnej architektury GPU, a nast˛epnie jego wywołanie.

Mi˛edzy w ˛atkami GPU oraz CPU istniej ˛a istotne ró˙znice. Przede wszystkim w ˛atki GPU s ˛a to relatywnie krótkie fragmenty kodu, które dodatkowo posiadaj ˛a bardzo małe koszty tworze-nia oraz przeł ˛aczania, przez co zarz ˛adzanie tysi ˛acami w ˛atków w procesorze odbywa si˛e bardzo wydajnie. Cech ˛a charakterystyczn ˛a jest równie˙z to, ˙ze cała architektura jest bardzo dobrze ska-lowalna na poziomie sprz˛etu — ten sam program (kernel) mo˙ze by´c uruchomiony na ró˙znych

Rysunek A.9: Schemat wykonywania programów (kernels) na wielu rdzeniach GPU (NVIDIA, 2011b)

procesorach GPU o ró˙znej liczbie rdzeni. Czas potrzebny do wykonania oblicze ´n jest tym krót-szy, im wi˛ecej rdzeni uczestniczy w obliczeniach.

W momencie wywołania programu (kernel) tworzona jest siatka (Grid), na któr ˛a składa si˛e zestaw bloków (Block), na który z kolei składaj ˛a si˛e w ˛atki (Thread) uruchamiane na konkret-nych rdzeniach SP. Rozmiary siatki (liczba bloków) oraz bloku (liczba w ˛atków) s ˛a okre´slane w momencie uruchamiania programu kernel jako dodatkowe parametry. Rozmiary te dobie-rane s ˛a do wielko´sci przetwarzanych danych. Do wszystkich w ˛atków trafia ten sam kod pro-gramu. Identyfikacja ró˙znych w ˛atków mo˙zliwa jest dzi˛eki zastosowaniu specjalnych zmien-nych, które dost˛epne s ˛a podczas wykonywania programu GPU i które maj ˛a warto´s´c „adresu” w ˛atku w bloku oraz bloku w siatce bloków. Wykaz zmiennych przedstawiono w tabeli A.2. Na pojedynczym rdzeniu procesora wykonywany jest wi˛ec jeden w ˛atek kernel, na multiproceso-rze wykonywany jest blok programów, za´s na dost˛epnych muliprocesorach uruchamiana jest siatka (Grid).

Ka˙zdy program kernel wykonywany jest wi˛ec przez tablic˛e rdzeni, które u˙zywaj ˛a własnych identyfikatorów do adresowania danych oraz do kontroli wykonywania programu. Wymiary tablicy rdzeni okre´slane s ˛a podczas wywoływania głównej funkcji kernela i dobierane s ˛a za-zwyczaj do wymiarów przetwarzanych danych w taki sposób, by jeden rdze ´n GPU przetwarzał jedn ˛a „porcj˛e” danych, np. mno˙zył dwie konkretne warto´sci dwóch wektorów. Zmienne wbu-dowane umo˙zliwiaj ˛a zaadresowanie danych — ka˙zdy w ˛atek mo˙ze obliczy´c swój własny indeks, który zostaje nast˛epnie u˙zyty jako wska´znik do danych. W przypadku danych

jednowymiaro-Tablica A.2: Wykaz zmiennych wbudowanych u˙zywanych do identyfikacji w ˛atku w CUDA

Zmienna Opis

gridDim wymiary siatki, liczba bloków w ˛atków w siatce

blockDim wymiar bloku, liczba w ˛atków w bloku

blockIdx indeks bloku w siatce (grid), jedno- lub dwuwymiarowy

threadIdx indeks w ˛atku w bloku, jedno- dwu- lub trójwymiarowy

Wszystkie zmienne s ˛a typu dim3, który jest wbudowanym typem danych u˙zywanym w CUDA — tróje-lementowym wektorem liczb całkowitych dodatnich. Do elementów wektora mo˙zna si˛e odwoła´c przez składowe: x, y oraz z.

wych, indeks w ˛atku obliczany jest na podstawie zmiennych wbudowanych z zale˙zno´sci (A.1): int T hr ead I d = thr ead I d x.x + bl ock I d x.x ∗ bl ockDi m.x . (A.1) Podsumowuj ˛ac, program kernel przetwarzaj ˛acy dane musi by´c napisany w taki sposób, by „umiał” zaadresowa´c dane przeznaczone tylko dla niego, przetworzy´c je, a nast˛epnie zwró-ci´c wyniki w taki sposób, by nie zostały one nadpisane przez setki innych, działaj ˛acych w tym samym czasie kopii tego samego programu. Poniewa˙z dane s ˛a „wspólnym dobrem” wielkiej liczby rdzeni procesora graficznego, zastosowano wielopoziomow ˛a architektur˛e pami˛eci — u˙zyto kilku rodzai pami˛eci o ró˙znych rozmiarach, wydajno´sci oraz prawach dost˛epu. Prze-strze ´n adresowa widziana z poziomu rdzenia jest ró˙zna dla ró˙znych typów zmiennych. Dzi˛eki temu zwi˛ekszono wydajno´s´c przetwarzania danych, np. poprzez ograniczenie niezsynchroni-zowanych dost˛epów do pami˛eci przez wiele rdzeni. Zastosowane w GPU bardzo szerokie szyny danych słu˙z ˛a do przesyłu jednocze´snie wielu bajtów danych. Dzi˛eki temu, mo˙zliwe jest efek-tywne kopiowanie danych z pami˛eci globalnej do pami˛eci on-chip GPU, do której bezpo´sredni dost˛ep maj ˛a rdzenie multiprocesorów.

W dokumencie Index of /rozprawy2/10612 (Stron 109-112)