Na początek odrobina marketingu. Jak to zwykle w takich przypadkach bywa, producent mówi o kolejnym przełomie, choć przy tym dość wyraźnie zaznacza, że Volta jest rozwinięciem pomysłów znanych z Pascala. Ostatecznie wszystko i tak sprowadza się do frazesów o poprawie wydajności, skalowalności i łatwości programowania, ale technicznie rzecz biorąc, lista zmian jest całkiem pokaźna. Wypada jednak zauważyć, że są to zmiany, na których skorzystają przede wszystkim środowiska HPC (High Performance Computing), centra danych czy systemy uczenia maszynowego, a tym samym szeroko pojęci profesjonaliści.
Dla graczy Volta, przynajmniej w obecnej formie układu GV100, jest głównie rozwinięciem ilościowym, a nie jakościowym. Nie bez kozery nawet Titan V nie jest przedstawiany jako czołowy sprzęt do gier. Gdzieniegdzie pojawiają się jeszcze plotki o wyspecjalizowanej, tym razem pod kątem rozrywki, architekturze Ampere.
Żeby zrozumieć istotę problemu, wystarczy przeanalizować kluczowe cechy Volty wymienione przez producenta. Nvidia chwali się m.in. zoptymalizowaną pod kątem uczenia maszynowego architekturą Streaming Multiprocessor (SM), drugą generacją łącza NVLink, sprzętową akceleracją serwerów CUDA MPS z trzykrotnym powiększeniem liczby klientów, poprawkami do systemu unifikującego pamięć czy wreszcie nowymi funkcjami oszczędzania energii dla klastrów wieloprocesorowych, obiecując przy okazji przystosowane wersje frameworków uczenia maszynowego, na przykład Caffe2, MXNet, CNTK i TensorFlow. Zabrakło jakiejkolwiek wzmianki o grach.
Są za to imponujące cyferki związane z teoretyczną efektywnością obliczeniową. Przy domyślnej częstotliwości taktowania w trybie Boost, 1530 MHz, wydajność w obliczeniach podwójnej precyzji (FP64) ma dochodzić do 7,8 teraflopa, a pojedynczej (FP32) – 15,7 teraflopa. Mało tego, nowe rdzenie Tensor (pisaliśmy o nich w odrębnym artykule) w precyzji mieszanej zapewniają ponoć 125 teraflopów. Nawet bez uwzględnienia tej ostatniej wielkości liczby robią wrażenie. Dla porównania, układ GP100 z linii Pascal w kluczowej dla zastosowań naukowych podwójnej precyzji zapewnia „tylko” 5,3 teraflopa.
Ale przejdźmy do tego, co tygryski lubią najbardziej, czyli omówienia budowy układu GV100 z uwzględnieniem wspomnianych założeń architektury.
GV100 jest największym procesorem graficznym w historii. Ma 21,1 mld tranzystorów przy powierzchni 815 mm2. Wytwarzany jest przez TSMC w procesie technologicznym klasy 12 nm FFN (FinFET Nvidia), który zoptymalizowano właśnie pod kątem produktów „zielonych”. Detale pozostają, niestety, owiane tajemnicą. Wiadomo natomiast, że struktura korzysta z koncepcji klastrowej, łudząco podobnej do ubiegłych generacji. Rdzeń ma sześć klastrów przetwarzania grafiki (Graphics Processing Cluster – GPC), z których każdy ma siedem klastrów przetwarzania tekstur (Texture Processing Cluster – TPC), a w konsekwencji – 14 multiprocesorów strumieniujących (Streaming Multiprocessor – SM). Do tego dochodzi osiem 512-bitowych kontrolerów HBM2, które są połączone bezpośrednio z 768 kB pamięci podręcznej drugiego poziomu, co daje sumarycznie 6144 kB L2. Na tym etapie różnice względem GP100 są wyłącznie ilościowe. Po pierwsze, w poprzedniku na pojedynczy GPC przypada nie siedem, ale pięć TPC, a po drugie ilość L2 wynosi 512 kB na jednostkę organizacyjną. Faktyczne zmiany w architekturze nastąpiły w samych jednostkach SM, które od teraz określane są mianem Volta SM.
Każdy blok Volta SM jest współtworzony przez 64 rdzenie FP32, 64 rdzenie INT32, 32 rdzenie FP64, osiem rdzeni Tensor oraz cztery jednostki mapowania tekstur. Wszystko to przekłada się na 5376 rdzeni FP32 i INT32, 2688 rdzeni FP64, 672 rdzenie Tensor oraz 336 jednostek teksturujących. Niemniej na rynku nie ma karty o takiej konfiguracji. Zarówno Tesla V100, jak i Titan V są ograniczone do 80 SM – 5120 rdzeni FP32 i INT32, 2560 rdzeni FP64, 640 rdzeni Tensor oraz 320 jednostek TMU. Suche cyferki, wyjąwszy rdzenie Tensor, sugerują, że układ GV100 pod względem struktury SM jest niezwykle zbliżony do poprzednika, GP100, ale tak nie jest. Istotnie zmodyfikowano bowiem jego organizację.
Podczas gdy każdy SM poprzedniej generacji podzielony jest na dwa bloki przetwarzania, Volta SM ma ich cztery. Tym samym 32-wątkowy planista (ang. warp scheduler) i dyspozytor (ang. dispatch unit) są samodzielne dla każdej jednostki organizacyjnej, a nie podwojone i współdzielone pomiędzy większą liczbę zasobów obliczeniowych. Na tej podstawie rozbito również 128-kilobajtową tablicę rejestrów na dwa autonomiczne rejestry o pojemności 64 kB. Zupełną nowość stanowi pamięć L0 na rozkazy, mająca usprawnić ich bufory. Co ciekawe, w dziedzinie pamięci L1 i współdzielonej (ang. shared memory) postąpiono odwrotnie niż przy jednostkach organizacyjnych – scalono ją. W rezultacie programista może zaadresować do 96 kB, zamiast 64 kB, jak w Pascalu.
Wspomniane zmiany w obrębie podsystemu pamięci są chyba najciekawsze ze wszystkich. Ujmując rzecz najprościej, jak tylko się da, pamięć współdzielona jest pulą pamięci o wydajności L1, dostępną dla programisty, który może przenieść do niej chociażby dane wymagające wielokrotnego dostępu. Jak wiadomo, typowa pamięć podręczna działa w pełni automatycznie, nie umożliwiając jakiejkolwiek kontroli programowej. Dotychczas oba te bloki działały oddzielnie. Jeśli więc programista nie korzystał z techniki shared memory, pewna część zasobów leżała odłogiem. Volta daje możliwość wykorzystania tejże jako tradycyjnej pamięci L1.
Nawiasem mówiąc, jest to swego rodzaju powrót do przeszłości. Fermi oraz Kepler też mają pamięć podręczną zintegrowaną z pamięcią współdzieloną, ale tam z kolei odrębna pozostaje pamięć podręczna dla tekstur, która to począwszy od Maxwella jest równoznaczna z pamięcią podręczną poziomu pierwszego.
Ale to nie wszystko. Jak twierdzi Nvidia, integracja obydwu bloków pozwoliła osiągnąć większą przepustowość, jak również mniejsze opóźnienia samej pamięci L1 (prawdopodobnie jest to kwestia połączenia). Ma to ponoć zapewnić Volcie większą tolerancję na scenariusze, w których programista nie skorzystał z shared memory. Dodatkowo nowa architektura, w przeciwieństwie do poprzedników, obsługuje caching operacji zapisu (wcześniej było to możliwe jedynie w operacjach odczytu).
Sprawdź ranking najpopularniejszych kart graficznych w Polsce.
Drugą istotną cechą struktury Volta SM jest zdolność do symultanicznego wykonania operacji stałoprzecinkowej i zmiennoprzecinkowej pojedynczej precyzji z pełną przepustowością. Stało się to możliwe dzięki wykorzystaniu odrębnych rdzeni FP32 oraz INT32, za czym idzie zwiększona wydajność przetwarzania rozkazów. Zmniejszono przy tym opóźnienie mnożenia akumulacyjnego (Fused multiply-add – FMA) do czterech cykli zegara, z sześciu cykli, charakterystycznych dla architektury Pascal. Rdzenie Tensor pomijam w tym miejscu, bo jakiś czas temu opublikowaliśmy wspomniany już artykuł na ten temat. Prawdopodobnie jednak kiedyś do nich wrócimy.
Nie sposób pominąć za to całego spektrum nowych rozwiązań z pogranicza sprzętowo-programowego. GV100 jest pierwszym w historii procesorem graficznym umożliwiającym planowanie niezależne (ang. independent scheduling) wątków. Pascal i wszyscy jego prekursorzy wykonują instrukcje grupowo po 32 wątki w modelu SIMT (Single Instruction, Multiple Thread). Wątki te mają wspólny licznik programu, połączony z aktywną maską określającą aktywność konkretnych wątków w danym momencie. W rezultacie rozbieżne gałęzie (ścieżki wykonania programu) prowadzą do tego, że część wątków pozostaje nieaktywna aż do momentu ponownego przekształcenia, zwykle na końcu sekcji rozbieżnej. Wszystko doskonale widać na umieszczonym poniżej schemacie, który stanowi graficzną reprezentację towarzyszącego mu pseudokodu instrukcji warunkowej. Voltę wyposażono w niezależne liczniki programu oraz stosy odwołań, co pozwala programiście na dowolne przeplatanie gałęzi, a później ręczne ich połączenie. To w dalszym ciągu SIMT, jednak realizowany w sposób bardziej naturalny z punktu widzenia matematyki.
Bezpośrednio z planowaniem niezależnym łączą się algorytmy niemożliwe do zagłodzenia, czyli takie, które wykonują się równolegle dopóty, dopóki programista unika równoczesnego użycia wspólnego zasobu. Zasadniczo każde zagłodzenie procesu wynika z próby uzyskania dostępu do jednego zasobu – stosuje się wówczas algorytmy wzajemnego wykluczania (ang. mutex). Nvidia zauważa tutaj problem, którym jest możliwość wielokrotnego pozyskiwania i zwalniania muteksów przez pojedynczy wątek, prowadząca do zagłodzenia innego wątku. Zdaniem Nvidii Volta przychodzi tu z odsieczą. Producent ponownie posługuje się przykładem. Tym razem mowa o dopisaniu elementu do listy dwukierunkowej w programie wielowątkowym. Lista tego typu przechowuje w każdym elemencie odniesienie do poprzednika oraz następnika, a w przytoczonym przypadku niezbędne jest jeszcze użycie mechanizmu blokady (ang. lock), zapobiegającego konfliktom w dostępie do zasobów. Dzięki planowaniu niezależnemu Volty jeden wątek może prowadzić blokadę, a drugi wyczekiwać na uwolnienie zasobu, nie przeszkadzając temu pierwszemu i nie ograniczając efektywności przez globalną blokadę gruboziarnistą. Wystarczy podmienić odpowiednie zmienne.
Gdzieś na początku niniejszego artykułu wspominałem o MPS. Temu rozwiązaniu również warto poświęcić kilka słów. Jego nazwa jest akronimem od słów Multi-Process Service. W zamyśle to kolejny krok na drodze do zwiększenia paralelizmu. Według oficjalnej dokumentacji MPS to alternatywna, binarnie zgodna implementacja interfejsu programistycznego CUDA, którą zaprojektowano po to, by jedno GPU mogło prowadzić wiele kerneli CUDA. Rozwiązanie wprowadzono w Keplerze, w którym wiele procesów CPU może zostać połączonych programowo w jeden kontekst dla GPU. Tymczasem Volta realizuje to zadanie na poziomie sprzętowym, zapewniając trzykrotnie większą liczbę klientów MPS (48 zamiast 16), niezależne przestrzenie adresowe i usprawnioną jakość usługi (ang. Quality of Service). Pod tym ostatnim, dość enigmatycznym, pojęciem skrywa się możliwość przydzielenia określonych zasobów obliczeniowych procesora graficznego każdemu z klientów. W przeszłości, kiedy tylko któryś z procesów przekraczał całkowity budżet obliczeniowy GPU, pozostałe klienty musiały wyczekiwać zakończenia pracy „szkodnika”. Obecnie nie ma takiej możliwości.
Nieco abstrahując od kwestii zmian w architekturze samego chipu, warto omówić temat pamięci i jej organizacji. Jak wspomniałem, GV100 ma osiem 512-bitowych kontrolerów HBM2, co pozwala uzyskać, odpowiednio, 4096-bitową magistralę oraz 16 GB pamięci graficznej o imponującej przepustowości 900 GB/s. Użyto czterech stosów marki Samsung, wyposażonych dodatkowo w system kodowania korekcyjnego (ECC) poprzez kod Hamminga z dodatkowym bitem parzystości (SECDED). Ponieważ bity ECC są przechowywane poza jawną pulą pamięci, nie mają żadnego wpływu na przepustowość czy pojemność, jak choćby w przypadku procesora Tesla K40.
Co istotne, w identyczny sposób chronione są wszystkie pozostałe bloki pamięci w GV100: tablica rejestrów, L1 i L2. Ponadto poprawiono system kopiowania, odpowiedzialny za przesyłanie danych pomiędzy kartami graficznymi lub kartą graficzną a procesorem centralnym. W poprzednich generacjach stosowano rozwiązanie na wzór dostępu bezpośredniego (DMA), a to według Nvidii może prowadzić do błędów krytycznych, jeśli adresy pamięci docelowej lub źródłowej nie są odwzorowane w tablicy stron karty graficznej. Podsystem pamięci Volty radzi sobie z błędem braku strony w ten sposób, że mapuje odpowiednie adresy w tablicy, po czym transfer nie stanowi już przeszkody. Całości dopełnia usprawniona unifikacja pamięci (wspólna wirtualna przestrzeń adresowa CPU i GPU). Sprzętowy licznik dostępu śledzi częstotliwość, z jaką GPU odwołuje się do pamięci pozostałych jednostek, co pozwala się upewnić, że dane znajdują się w pamięci tego procesora, który korzysta z nich najczęściej.
Co poza tym? Zwiększono sygnałowanie pojedynczego łącza NVLink z 20 Gb/s do 25 Gb/s, a liczbę łączy – z czterech do sześciu, co dało przepustowość rzędu 300 Gb/s. Dodatkowo nowe łącze NVLink zapewnia pełną koherencję pamięci pomiędzy połączonymi kartami, w tym wzajemną możliwość wykonywania operacji zapisu lub odczytu. Mało tego, GPU może uzyskać bezpośredni dostęp do tablicy stron pamięci procesora centralnego, choć oczywiście tyczy się to jedynie połączenia przez NVLink, a nie PCI Express. Ostatecznie w dokumentacji technicznej zamieszczono wzmianki o konfigurowalnym TDP i rozszerzeniach dla CUDA 9, ponownie z myślą o poprawie zarządzania zasobami przy symultanicznym wykonywaniu instrukcji na wielu wątkach.
Analiza wszystkich wymienionych i opisanych powyżej cech pokazuje jak na dłoni, czym w istocie jest Volta, nawet w formie Titana V. To sprzęt projektowany pod kątem rozwiązań profesjonalnych. Pod tym względem Nvidia zrobiła doskonałą robotę. Rozbicie rdzeni FP32 oraz INT32, wprowadzenie rdzeni Tensor, zunifikowana pamięć podręczna, liczne usprawnienia potoku wykonawczego, lepszy NVLink… Na gruncie konsumenckim lwia część wprowadzonych modyfikacji okazuje się zupełnie nieistotna i tylko zwiększa skomplikowanie układu, a przez to cenę. Dlatego plotki o Ampere mogą nosić znamiona prawdy.
Wprawdzie szklaną kulą nie dysponuję, ale mam swoją teorię. Brzmi ona: wyrzucone zostaną rdzenie FP64, Tensor i wyspecjalizowane INT32, a kontrolery pamięci zostaną wymienione – z HBM2 na GDDR6. Przy zachowaniu dotychczasowych trendów domniemany GA104 alias GeForce GTX 2080 otrzyma cztery klastry GPC, a więc 28 bloków SM, czyli 3584 procesory strumieniowe. Przyspieszone dzięki litografii klasy 12 nm FFN częstotliwości taktowania sprawią, że konstrukcja otwierająca nową linię produktową Nvidii tradycyjnie prześcignie dotychczasowy flagowiec, którym obecnie jest GeForce GTX 1080 Ti (sprawdź najlepsze oferty). Może nawet podgryzie Titana Xp, co będzie dobrym posunięciem z punktu widzenia działu marketingu. A co z Voltą? Cóż, dla większości z nas to i tak w najlepszym razie intrygująca ciekawostka.