Implementacje algorytmów oddziałujących cząstek na

Transkrypt

Implementacje algorytmów oddziałujących cząstek na
Akademia Górniczo-Hutnicza im. Stanisława Staszica w Krakowie
Wydział Elektrotechniki, Automatyki, Informatyki i Elektroniki
Katedra Informatyki
Autoreferat rozprawy doktorskiej
Implementacje algorytmów oddziałujących cząstek na architekturach
masywnie równoległych
mgr inż. Tomasz Rożen
Promotor:
dr hab. Krzysztof Boryczko prof. AGH, Akademia Górniczo-Hutnicza w Krakowie, EAIiE
Recenzenci:
dr hab. inż. Marek Tudruj prof. PAN, Polska Akademia Nauk w Warszawie, IPI
prof. dr hab. inż. Jacek Kitowski, Akademia Górniczo-Hutnicza w Krakowie, EAIiE
Cel i zakres pracy
Metody oddziałujących cząstek należą do popularnych metod symulacyjnych, umożliwiających
przeprowadzanie zaawansowanych eksperymentów komputerowych, między innymi z takich dziedzin
nauki jak fizyka, chemia, astrofizyka. Do przeprowadzenia sensownej symulacji popularnymi
metodami cząstek, takimi jak dyssypatywna dynamika cząstek (DPD) czy hydrodynamika cząstek
wygładzonych (SPH), nierzadko stosuje się układy zbudowane z milionów cząstek lub większe.
Pociąga to za sobą duże nakłady obliczeniowe, a szukanie efektywnych algorytmów symulacji jest
ciągle przedmiotem badań. W pracy doktorskiej rozpatrywane były jedynie metody cząstek o
oddziaływaniach krótkozasięgowych, do których należą m.in. wymienione metody.
W ciągu ostatnich lat obserwujemy zmianę podejścia do projektowania procesorów spowodowaną
ograniczeniami fizycznymi technologii CMOS. Problemy ze zwiększaniem częstotliwości taktowania
spowodowały, że zaczęły się pojawiać układy z bardzo duża liczbą rdzeni obliczeniowych.
Jako cel pracy doktorskiej postanowiono opracowanie metod umożliwiających efektywną realizację
algorytmów oddziałujących cząstek, dedykowanych dla wybranych, nietypowych architektur
komputerowych.
Pierwszą grupą architektur były procesory graficzne (GPU), które w ciągu ostatnich lat rozwinęły się
od prostych układów wykonujących jedynie predefiniowany zestaw operacji arytmetycznych do
układów charakteryzujących się wielopotokowością oraz wysoką programowalnością. Kolejną
chronologicznie architekturą był procesor Cell opracowany na potrzeby konsoli do gier Playstation 3, a
występujący obecnie również w superkomputerach z listy TOP500. Układ składa się z jednego rdzenia
ogólnego przeznaczenia oraz ośmiu pomocniczych, przeznaczonych do przetwarzania dużej ilości
danych. Ostatnią omawianą architekturą jest CUDA, rozwinięcie i uogólnienie koncepcji obliczeń na
GPU do zastosowań, które nie są związane z grafiką komputerową. Do tej kategorii należy procesor
Tesla oraz ostatnie generacje kart graficznych.
W pracy wysunięto tezę, że opracowanie dedykowanych algorytmów dla architektur masywnie
równoległych pozwoli osiągnąć większą wydajność, niż na architekturach tradycyjnych. Dla wykazania
prawdziwości tezy postanowiono zrealizować następujące cele:
1. Dokonano analizy modelu oddziaływań wykorzystywanych wykorzystywanych w symulacjach
metodami cząstek pod kątem ich efektywnej realizacji.
2. Opracowano i zaimplementowano algorytmy symulacji dla wybranych architektur.
3. Przeprowadzono badanie algorytmów pod kątem złożoności obliczeniowej oraz wydajności
opracowanych metod.
4. Następnie dokonano symulacji wybranych zjawisk fizycznych za pomocą opisanych metod.
Procesory graficzne
Symulacja metodami cząstek, takimi jak DPD czy SPH, realizowana jest przez wielokrotne
powtórzenie kroku symulacyjnego, który polega na wyliczeniu sił oddziaływań między cząstkami, a
następnie wyliczenia z równań ruchu nowych położeń cząstek. Dobór metod całkowania nie należał do
przedmiotu rozprawy, dlatego zastosowane zostały popularne i sprawdzone rozwiązania.
Ze względu na strumieniowy model przetwarzania główną trudność w implementacji metod cząstek na
procesorach graficznych stanowiło wyznaczenie cząstek sąsiednich każdej cząstki, konieczne dla
wyliczenia oddziaływań. Autor zastosował podział przestrzeni symulacji (prostopadłościennego pudła
obliczeniowego) na sześcienne komórki. Dla danej cząstki należało w takim układzie przejrzeć
wszystkie cząstki z 27 komórek otaczających daną cząstkę sprawdzając jednocześnie, czy znajdują się
one w tzw. promieniu obcięcia. Stąd długość promienia obcięcia nie może być większa od długości
krawędzi celi.
W celu przyporządkowania cząstek do komórek postanowiono zastosować zmodyfikowany algorytm
sortowania kubełkowego (rys.1.). Celem działania algorytmu było wyznaczenie list odsyłaczowych
elementów dla każdej komórki. Uzyskiwane było to przez naprzemienne zapisywanie identyfikatorów
elementów do "głowy" listy, a następnie wyznaczanie elementu następnego. Ze względu na konflikty w
zapisie, powodowane przypisaniem wielu elementów do tej samej komórki, kroki te musiały być
powtarzane wielokrotnie aż do umieszczenia wszystkich elementów w listach. Element raz
umieszczony w częściowej liście odsyłaczowej nie był brany pod uwagę w dalszej części
przetwarzania.
a)
b)
c)
Rys.1. Przykład działania równoległej wersji algorytmu sortowania kubełkowego: a) dane wejściowe,
b) poszczególne kroki przetwarzania, c) wynik sortowania.
Złożoność obliczeniowa proponowanego algorytmu jest rzędu O(N2/M) gdzie N i M to odpowiednio
liczba cząstek i liczba kubełków. Ze względu na równoległe przetwarzanie liczba cykli procesora
mogła być mniejsza, niż dla klasycznego algorytmu sortowania kubełkowego.
Dla powyższego algorytmu przeprowadzono dwie dodatkowe optymalizacje. Pierwszą z nich było
zastosowanie "przesuwanego okna" o stałym rozmiarze. Przy pierwszym przebiegu listy odsyłaczowe
tworzone były jedynie w obrębie okien, a scalane w jedną były dopiero w ostatecznym kroku
algorytmu.
Druga optymalizacja wynikała z obserwacji, że w ciągu kroku czasowego symulacji tylko niewielka
część cząstek zmieniała zajmowaną komórkę. W związku z powyższym dodano początkowy krok,
którego zadaniem było usunięcie z gotowych list odsyłaczowych elementów, które powinny znaleźć się
w innych komórkach. Następnie stosowany był wyżej opisany algorytm sortowania kubełkowego, z tą
różnicą, że zaczynał od już częściowo uporządkowanych list.
Zaproponowany algorytm symulacji został zaimplementowany na karcie graficznej GeForce 6800
Ultra. Dane cząstek, położenie i pęd, przechowywane były w postaci 32-bitowych,
zmiennoprzecinkowych tekstur, natomiast indeksy list odsyłaczowych kodowane były jako 8-bitowe,
całkowite składowe RGBA.
Implementacja algorytmu na GPU wymagała rozwiązania szeregu problemów technicznych. Ze
względu na model przetwarzania potokowego nie było możliwe zrealizowanie zapisu do dowolnej
pozycji w pamięci. W tym celu autor zastosował mechanizm renderowania punktów. Dane cząstek były
kopiowane z pamięci tekstury do pamięci wierzchołków, skąd następowało renderowanie punktów z
przetwarzaniem pozycji cząstki na identyfikator komórki przy użyciu jednostki vertex shader.
Drugą przeszkodą była realizacja warunku stopu. Do tego celu zastosowano mechanizm testowania
okluzji, informującej o liczbie elementów, które pozytywnie przeszły wszystkie testy w potoku
renderowania. W przypadku algorytmu sortowania kubełkowego badane było, ile cząstek dodanych
zostało do list odsyłaczowych. Algorytm kończył działanie, gdy liczba ta wynosiła zero.
Dla metody DPD konieczne było również zaimplementowanie na GPU generatora liczb
pseudolosowych, działającego jedynie w oparciu o liczby zmiennoprzecinkowe.
Otrzymane wyniki eksperymentalne porównano z implementacją na tradycyjnym procesorze oraz
podobnym algorytmem sortowania działającym na GPU, pokazując lepszą wydajność algorytmu
autorskiego.
Procesor Cell
Układ Cell jest jednostką heterogeniczną, składającą się z jednego rdzenia ogólnego przeznaczenie
PPU oraz ośmiu niezależnych rdzeni przetwarzania wektorowego SPU (sześciu w przypadku wersji
procesora w Playstation 3), każdy wyposażony jedynie w 256kB dostępnej pamięci. Ze względu na
nietypową budowę procesora standardowy schemat realizacji symulacji metodami cząstek polegający
na: 1) znalezieniu par oddziałujących cząstek, 2) obliczeniu sił oddziaływań, 3) rozwiązania układu
równań ruchu musiał zostać zmodyfikowany, aby wykorzystać dostępną moc obliczeniową oraz
specyficzną architekturę pamięci. Ze względu na duża liczbę obliczeń zmiennoprzecinkowych oraz
lokalność oddziaływań obliczenia te mogły być wykonane na jednostkach SPE. Natomiast pierwszy
krok, wymagający przejrzenia wszystkich cząstek, musiał zostać zrealizowany przez rdzeń główny.
Rys.2. Podział przestrzeni symulacji na pionowe „kominy” składające się z poziomych „plastrów” o
wysokości komórki. Prezentowany komin składa się z 4x4xN komórek wraz z komórkami
otaczającymi.
Z powodów wymienionych powyżej ogólny układ algorytmu był następujący: na początku cząstki
przyporządkowywane były do odpowiednich komórek na jednostce PPU, następnie dane rozsyłane
były do jednostek SPU w celu przeprowadzenia obliczeń. Ostatecznie wyniki były zwracane do
pamięci głównej, gdzie następowało scalane.
Cała przestrzeń symulacji, składająca się sześciennych komórek, została podzielona na pionowe
"kominy", które natomiast składały się z poziomych "plastrów" (rys.2). Podział ten był niezbędny ze
względu na niewielką dostępną pamięć jednostek SPU. Po rozdzieleniu cząstek do komórek rdzeń PPU
zajmował się rozsyłaniem zadań do jednostek SPU. Podstawową jednostką przesyłaną był "plaster"
składający się z NxN komórek "komina", wraz z komórkami otaczającymi. Architektura wewnętrzna
procesora Cell pozwalała jednostkom SPU na wykonywanie obliczeń przy równoczesnym,
asynchronicznym przesyłaniu danych wejściowych oraz wyjściowych. Ze względu na nieduża pamięć
SPU operował równocześnie na trzech "plastrach" oraz buforach wejścia/wyjścia.
Przyjęty model pamięci podyktowany był wymogami architektury procesora. W celu zapewnienia
efektywnego transferu oraz przetwarzania wektorowego dane były wyrównywane do granicy 128bitów. Również efektywny transfer danych wymagał wyrównywania początku paczki danych do
granicy 128 bajtów.
Program został zaimplementowany w języku C++ z wykorzystaniem instrukcji typu intrinsics,
realizujących rozkazy SIMD procesora Cell. Następnie został poddany optymalizacji przez
reorganizację operacji arytmetycznych oraz dostępu do pamięci, dając pełniejsze wykorzystanie
dostępnych potoków przetwarzania. Przesyłanie danych między pamięcią główną i pamięcią lokalną
SPU, inicjowane przez SPU, odbywało się asynchronicznie.
Opisany algorytm został zaimplementowany i uruchomiony na konsoli do gier Playstation 3,
wyposażonej w procesor Cell, działającej pod kontrolą systemu operacyjnego Linux. Zbadano
wydajność programu symulacyjnego dla różnych konfiguracji oraz różnej liczby aktywnych rdzeni.
Wyniki porównano z tradycyjnym procesorem, wykazując lepszą wydajność procesora Cell.
Dodatkowo zbadano zysk z zastosowanych optymalizacji, jednak całkowite przyspieszenie było bardzo
niewielkie rzędu 3% procent.
W ramach pracy przeprowadzono również badanie wydajności przesyłania danych między jednostką
główną a jednostkami pomocniczymi dla użytego schematu komunikacji. Uzyskano wynik
maksymalny rzędu 13GB/s.
CUDA
Architektura CUDA powstała w wyniku rozwoju procesorów graficznych, pojawiła się w momencie,
gdy układy te zaczęły zyskiwać uznanie w zastosowaniach naukowych o charakterze obliczeniowym.
CUDA znosi konieczność stosowania interfejsów programowania grafiki oraz liczne ograniczenia z
nimi związane, jednak nadal wykazuje duże podobieństwo do klasycznej architektury GPU. W związku
z tym ogólny układ algorytmu jest podobny do omówionego w ramach GPU. Tutaj także głównym
problemem była implementacja algorytmu znajdowania sąsiadów, realizowanego za pomocą
sortowania kubełkowego.
Algorytm sortowania kubełkowego dla architektury CUDA różni się jednak zasadniczo od
omawianego powyżej. Nowością wprowadzoną do architektury CUDA były instrukcje zapewniające
atomowość równoległych operacji na pamięci. Za pomocą instrukcji atomicExch możliwe jest
zrealizowanie sortowania kubełkowego w kilku instrukcjach. W pierwszym kroku na początek listy
wpisywany jest element, należący do kubełka, a następnie ustawiany jest wskaźnik na element
następny, którym jest dotychczasowy element z początku. Ze względu na atomowość tych operacji
nigdy nie nastąpi konflikt w zapisie. Natomiast rozwiązanie takie jest mało wydajne ze względu na
koszt operacji atomowych oraz nie wykorzystuje w pełni dostępnego sprzętu.
Dlatego też dokonano szeregu optymalizacji i zmian. Po pierwsze należy zauważyć, że wątki
wykonywane są grupami po kilkaset. W związku z tym korzystne jest, aby pracowały na wspólnych
danych. CUDA oferuje pamięć współdzieloną dla grup wątków, gdzie kopiowane były dane do
przetwarzania. Aby zapewnić spójność danych w pamięci wspólnej dokonywana jest synchronizacja
dostępów. Algorytm realizuje następujące kroki:
1. Kopiowanie danych do pamięci wspólnej, gdzie budowana będzie lokalna lista odsyłaczowa.
2. Znalezienie elementów należących do tych samych kubełków w lokalnych danych i tworzenie
lokalnych list odsyłaczowych.
3. Integrowanie lokalnych list odsyłaczowych z danymi globalnymi, z wykorzystaniem operacji
atomowych.
4. Ustawienie końca listy lokalnej na element będący uprzednio na przedzie.
5. Kopiowanie lokalnej tablicy indeksów do pamięci globalnej.
Problemem z wykorzystaniem listy odsyłaczowej jest rozproszenie danych w pamięci. Dlatego
wprowadzony został krok reorganizacji, który przekształcał listę odsyłaczową w tablicę. Numer
kubełka elementów był niemalejący. Aby tego dokonać należało równolegle wyliczyć rozmiar każdego
z kubełków, a następnie wyznaczyć indeksy początkowe dla każdego kubełka. Na zakończenie
następowała reorganizacja danych według otrzymanych indeksów.
Opisany algorytm sortowania był podstawą do implementacji metod oddziałujących cząstek. Dla danej
cząstki obliczenie oddziaływań wymagało przejrzenia list cząstek z otaczających komórek. Następnie
nowe współrzędne położenia wyznaczane były z równań ruchu.
Otrzymane wyniki eksperymentalne porównano z istniejącym algorytmem sortowania pozycyjnego.
Algorytm prezentowany przez autora dla dużych danych był szybszy od konkurencyjnego o 20-40%.
Następnie porównano czasy symulacji na karcie graficznej GeForce 8800GT z procesorem
tradycyjnym.
Wyniki eksperymentalne
Tab.1. pokazuje porównanie czasów obliczeń dla różnych architektur komputerowych. Celem pracy
doktorskiej było opracowanie i implementacja algorytmów oddziałujących cząstek dla pierwszych
trzech: GPU, Cell i CUDA. Ze względu na różny czas, w którym pojawiały się te procesory nie jest
wskazane porównanie ich między sobą. Widać, że wraz z pojawianiem się nowych generacji sprzętu
czas symulacji malał. Dla porównania zostały pokazane czasy symulacji dla dwóch tradycyjnych
procesorów. Procesor Itanium został umieszczony w porównaniu ze względu na powszechne użycie w
klastrach takich jak Altix. Pokazano wyniki również dla nowoczesnego procesora, jakim był Core 2
Duo. Procesor ten wykonywał program jednowątkowy, dlatego należy przypuszczać, że czas obliczeń
wielowątkowych byłby o połowę krótszy. Nie mniej jednak czas uzyskany algorytmami opracowanymi
przez autora jest znacząco krótszy.
Na rys.3. przedstawiono wybrane klatki z symulacji metodami cząstek, które były realizowane w
ramach pracy doktorskiej. Jakościowe wyniki nie różniły się między poszczególnymi architekturami,
natomiast różne były trajektorie pojedynczych cząstek. Wynikało to z różnej kolejności obliczeń
przeprowadzanych przez zaimplementowane algorytmy.
Procesor
Czas obliczeń [s]
GPU (GeForce 6800 Ultra)
1.868
Cell B.E.
1.353
CUDA (GeForce 8800 GT)
0.251
Itanium 1.5 GHz
Core 2 Duo 2.4 GHz (1 wątek)
15.765
3.392
Tab. 1. Czas obliczeń jednego kroku symulacyjnego w sekundach dla różnych architektur
komputerowych. Układ obliczeniowy składał się z 220 cząstek.
Rys.3. Przykładowe wyniki symulacji uzyskane w ramach badania algorytmów opisanych w pracy. Od
lewej do prawej: separacja faz (DPD), efekt Rayleigha-Taylora (DPD), przerwanie tamy (SPH).
Podsumowanie
W rozprawie przedstawione zostały wyniki prac nad zastosowaniem architektur masywnie
równoległych do rozwiązywania problemów symulacji metodą oddziałujących cząstek. Przedstawione
propozycje algorytmów i ich implementacje dotyczyły oddziaływań krótkozasięgowych występujących
w modelach takich, jak dynamika dyssypatywnych cząstek (DPD) oraz także hydrodynamika
wygładzonych cząstek (SPH). Metody tego typu wymagają dużych mocy obliczeniowych. Jednak
bezpośrednie przenoszenie istniejących algorytmów na architektury masywnie równoległe nie jest, z
wielu powodów, możliwe. Konieczna jest nie tylko zmiana algorytmów ale także koncepcji
projektowania oprogramowania i specyficzna implementacja.
W niniejszej pracy udało się zrealizować następujące cele:
• Udowodniono możliwość przeprowadzania efektywnej symulacji metodami cząstek na
architekturach masywnie wielopotokowych. Dotyczy to także jednostek obliczeniowych, takich
jak karty graficzne, których oryginalne przeznaczenie jest zupełnie inne.
• Zbadano funkcjonalność oraz model programowania pod kątem symulacji metodami cząstek
dla następujących architektur komputerowych: kart graficznych korzystających z graficznego
interfejsu programowania (np. OpenGL), heterogenicznego procesora Cell Broadband Engine,
jednostek o architekturze CUDA.
• Zaproponowano implementację symulacji metodami cząstek dla każdej z wymienionych
architektur.
• Opracowano algorytmy sortowania kubełkowego oraz korzystające z nich algorytmy
znajdowania sąsiadów dla architektur GPU oraz CUDA.
• Zbadano wydajność oraz określono złożoność obliczeniową algorytmów zaimplementowanych
dla testowanych architektur. Wyniki zostały porównane z wynikami otrzymanymi dla
tradycyjnych architektur procesorowych. Świadczą one o przydatności architektur masywnie
równoległych dla symulacji metodami cząstek. Co więcej, zaproponowane algorytmy uzyskują
krótsze czasy wykonania niż ich odpowiedniki na tradycyjnych procesorach.
• Dla architektury CUDA porównane zostały różne sposoby znajdowania i przeglądania
sąsiadów. Wskazano metodę optymalną.
• Dla architektury Cell zaproponowano efektywny mechanizm podziału problemu
obliczeniowego na mniejsze zadania umożliwiający wydajną transmisję danych pomiędzy
jednostkami składowymi procesora. Ponadto przebadano przepustowość przesyłania danych z
pamięci systemowej do pamięci lokalnych.
• Dla kart graficznych zaproponowane zostało wykorzystanie generatora liczb pseudolosowych,
operującego jedynie na liczbach zmiennoprzecinkowych.
Badania przeprowadzane w ramach niniejszej pracy były ograniczone pod różnymi względami.
Pozostawiają one jednak miejsce na dalszą pracę, w ramach której można wymienić:
•
•
•
•
•
Implementację nowoczesnych modeli oddziałujących cząstek uwzględniających stan
termodynamiczny układu takich, jak GENERIC DPD oraz SDPD.
Wzbogacenie implementowanych modeli oddziaływań cząstek o oddziaływania dalekiego
zasięgu.
Zaproponowanie wspólnego środowiska dla realizacji różnorodnych metod cząstek, które
potrafiłoby efektywnie wykorzystać różnego typu sprzęt komputerowy.
Opracowanie algorytmów dla wykorzystania większej liczby węzłów obliczeniowych. Klaster
złożony z komputerów o jednostkach masywnie wielopotokowych byłby w stanie rozwiązywać
problemy o niespotykanych dotychczas rozmiarach.
Przetestowanie architektur komputerowych następnych generacji, takich jak Larrabee firmy
Intel.