2016-01-29 48 views
6

Dlaczego na najniższym poziomie sprzętu wykonującego operacje i związane z nimi podstawowe operacje (tj. Rzeczy ogólne we wszystkich rzeczywistych implementacjach języków programowania podczas uruchamiania kodu), wektoryzacja jest zazwyczaj znacznie szybsza niż zapętlanie?Dlaczego wektoryzacja jest szybsza niż pętle?

Co robi komputer, gdy działa w pętli, ale nie robi tego podczas korzystania z wektoryzacji (mówię o rzeczywistych obliczeniach wykonywanych przez komputer, a nie o tym, co programista pisze), lub co robi inaczej?

Nie potrafiłem się przekonać, dlaczego różnica jest tak znacząca. Prawdopodobnie mógłbym być przekonany, że wektorowy kod zgasił gdzieś jakieś pętle, ale komputer wciąż musi wykonywać tę samą liczbę operacji, prawda? Na przykład, jeśli mnożymy wektor o rozmiarze N przez skalar, będziemy mieli N multiplikacje, które będą działały w obie strony, prawda?

+1

Sprzęt może być równoległy. Możesz xorować dwie 32-bitowe liczby w jednym cyklu. Możesz zapisać xor dwie 1048576 bitów w 1 cyklu. Wystarczy wypalić jeszcze kilka przewodów na chipie. – usr

+0

Dzięki nowoczesnemu SIMD z krótkimi wektorem, wektory używają pętli do przetwarzania całej tablicy. Starsze maszyny wektorowe Cray'a mogły być skonfigurowane do dużych operacji, a następnie jedna instrukcja ładowałaby/działała/zapisywała, ale nie tak działa x86 SSE/ARM NEON/PowerPC AltiVec. –

Odpowiedz

11

Wektoryzacja (tak jak termin jest zwykle używany) odnosi się do operacji SIMD (pojedyncza instrukcja, wiele danych).

Oznacza to w istocie, że jedna instrukcja wykonuje tę samą operację na kilku operandach równolegle. Na przykład, dla wielu wektorów o rozmiarze N przez skalar, nazwijmy M liczbą operandów, których rozmiar może działać jednocześnie. Jeśli tak, to liczba instrukcji, które musi wykonać, to w przybliżeniu N/M, gdzie (z czysto skalarnymi operacjami) musiałby wykonać operacje N.

Na przykład obecny zestaw instrukcji Intel AVX 2 wykorzystuje rejestry 256-bitowe. Mogą one służyć do przechowywania (i obsługi) zestawu 4 operandów po 64 bity lub 8 operandów po 32 bity.

Zakładając, że mamy do czynienia z 32-bitowymi, rzeczywistymi liczbami o pojedynczej precyzji, oznacza to, że pojedyncza instrukcja może jednorazowo wykonać 8 operacji (multiplikacji, w twoim przypadku), więc (przynajmniej teoretycznie) możesz zakończyć multiplikację N przy użyciu tylko instrukcji mnożenia N/8. Przynajmniej teoretycznie powinno to pozwolić na zakończenie operacji około 8 razy szybciej niż pozwala na to wykonanie jednej instrukcji na raz.

Oczywiście, dokładne korzyści zależą od tego, ile operandów obsługuje się na podstawie instrukcji. Pierwsze próby Intela obsługiwały tylko rejestry 64-bitowe, więc aby działać na 8 elementach jednocześnie, te elementy mogły mieć tylko 8 bitów na sztukę. Obecnie obsługują rejestry 256-bitowe i ogłosiły wsparcie dla 512-bitów (a mogły nawet wysłać je w kilku wysokiej klasy procesorach, ale jeszcze nie w zwykłych procesorach konsumenckich). Właściwe wykorzystanie tej możliwości może również być nietrywialne, delikatnie mówiąc. Planuj instrukcje, aby faktycznie mieć N operandów i we właściwych miejscach we właściwym czasie niekoniecznie jest to łatwe zadanie (w ogóle).

Aby spojrzeć na to z innej perspektywy, (starożytna) Cray 1 osiągnęła dużą prędkość właśnie w ten sposób.Jego jednostka wektorowa działała na zestawach 64 rejestrów po 64 bity, więc mogła wykonywać 64 operacji podwójnej precyzji na cykl zegara. Na optymalnie wektoryzowanym kodzie był on znacznie bliższy prędkości aktualnego procesora, niż można by oczekiwać, bazując wyłącznie na jego (znacznie niższej) szybkości zegara. Wykorzystanie tego nie zawsze było jednak łatwe (i nadal nie jest łatwe).

Należy jednak pamiętać, że wektoryzacja to , a nie jedyny sposób, w jaki procesor może wykonywać operacje równolegle. Istnieje również możliwość równoległości poziomu instrukcji, która pozwala pojedynczemu procesorowi (lub jednemu rdzeniu procesora) na wykonanie więcej niż jednej instrukcji naraz. Większość nowoczesnych procesorów zawiera sprzęt (teoretycznie) do wykonania około 4 instrukcji na cykl zegara, jeśli instrukcje są mieszanką obciążeń, zapasów i jednostek ALU. Mogą dość rutynowo wykonywać blisko 2 instrukcje na zegar średnio lub więcej w dobrze dostrojonych pętlach, gdy pamięć nie jest wąskim gardłem.

Oczywiście, istnieje wiele wątków - uruchamianie wielu strumieni instrukcji na (przynajmniej logicznie) oddzielnych procesorach/rdzeniach.

Współczesny procesor może mieć, powiedzmy, 4 rdzenie, z których każdy może wykonać 2 mnożenia wektorów na zegar, a każda z tych instrukcji może działać na 8 operandach. Tak więc, przynajmniej teoretycznie, może wykonywać 4 * 2 * 8 = 64 operacji na zegar.

Niektóre instrukcje mają lepszą lub gorszą przepustowość. Na przykład przepustowość dodawania FP jest niższa niż FMA lub mnożenie na Intelu przed Skylake (1 wektor na zegar zamiast 2). Ale logika logiczna, taka jak ORAZ XOR, ma 3 wektory na przepustowość zegara; nie wymaga wielu tranzystorów do zbudowania jednostki wykonawczej AND/XOR/OR, więc procesory je replikują. Wąskie gardła na całej szerokości rurociągu (front-end, który dekoduje i przechodzi do części rdzeniowej poza kolejnością) są powszechne w przypadku stosowania instrukcji o dużej przepustowości, a nie wąskich gardeł w konkretnej jednostce wykonawczej.

+0

W moim wstępnym kursie systemów komputerowych (oraz w naszym kursie programowania równoległego) traktowaliśmy procesor (lub pojedynczy rdzeń wielordzeniowego procesora) jako system typu czarnej skrzynki, który może TYLKO wykonywać czynności sekwencyjnie; nie można obliczyć jednocześnie żadnych obliczeń. Czy to jest nieprawidłowe? A może rdzeń ma własne pod-procesory, z których każdy może wykonywać proste obliczenia? –

+2

Tak, w odniesieniu do nowoczesnego (rozsądnie zaawansowanego) procesora, który jest nieprawidłowy. Główne jednostki centralne komputerów/serwerów obsługują różne typy równoległości przez dziesięciolecia. Czysto sekwencyjny byłby (na przykład) 486, ale nie był już prawdziwy w stosunku do oryginalnego Pentium. Na komputerach typu mainframe te same rzeczy zdarzały się jeszcze dłużej (np. CDC 6500 miał architekturę podobną do Pentium, a 6600 było podobne do Pentium Pro). Te zostały wydane około 1964 roku. –

+0

Większość nowoczesnych procesorów ma szerokość potoku 4 (Intel od Core2, AMD od Bulldozer). To daje ci 4 instrukcje na zegar, jeśli masz mieszankę ładunków, zapasów i instrukcji jednostrzałowych ALU. (Porównania + instrukcje rozgałęzień mogą się łączyć w 1 uop, więc prawdziwy max IPC Haswell wynosi 6 instrukcji na zegar, ale o wiele bardziej realistyczny, aby powiedzieć po prostu 4). Ryzen's pipeline ma 6 szerokości, ale instrukcje single-uop mogą zawierać tylko 5 zegar. (AVX/AVX2 256b wektory dekodują do 2 uops i mogą ładnie wypełnić fajkę.) Core2 raczej nie wykona 4 IPC poza specjalnie spreparowanymi pętlami, ale jest to realistyczne w SKL. –

1

Wektoryzacja jest rodzajem przetwarzania równoległego. Pozwala na poświęcenie większej ilości sprzętu komputerowego na wykonywanie obliczeń, więc obliczenia wykonywane są szybciej.

Wiele problemów numerycznych, w szczególności rozwiązanie równań różniczkowych cząstkowych, wymaga wykonania tych samych obliczeń dla dużej liczby komórek, elementów lub węzłów. Wektoryzacja wykonuje obliczenia równolegle dla wielu komórek/elementów/węzłów.

Wektoryzacja wykorzystuje specjalny sprzęt. W przeciwieństwie do procesorów wielordzeniowych, dla których każda z jednostek przetwarzania równoległego jest w pełni funkcjonalnym rdzeniem procesora, jednostki przetwarzania wektorowego mogą wykonywać tylko proste operacje, a wszystkie jednostki wykonują tę samą operację w tym samym czasie, operując na sekwencji wartości danych (wektor) jednocześnie.

+0

Więc wektorowy kod ma radykalnie inną implementację? Właściwie po prostu dzieli operacje pomiędzy więcej rdzeni? Jeśli tak, czy to oznacza, że ​​pojedynczy rdzeń procesora nie zauważy żadnych korzyści z wektoryzacji, czy też istnieją "podrzędne" jednostki sprzętowe (z braku lepszego słowa) w każdym rdzeniu, które mogłyby jeszcze przyspieszyć działanie? –

0

Wektoryzacja ma dwie główne zalety.

  1. Podstawową korzyścią jest to, że sprzęt przeznaczony do obsługi instrukcji wektorowych generalnie ma sprzęt, który jest zdolny do wykonywania wielu operacji ALU w ogóle, gdy używane są instrukcje wektorowe. Na przykład, jeśli poprosisz go o wykonanie 16 dodatków za pomocą 16-elementowej instrukcji wektorowej, może mieć 16 równoległych adderów, które mogą wykonać wszystkie dodatki naraz. Jedynym sposobem uzyskania dostępu do wszystkich tych dodatków jest uzyskanie wektoryzacji. Dzięki skalarnym instrukcjom otrzymujesz 1 samotny sumator.

  2. Zwykle zaoszczędzono trochę czasu, stosując instrukcje wektorowe. Ładujesz i przechowujesz dane w dużych porcjach (do 512 bitów na raz na niektórych najnowszych procesorach Intela) i każda iteracja pętli wykonuje więcej pracy, więc ogólne obciążenie pętli jest ogólnie niższe w znaczeniu względnym: , a potrzebujesz mniej instrukcji do wykonać tę samą pracę tak napowietrznej CPU front-end jest niższa, itp

Wreszcie, dychotomia między pętle i wektoryzacji jest nieparzysta. Kiedy przyjmujesz kod inny niż wektorowy i wektoryzujesz go, zwykle kończysz z pętlą, jeśli wcześniej była tam pętla lub nie, jeśli nie było. Porównanie jest naprawdę pomiędzy skalarnymi (nie wektorem) instrukcjami i instrukcjami wektorowymi.


Albo przynajmniej 15 z 16, być może jeden służy również do zrobienia operacji skalarnych.

Prawdopodobnie można uzyskać podobną korzyść z pętli w przypadku skalarnego, kosztem długiego rozwijania pętli.