Używam CUDA od kilku tygodni, ale mam pewne wątpliwości co do alokacji bloków / wypaczeń / wątków. Studiuję architekturę z dydaktycznego punktu widzenia (projekt uniwersytecki), więc osiągnięcie maksymalnej wydajności nie jest moim problemem.
Przede wszystkim chciałbym zrozumieć, czy dobrze zrozumiałem te fakty:
Programista pisze jądro i organizuje jego wykonanie w siatce bloków wątków.
Każdy blok jest przypisany do wieloprocesora strumieniowego (SM). Po przypisaniu nie można go migrować do innego SM.
Każda SM dzieli swoje własne bloki na Warps (obecnie o maksymalnym rozmiarze 32 wątków). Wszystkie wątki w warpie są wykonywane jednocześnie na zasobach SM.
Faktyczne wykonanie wątku jest wykonywane przez rdzenie CUDA zawarte w SM. Nie ma określonego mapowania między wątkami i rdzeniami.
Jeśli osnowa zawiera 20 wątków, ale obecnie dostępnych jest tylko 16 rdzeni, osnowa nie będzie działać.
Z drugiej strony, jeśli blok zawiera 48 wątków, zostanie podzielony na 2 wypaczenia i będą one wykonywane równolegle, pod warunkiem, że dostępna jest wystarczająca ilość pamięci.
Jeśli wątek zostanie uruchomiony na rdzeniu, zostanie zatrzymany w celu uzyskania dostępu do pamięci lub długiej operacji zmiennoprzecinkowej, jego wykonanie może zostać wznowione na innym rdzeniu.
Czy mają rację?
Teraz mam GeForce 560 Ti, więc zgodnie ze specyfikacją jest wyposażony w 8 SM, każdy zawierający 48 rdzeni CUDA (łącznie 384 rdzenie).
Moim celem jest upewnienie się, że każdy rdzeń architektury wykonuje SAME instrukcje. Zakładając, że mój kod nie będzie wymagał więcej rejestrów niż te dostępne w każdym SM, wyobrażałem sobie różne podejścia:
Tworzę 8 bloków po 48 wątków, więc każdy SM ma 1 blok do wykonania. Czy w takim przypadku 48 wątków będzie działać równolegle w SM (wykorzystując wszystkie 48 dostępnych dla nich rdzeni)?
Czy jest jakaś różnica, jeśli uruchomię 64 bloki po 6 wątków? (Zakładając, że zostaną one odwzorowane równomiernie między SM)
Jeśli "zanurzę" GPU w zaplanowanej pracy (na przykład tworząc 1024 bloki po 1024 wątki), to rozsądnie jest założyć, że wszystkie rdzenie zostaną użyte w pewnym momencie i wykonają te same obliczenia (zakładając, że wątki nigdy nie przeciągnij)?
Czy istnieje sposób, aby sprawdzić te sytuacje za pomocą profilera?
Czy jest jakieś odniesienie do tych rzeczy? Przeczytałem przewodnik programowania CUDA oraz rozdziały poświęcone architekturze sprzętowej w rozdziałach „Programowanie masowo równoległych procesorów” oraz „Projektowanie i tworzenie aplikacji CUDA”; ale nie mogłem uzyskać dokładnej odpowiedzi.
źródło
Odpowiedzi:
Dwie najlepsze referencje to
Spróbuję odpowiedzieć na każde Twoje pytanie.
Programista dzieli pracę na wątki, wątki na bloki wątków i bloki wątków na siatki. Dystrybutor pracy obliczeniowej przydziela bloki wątków do wieloprocesorów przesyłania strumieniowego (SM). Gdy blok wątków jest dystrybuowany do SM, zasoby dla bloku wątków są przydzielane (wypaczenia i pamięć współdzielona), a wątki są dzielone na grupy po 32 wątki zwane wypaczeniami. Po przydzieleniu wypaczenia nazywa się je aktywnym wypaczeniem. Dwa programy planujące wypaczenia wybierają dwa aktywne wypaczenia na cykl i wysyłają wypaczenia do jednostek wykonawczych. Aby uzyskać więcej informacji na temat jednostek wykonawczych i wysyłania instrukcji, patrz 1 str. 7-10 i 2 .
4 ' . Istnieje mapowanie między linią (indeks wątków w osnowie) a rdzeniem.
5 ' . Jeśli wypaczenie zawiera mniej niż 32 wątki, w większości przypadków zostanie wykonane tak samo, jak gdyby miało 32 wątki. Wypaczenia mogą mieć mniej niż 32 aktywne wątki z kilku powodów: liczba wątków na blok nie jest podzielna przez 32, program wykonuje rozbieżny blok, więc wątki, które nie przeszły bieżącą ścieżką, są oznaczane jako nieaktywne lub wątek w wypaczeniu został zakończony.
6 ' . Blok wątku zostanie podzielony na WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1) / WarpSize Nie ma wymogu, aby harmonogramy wypaczania wybierały dwa wypaczenia z tego samego bloku wątku.
7 ' . Jednostka wykonawcza nie zatrzyma się w operacji pamięci. Jeśli zasób nie jest dostępny, gdy instrukcja jest gotowa do wysłania, instrukcja zostanie wysłana ponownie w przyszłości, gdy zasób będzie dostępny. Wypaczenia mogą utknąć na barierach, przy operacjach pamięciowych, operacjach na teksturach, zależnościach danych, ... Zatrzymane wypaczenie nie kwalifikuje się do wybrania przez harmonogram wypaczania. Na Fermi przydatne jest posiadanie co najmniej 2 kwalifikujących się wypaczeń na cykl, aby program planujący wypaczenie mógł wydać instrukcję.
Zobacz odniesienie 2, aby poznać różnice między GTX480 i GTX560.
Jeśli przeczytasz materiał referencyjny (kilka minut), myślę, że zauważysz, że twój cel nie ma sensu. Postaram się odpowiedzieć na Twoje uwagi.
1 ' . Jeśli uruchomisz jądro <<< 8, 48 >>>, otrzymasz 8 bloków, każdy z 2 wypaczeniami po 32 i 16 wątków. Nie ma gwarancji, że te 8 bloków zostanie przypisanych do różnych modułów SM. Jeżeli do SM przydzielone są 2 bloki, możliwe jest, że każdy program planujący odkształcenie może wybrać wypaczenie i wykonać wypaczenie. Będziesz używać tylko 32 z 48 rdzeni.
2 ' . Istnieje duża różnica między 8 blokami po 48 wątków a 64 blokami po 6 wątków. Załóżmy, że twoje jądro nie ma rozbieżności i każdy wątek wykonuje 10 instrukcji.
W celu uzyskania optymalnej wydajności podział pracy powinien być wielokrotnością 32 wątków. Sprzęt nie będzie łączył wątków z różnych wypaczeń.
3 ' . GTX560 może mieć 8 bloków SM * 8 = 64 bloki na raz lub 8 SM * 48 warps = 512 warps, jeśli jądro nie ma maksymalnej liczby rejestrów lub pamięci współdzielonej. W dowolnym momencie część pracy będzie aktywna na SM. Każdy moduł SM ma wiele jednostek wykonawczych (więcej niż rdzenie CUDA). To, które zasoby są używane w danym momencie, zależy od harmonogramów wypaczania i zestawu instrukcji aplikacji. Jeśli nie wykonasz operacji TEX, jednostki TEX będą bezczynne. Jeśli nie wykonasz specjalnej operacji zmiennoprzecinkowej, jednostki SUFU będą bezczynne.
4 ' . Parallel Nsight i pokaz Visual Profiler
za. wykonane IPC
b. wydany IPC
do. aktywne wypaczenia na aktywny cykl
re. kwalifikujące się wypaczenia na aktywny cykl (tylko w nocy)
mi. przyczyny przeciągnięcia warp (tylko w nocy)
fa. aktywnych wątków na wykonaną instrukcję
Profiler nie pokazuje procentu wykorzystania żadnej z jednostek wykonawczych. W przypadku GTX560 zgrubne oszacowanie to IssuedIPC / MaxIPC. Dla MaxIPC załóżmy, że GF100 (GTX480) to 2 GF10x (GTX560) to 4, ale cel to 3 to lepszy cel.
źródło
„E. Jeśli warp zawiera 20 wątków, ale obecnie dostępnych jest tylko 16 rdzeni, warp nie będzie działać”.
jest nieprawidłowe. Mylisz rdzenie w ich zwykłym sensie (również w procesorach) - liczba „procesorów wieloprocesorowych” w GPU, z rdzeniami w marketingu nVIDIA („nasza karta ma tysiące rdzeni CUDA”).
Samo wypaczenie może być zaplanowane tylko na jednym rdzeniu (= wieloprocesorowym) i może działać do 32 wątków w tym samym czasie; nie może używać więcej niż jednego rdzenia.
Liczba „48 wypaczeń” to maksymalna liczba aktywnych wypaczeń (wypaczeń, które można wybrać do zaplanowania pracy w następnym cyklu, w dowolnym cyklu) na wieloprocesorowy procesor graficzny nVIDIA z wydajnością obliczeniową 2.x; a ta liczba odpowiada 1536 = 48 x 32 wątki.
Odpowiedz na podstawie tego seminarium internetowego
źródło