Wydajność w programowaniu równoległym GPU
W kontekście programowania równoległego na GPU, wydajność oznacza maksymalne wykorzystanie dostępnych zasobów obliczeniowych przy minimalnych opóźnieniach i minimalnym zużyciu pamięci. Na osiągnięcie przytoczonych założeń składają się następujące czynniki:
- optymalne zarządzanie pamięcią poprzez unikanie dostępu do pamięci globalnej wraz z częstszymi operacjami w pamięci współdzielonej,
- zrównoważone obciążenie jednostek sprzętowych poprzez optymalne przydzielanie wątków na rdzenie CUDA,
- maksymalne wykorzystanie przepustowości poprzez transferu danych poprzez łączenie ze sobą operacji dostępu do pamięci oraz unikanie przeciążeń magistrali PCIe lub NVLink.
Konsekwencje nieoptymalnego kodu CUDA
Kod źródłowy CUDA, uruchamiany na GPU przygotowany w sposób niestaranny i nieoptymalny może prowadzić do następujących problemów:
- niepełne (i nierównomierne) wykorzystanie zasobów sprzętowych, co może powodować zjawisko kolejkowania wątków do wykonania na obciążonych jednostkach obliczeniowych podczas gdy inne będą pozostawały nieużywane,
- wysokie opóźnienia w dostępie do pamięci, co znacznie opóźnia przydział warp’ów do wykonania na partycjach SM,
- problematyczna i długotrwała synchronizacja wątków w przypadkach częstych transferów pamięci między GPU a CPU.
Metody optymalizacji kodu CUDA
- profilowanie,
- optymalizacja dostępu do pamięci GPU poprzez stosowanie pamięci współdzielonej i tymczasowej,
- optymalizacja organizacji wątków poprzez dopasowanie rozmiaru bloków i siatki do architektury układu GPU.
Profilowanie kodu źródłowego
Profilowanie kodu to proces analizy programu w celu identyfikacji jego wydajności, zużycia zasobów obliczeniowych i pamięciowych oraz potencjalnych wąskich gardeł. W kontekście obliczeń równoległych i CUDA, profilowanie pozwala zrozumieć, jak kod wykorzystuje GPU, jakie są jego główne ograniczenia i jak można go zoptymalizować.
Cele profilowania kodu