DejaVu |
» 2014-10-21 01:17:11 Ja jeszcze dodam, że w sumie dumam sobie nad tą technologią już około dwóch tygodni, tydzień sobie z nią poeksperymentowałem i porobiłem notatki z własnymi spostrzeżeniami.
Generalnie rzecz biorąc, efektywne wykorzystanie GPU jest trudne, ponieważ: 1) każda karta graficzna ma inną liczbę rdzeni, inną moc rdzeni i inne parametry pamięci. 2) algorytmy, które chcemy przerzucić na GPU mają różną charakterystykę i dla jednego algorytmu wąskim gardłem może być przepustowość pamięci oraz koszty jej współdzielenia, a dla innego moc obliczeniowa.
Na temat GPU dostępnych jest sporo wykładów, które pokazują uzyskiwanie wzrostu wydajności wraz z redukcją liczby używanych rdzeni GPU i tu właśnie pojawił mi się powód do rozmyślań w jaki sposób maksymalnie wykorzystać moc obliczeniową, jaką dostarcza nam współczesna domowa technologia.
Dane wejściowe GPUPracując z GPU u podstaw leży wymiana danych między CPU, a GPU. Dane wejściowe w zasadzie można zdefiniować często w postaci jednej lub kilku tablic. Dane wejściowe mogą być wspólne dla każdego wątku, lub tablica może zawierać zestawy do wykonania przez dowolny wątek. Układy mogą być też mieszane. W obu przypadkach kluczem jest transmisja danych z CPU do GPU dużymi blokami pamięci.
Dane wyjściowe GPUArchitektura GPU generalnie sugeruje, aby ilość danych wyjściowych była zależna od ilości danych wejściowych, a nie od ich zawartości. Taki układ jest bardzo łatwy do zaimplementowania, ponieważ wystarczy zaalokować określoną ilość pamięci przed rozpoczęciem kernela GPU, odpowiedzialnego za wykonanie naszych obliczeń na GPU. Problem w tym, że jest też spora pula algorytmów, która generuje nowe rozwiązania, a dynamiczna alokacja pamięci nie jest możliwa w trakcie pracy kernela GPU w taki sposób, aby dało się później przekazać wygenerowane wyniki z GPU do CPU. Oznacza to, że uruchamiając GPU musimy zaalokować dostatecznie duży obszar pamięci, który pomieści wszystkie ewentualne wyniki, które wygeneruje algorytm uruchomiony na GPU. W tym miejscu pojawia się również problem efektywnego zarządzania wspólnym obszarem pamięci, ponieważ wątków możemy mieć 2 tysiące i każdy z nich może produkować intensywną ilość danych wyjściowych, które w jakiś sposób trzeba koordynować, aby się te dane nie nadpisywały. Tu też pojawia się potężny problem zachowania wysokiej wydajności algorytmów wykorzystujących moc obliczeniową GPU oraz ten wycinek problemu będzie wymagał sporej ilości przemyślanego kodu, aby zrobić komunikację w sposób elegancki, wygodny i wydajny.
Dynamiczna alokacja pamięci podczas wykonywania algorytmu na GPUPo dokształceniu się z technologii CUDA okazało się, że dynamiczna alokacja pamięci na GPU jest możliwa, ale alokacja i dealokacja musi odbyć się w kernelu, czyli podczas wykonywania obliczeń. To prawdopodobnie oznacza, że nie da rady takiej pamięci wykorzystać do zwracania dynamicznej ilości wyników. Zastanawiam się jeszcze, czy aby na pewno nie da rady zaalokować dynamicznie pamięci na GPU, zwrócić wyniki kończąc pracę kernela, a następnie uruchomić drugiego kernela, który posprzątałby pamięć wcześniej zaalokowaną na GPU przez poprzedni kernel - to jest jakiś pomysł, który wymaga weryfikacji z dokumentacją CUDA (bo ja drążę intensywnie technologię CUDA, a nie OpenCL).
Synchronizacja wątkówWątki można synchronizować w obrębie bloku, choć synchronizacji generalnie rzecz biorąc należy unikać. Warto zastanowić się również, czy synchronizacja aby na pewno jest konieczna, ponieważ być może da się oczekiwany efekt osiągnąć operacjami atomowymi, które dostarcza CUDA w postaci kilku funkcji.
Wykorzystywanie pamięci współdzielonej (shared)Pamięć współdzielona (shared) jest generalnie rzecz biorąc bardzo mała. Nie ma sensu nawet rozważać jak jej używać, jeżeli przetwarzasz ogromne ilości danych. Jeżeli jednak masz względnie mało danych wejściowych i dużo obliczeń, to warto podumać nad tą pamięcią, bo ponoć jest ona ~10-krotnie szybsza od pamięci globalnej GPU (w zasadzie jej szybkość jest bardzo zbliżona do szybkości rejestrów GPU). Osobiście na razie trzymam się z daleka od tego obszaru pamięci, ponieważ uważam (być może błędnie), że bardzo utrudnia to myślenie o skalowalności rozwiązania na urządzenia, które mają do dyspozycji po 2 tysiące rdzeni lub więcej.
GPU, a programowanie obiektoweNa dzień dzisiejszy przystosowanie technologii GPU w taki sposób, aby było możliwe wygodne tworzenie algorytmów z wykorzystaniem obiektowości jest możliwe, ale wymaga dużego nakładu pracy. De-facto trzeba by było poświęcić kilka miesięcy intensywnej pracy nad samym frameworkiem oraz jego ustabilizowaniem, aby później móc spokojnie zacząć bawić się w pisanie fajnych i jednocześnie użytecznych algorytmów na GPU. |