Architektura Systemów Komputerowych Wykład 10: Redukcja opóźnień w procesorach superpotokowych i superskalarnych Dr inż. Marek Mika Państwowa Wyższa Szkoła Zawodowa im. Jana Amosa Komeńskiego W Lesznie
Plan Opóźnienia w architekturach superpotokowych i superskalarnych Redukcja opóźnień skoków Redukcja opóźnień danych
Opóźnienia w procesorach superpotokowvch i superskaiarnych Duża liczba stopni potoków powoduje znaczące opóźnienia Opóźnienie wyraża się proporcjonalnym spadkiem wydajności w porównaniu z idealnym wykonaniem programu bez opóźnień w architekturach jednopotokowch bierze się pod uwagę liczbę straconych cykli procesora, która jest równa liczbie utraconych instrukcji w architekturach wielopotokowych liczbę straconych cykli należy pomnożyć przez liczbę potoków
Opóźnienia skoków Ze statystyki wynika, że skoki stanowią od 7 do 14 % wszystkich wykonywanych instrukcji dla dalszych rozważań przyjmiemy, że skoki stanowią 10% instrukcji W bardziej złożonych architekturach opóźnienia skoków paraliżują działanie procesora niezbędne są mechanizmy umożliwiające znaczącą redukcję opóźnień Architektura Liczba utraconych instrukcji Spadek wydajności MIPS R3000 1 10 % MIPS R4000 2 20 % Intel Pentium ok. 6 40 % Intel Pentium Pro / II / III ok. 30 75 % AMD K8 ok. 36 78 % Intel Pentium 4 / Core ok. 45 82 %
Spekulatywne wykonanie instrukcji Współczesne procesory są wyposażone w mechanizmy spekulatywnego wykonania instrukcji instrukcja jest wykonywana na podstawie przewidywania, że powinna być wykonana (np. po instrukcji skoku) w przypadku błędnego przewidywania następuje anulowanie instrukcji i wszelkich efektów jej wykonania procesory umożliwiają wielopoziomową spekulację wykonanie instrukcji po kilku nierozstrzygniętych skokach Jeśli w procesorze przebywa równocześnie 100 instrukcji, to wśród nich jest 10 skoków oznacza to, że niemal przez cały czas wykonanie instrukcji ma charakter spekulatywny bez spekulacji wydajność byłaby ok 10-krotnie mniejsza
Terminologia Wykonanie skoku wykonanie instrukcji skoku, które może, ale nie musi, powodować zmianę wartości PC Realizacja skoku zmiana zawartości PC Skok warunkowy przy niespełnionym warunku zostaje wykonany, ale nie zrealizowany Adres skoku: statyczny zawarty w instrukcji w postaci stałej dynamiczny zmienna wartość w rejestrze lub pamięci (w tym na stosie powroty z procedur) Skoki z adresem statycznym: względne w obrazie instrukcji jest zapamiętane przemieszczenie względem PC jako liczba ze znakiem (U2) bezwzględne w obrazie instrukcji jest zapamiętany adres docelowy, ładowany do PC
Przewidywanie skoków zasady Przewidywanie skoków polega na przewidzeniu wykonania instrukcji skoku przed faktycznym jej wykonaniem Po przewidzeniu skoku procesor spekulatywnie wykonuje instrukcje po skoku (zrealizowanym lub niezrealizowanym) Rzeczywiste wykonanie instrukcji skoku umożliwia sprawdzenie poprawności przewidywania Jeśli przewidywanie było poprawne: skok został wykonany bez opóźnień lub ze zmniejszonym opóźnieniem instrukcje wykonane spekulatywnie mogą zostać zatwierdzone Jeśli przewidywanie było błędne: instrukcje wykonane spekulatywnie są anulowane, a czas przeznaczony na ich wykonanie jest czasem opóźnienia skoku następuje wykonanie właściwego strumienia instrukcji
Przewidywanie skoków aspekty Przewidywanie wystąpienia instrukcji skoku w strumieniu instrukcji Przewidywanie adresu docelowego skoku Przewidywanie sposobu wykonania skoku warunkowego (zrealizowany / niezrealizowany)
Możliwości przewidywania skoków Aby wykonać skok, procesor musi: wiedzieć, że występuje instrukcja skoku znać adres docelowy znać warunek wykonania dla skoków warunkowych Możliwość wykonania bez spekulacji: skoki statyczne bezwarunkowe natychmiast po stwierdzeniu wystąpienia instrukcji skoku skoki statyczne warunkowe po wyznaczeniu warunku adres docelowy znany bezpośrednio po zdekodowaniu skoki dynamiczne po wyznaczeniu adresu docelowego Przewidywanie może obejmować: dla wszystkich skoków wystąpienie skoku, adres docelowy skoku dla skoków warunkowych dodatkowo sposób wykonania
Przewidywanie statyczne i dynamiczne Statyczne zachodzi po zdekodowaniu instrukcji skoku, nie wymaga gromadzenia wiedzy o historii wykonania programu przewidywanie realizacji skoku warunkowego Dynamiczne na podstawie wiedzy o historii wykonania programu przewidywanie wystąpienia instrukcji skoku przed jej pobraniem przewidywanie adresu docelowego skoków statycznych i dynamicznych przewidywanie realizacji skoku warunkowego
Statyczne przewidywanie realizacji skoku Przewidywanie przez kompilator lub programistę kompilator języka wysokiego poziomu lub programista piszący program w asemblerze zna prawdopodobieństwo wykonania skoku warunkowego informacja ta może zostać umieszczona w programie o ile model programowy uwzględni dwa warianty skoków warunkowych skoki prawdopodobne skoki nieprawdopodobne przykłady: Alpha AXP, Intel Pentium 4 Przewidywanie przez procesor z analizy własności programów wynika, że ponad 60% skoków warunkowych w tył jest realizowanych, a skoków w przód nierealizowanych skoki warunkowe są zapisywane jako względne bit znaku przemieszczenia może zostać użyty przez procesor jako znacznik prawdopodobieństwa skoku
Dynamiczne przewidywanie wystąpienia skoku Wymaga wprowadzenia do struktury procesora dodatkowych bloków sprzętowych, gromadzących informację o historii wykonania programu Bufor docelowy skoków (BTB Branch Target Buffer) gromadzi informację o pewnej liczbie ostatnio wykonywanych skoków działa na zasadzie podobnej do pamięci podręcznej często realizowany w powiązaniu z pamięcią podręczną kodu Przy każdej realizacji skoku adres, pod którym jest położona instrukcja skoku jest odnotowywany w BTB na ogół razem z adresem docelowym skoku Przy każdym pobraniu instrukcji stopień pobrania sprawdza, czy adres pobrania został wcześniej zanotowany jako adres instrukcji skoku jeśli tak stopień pobrania może w następnym cyklu wykonać skok
Bufor docelowy działanie Przy wykonaniu skoku do adresu Y położonego pod adresem X w buforze docelowym zostaje zapamiętana para X,Y Równocześnie z pobraniem każdej instrukcji następuje przeszukanie bufora z wartością scanpc jako kluczem Jeśli w buforze znajduje się wartość X = scanpc, to na końcu cyklu następuje załadowanie Y do scanpc w następnym cyklu stopień pobrania pobierze instrukcję spod przewidywanego adresu docelowego skoku Opisany schemat działa poprawnie jeżeli: pod adresem X nadal znajduje się ta sama instrukcja skoku adres docelowy skoku pozostaje niezmienny warunek wykonania (dla skoku warunkowego) ma tę samą wartość Przy udanym przewidywaniu skok wykonuje się bez opóźnień
Bufor docelowy - ograniczenia Bufor docelowy w podstawowej formie nie może przewidywać: skoków dynamicznych skoków warunkowych przy różnych wartościach warunku w kolejnych wykonaniach Zastosowanie skoków dynamicznych: powroty z procedur bardzo częste, niezbędne wskaźniki na funkcje, w tym metody wirtualne zależne od przyjętego stylu programowania jedna z możliwych realizacji konstrukcji typu switch - zależne od kompilatora Skoki dynamiczne mogą być przewidywane w buforze docelowym jako statyczne działa to dość dobrze dla wskaźników na funkcje Potrzebny inny mechanizm przewidywania powrotów z procedur
Przewidywanie adresów powrotów z procedur Szczególnie potrzebne w procesorach CISC odczyt śladu ze stosu jest czasochłonny Założenie: adres powrotu jest ostatnim zapamiętanym śladem implikuje to wymaganie, że każdej instrukcji skoku ze śladem odpowiada instrukcja powrotu przewidywanie adresu powrotu nie działa dla par: PUSH-RET CALL-POP
Sprzętowy stos powrotów Niewielki, niewidoczny programowo stos (bufor LIFO), umieszczony w procesorze pojemność: 8 16 elementów Wykonanie instrukcji skoku ze śladem powoduje umieszczenie na stosie powrotów wartości śladu dzieje się to niezależnie od przesłania śladu na stos w pamięci (CISC) lub do rejestru (RISC) Napotkanie instrukcji powrotu powoduje zdjęcie śladu ze stosu przy przewidywaniu dynamicznym akcja ta jest inicjowana przez BTB przy pobraniu instrukcji powrót nie wnosi żadnych opóźnień przy przewidywaniu statycznym spekulatywny powrót następuje po zdekodowaniu instrukcji powrotu Wykonanie instrukcji powrotu weryfikuje poprawność spekulacji jeśli adres ze stosu sprzętowego jest różny od adresu powrotu następuje anulowanie całego ciągu instrukcji
Efektywność sprzętowego stosu powrotów Stos powrotów działa skutecznie dla fragmentów programu, w których zagłębianie procedur nie przekracza pojemności stosu Każda niesparowana instrukcja CALL lub RETURN powoduje desynchronizację stosu wszystkie następne powroty będą przewidywane błędnie, aż do zapełnienia całego stosu nowymi śladami
Dynamiczne przewidywanie realizacji skoku Sam bufor docelowy przewiduje skoki warunkowe jako bezwarunkowe skok niezrealizowany po zrealizowanym jest przewidziany błędnie Lepsze przewidywanie realizacji skoków wymaga implementacji predyktora, decydującego o tym, czy procesor ma traktować skok jako realizowany czy nierealizowany Skróty i konwencje: T (Taken) skok realizowany NT (Not Taken) skok nierealizowany PT (Predict Taken) skok przewidywany jako realizowany (na grafach kolor zielony) PNT (Predict Not Taken) skok przewidywany jako nierealizowany (na grafach kolor czerwony)
Dynamiczne predyktory realizacji skoku Automaty decydujące o sposobie spekulatywnego wykonania przewidywanego skoku warunkowego na podstawie historii wykonania programu Działanie predyktorów deterministyczne wykonanie (rozstrzygnięcie skoku) przez procesor powoduje modyfikację stanu predyktora spekulatywne wykonanie skoku na podstawie stanu predyktora Klasyfikacja predyktorów wg. konstrukcji elementarnego automatu predyktora dwustanowe Czterostanowe wg. sposobu wiązania instrukcji skoku z automatem predyktora jednopoziomowe prawdopodobieństwo bezwarunkowe dwupoziomowe prawdopodobieństwo warunkowe trójpoziomowe - prawdopodobieństwo warunkowe z adaptacją schematu przewidywania
Predyktor dwustanowy budowa T T Stany: T, NT T Predyktor przydzielany do instrukcji skoku z chwilą pierwszej realizacji NT NT T Kolejne przewidywanie skoku jest takie samo, jak było ostatnie wykonanie NT
Predyktor dwustanowy - charakterystyka for (j=0; j<jmax; j++) { // przed pierwszą iteracją // NT -> zmiana na T for (i=0; i<imax; i++) { if (i % 2) // zawsze błąd {... } else {... } } // po ostatniej iteracji // T -> zamiana na NT } Błędne przewidywanie skoku zamykającego pętlę zagnieżdżoną przy pierwszym i ostatnim wykonaniu istotne przy pętlach iterowanych niewielką liczbę razy Błędne przewidywanie po każdym odstępstwie od typowego wykonania 100% błędne przewidywanie skoków realizowanych co drugi raz
Predyktor czterostanowy T T Stany: ST ST Strongly Taken NT T WT Weakly Taken WNT Weakly Not Taken SNT Strongly Not Taken NT NT WT WNT T T Pierwsza realizacja skoku wprowadza predyktor w stan ST Zmiana przewidywania następuje po dwóch kolejnych takich samych wykonaniach SNT NT
Predyktor czterostanowy - charakterystyka for (j=0; j<jmax; j++) { // przed pierwszą iteracją // WT -> zmiana na ST for (i=0; i<imax; i++) { if (i % 1) // błąd co drugie wykonanie {... } else {... } } // po ostatniej iteracji // ST -> zamiana na WT } Błędne przewidywanie skoku zamykającego pętlę zagnieżdżoną przy ostatnim wykonaniu istotne przy pętlach iterowanych niewielką liczbę razy Błędne przewidywanie po każdym jednokrotnym odstępstwie od typowego wykonania Skoki realizowane co drugi raz przewidywanie poprawne w 50%
Ograniczenia predyktorów jednopoziomowych Brak możliwości trafnego przewidzenia wszystkich iteracji skoku zamykającego pętlę szczególnie istotne przy pętlach iterowanych niewielką liczbę razy, często spotykanych w oprogramowaniu Brak możliwości trafnego przewidzenia skoków wykonywanych cyklicznie np. dwa razy realizowany, następnie dwa razy nierealizowany
Predyktory dwupoziomowe Przechowują informację o prawdopodobieństwie warunkowym jak wykona się skok, jeśli ostatnio raz był zrealizowany i trzy razy niezrealizowany Predyktor elementarny nie jest bezpośrednio związany z instrukcją skoku wybór predyktora zachodzi na podstawie adresu instrukcji skoku i historii wykonań Rejestr historii: rejestr przesuwający o długości 8 16 bitów, zawierający historię wykonań (T/NT) dla ostatnich wykonań pojedynczego lub wielu skoków Predyktory dwupoziomowe i trójpoziomowe nazywane korelatorami skoków
Predyktor dwupoziomowy glocal Adres instrukcji skoku Tablica rejestrów historii Tablica predyktorów T/NT #
Predyktor dwupoziomowy gshare Adres instrukcji skoku Globalny rejestr historii Tablica predyktorów T/NT #
Predyktory dwupoziomowe - własności Powolne,,uczenie się predyktora trafne przewidywanie wymaga często wielu tysięcy wykonań skoku Możliwość poprawnego przewidywania sekwencji wykonań o długości równej co najmniej długości rejestru historii w tym możliwość poprawnego przewidywania zamknięć pętli iterowanych np. 8 razy Niewrażliwość na pojedyncze nieregularności wykonania Trafność przewidywania typowo około 95% lub więcej Predyktor glocal lepiej przewiduje pętle iterowane niewielką liczbę razy Predyktor gshare lepiej przewiduje rozejścia zależne od wartości danych o ile kilka kolejnych rozejść jest ze sobą powiązanych
Predyktory trójpoziomowe Predyktor trójpoziomowy jest hybrydą dwóch predyktorów, zwykle glocal i gshare Dwa schematy przewidywania dla każdego skoku, z możliwością wyboru schematu zmiana wyboru schematu dla danego skoku zachodzi, gdy dotychczas wybrany schemat przewidział skok błędnie, a alternatywny schemat poprawnie Trafność przewidywania typowo powyżej 96%
Redukcja opóźnień pobierania danych z pamięci W architekturach superskalarnych samo rozsunięcie instrukcji ładującej daną i instrukcji korzystającej z danej nie maskuje opóźnienia Niezbędne pobieranie danych z pamięci operacyjnej do pamięci podręcznej lub buforów na zapas (Data Prefetch) Realizacje: pobieranie inicjowane przez oprogramowanie automatyczne (spekulatywne) pobieranie przez procesor
Pamięć podręczna a wydajność Automatyczne umieszczenie danych w pamięci podręcznej nie zawsze przyspiesza wykonanie programu Przykład program przetwarzający dużą tablicę T1 przy użyciu danych z mniejszej tablicyt2 T2 mieści się w pamięci podręcznej L1 T1 mieści się w pamięci podręcznej L2, nie mieści się w pamięci podręcznej L1 odwołania do T1 powodują usuwanie elementów T2 z pamięci podręcznej L1 efektywny współczynnik trafień L1 wynosi 0 Rozwiązanie: buforować T1 tylko w pamięci podręcznej L2, a T2 - również w L1 szybki dostęp do T1(100% trafień w L1) wolniejszy dostęp tylko do T1 (w L2) Potrzebna jest możliwość sterowania buforowaniem danych z poziomu aplikacji wymaga to ujawnienia obecności pamięci podręcznej w modelu programowym program powinien brać pod uwagę konfigurację komputera, na którym działa
Instrukcje pobierania danych Instrukcje nie mają skutku w modelu programowym nie modyfikują kontekstu procesora Implementacja opcjonalna prostsze procesory mogą je wykonywać jako puste Instrukcje mają charakter sugestii (podpowiedzi), umożliwiających optymalizację działania procesora Jeden argument adres pamięci Wykonanie instrukcji polega na przesłaniu danych z pamięci operacyjnej do pamięci podręcznej lub bufora, ew. zmianie stanu linii pamięci podręcznej instrukcja pobrania do zapisu tylko alokuje linie w pamięci podręcznej, które mają być całkowicie zapełnione nowym danymi bez późniejszego zapisu danych ich wartość będzie nieokreślona! Czas i sposób wykonania mogą zależeć od bieżącego obciążenia interfejsu pamięci operacyjnej i pamięci podręcznej
Instrukcje PREFETCH x86 PREFETCHNTA pobranie danych z pominięciem pamięci podręcznej (do niewidocznego bufora danych w procesorze) dane będą użyte jednorazowo i nie powinny powodować usunięcia innych obiektów z pamięci podręcznej PREFETCHT0 pobranie danych do pamięci podręcznej poziomu 1 i ew. innych poziomów PREFETCHT1 pobranie danych do pamięci podręcznej poziomu 2 i ew. następnych dane nie mieszczą się w L1 i nie powinny jej zajmować PREFETCHT2 pobranie danych do pamięci podręcznej poziomu 3 i ew. następnych dane nie mieszczą się w L2 i nie powinny jej zajmować
Automatyczne pobieranie danych przez procesor Odpowiedni moduł sprzętowy wykrywa wzorce odwołań do pamięci realizowanych przez program Na podstawie rozpoznanego wzorca procesor samoczynnie wykonuje operację pobierania danych analogiczną do inicjowanej przez instrukcję PREFETCH Mechanizm zaimplementowany m.in. w procesorach Intel serii Pentium 4 i Core
DZIĘKUJĘ ZA UWAGĘ!