Programowanie w asemblerze Architektury równoległe 24 listopada 2015 1 1 Ilustracje: Song Ho Anh
Klasyfikacja Flynna Duża różnorodność architektur równoległych, stad różne kryteria podziału. Najstarsza klasyfikacja Flynna używała pojęć strumienia instrukcji i strumienia danych. SISD (Single Instruction Single Data) to klasyczny system jednoprocesorowy z pojedynczym,i strumieniami instrukcji i danych. Jeśli zwielokrotnimy strumienie danych, to otrzymamy system SIMD (Single Instruction Multiple Data), w którym wiele procesorów wykonywało równocześnie tę sama instrukcję na różnych danych. Przyśpiesza to wykonywanie typowych operacji macierzowych, takich jak mnożenie czy odwracanie. Tak pracowały procesory wektorowe (np. Cray-1) i macierzowe.
Klasyfikacje Flynna Zwielokratniajac strumień instrukcji otrzymujemy system MISD (Multiple Instruction Single Data), spotykany jedynie w bardzo specyficznych zastosowaniach (np. przetwarzanie lustrzane). Przy zwielokrotnieniu obu strumieni otrzymujemy system MIMD (Multiple Instruction Multiple Data), z pełna współbieżnościa możliwościa niezależnego przetwarzania różnych danych przez poszczególne procesory.
Podział według metod synchronizacji synchroniczne, np. SIMD; asynchroniczne, np. MIMD.
MMX Pierwsze podejście do strumieni instrukcji. Pasożytuje na FPU używa tych samych rejestrów. Pierwsze instrukcje 64-bitowe, np. movq mm0,[tablica] pozwalajace przesłać wektor wartości do rejestru MMX. Dostępne także w SSE.
Wykrywanie technologii SSE Przed użyciem zaawansowanych instrukcji trzeba sprawdzić, czy procesor ja obsługuje. W naszej pracowni sa różne procesory! Do sprawdzania służy instrukcja cpuid.
CPUID Instrukcja CPUID zwraca informacje o procesorze. Podobne informacje w Linuksie przez cat /proc/cpuinfo Aby sprawdzić, czy procesor reaguje na CPUID, należy spróbować, czy da się zmodyfikować bit 21 w słowie stanu procesora (EFLAGS) pushfd ;wyjmujemy flagi pop eax mov ecx,eax ;zachowanie flag xor eax,200000h ;zmiana bitu 21 push eax ;z powrotem popfd pushfd ;jeszcze raz pobieramy pop eax cmp eax,ecx je niema
CPUID Użycie CPUID (gdy jest) mov eax,funkcja cpuid Dla funkcji 0 dostajemy w EAX maks. numer funkcji (co najmniej 0 ;-) w EBX ECX EDX nazwa procesora, np. Genuine Intel
CPUID Dla funkcji 1 dostajemy w EDX bit 0: czy jest FPU bit 11: czy działa SYSCALL/SYSRET bit 15: czy jest CMOV bit 23: czy jest MMX bit 25: czy jest SSE bit 26: czy jest SSE2 a w ECX bit 0: czy jest SSE3
CPUID Dla funkcji 4 dostajemy w EAX bity 26..31: liczba procesorów (cores) Reszta (dużo większa) w dokumentacji.
Rejestry XMM Używane w zbiorze instrukcji SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, SSE5, Advanced Vector Extensions W trybie 32-bitowym 8 rejestrów 128-bitowych XMM0 XMM7 W trybie 64-bitowym 16 rejestrów 128-bitowych XMM0 XMM15
Rejestry XMM Przechowuja wektor 16 wartości 8-bitowych całkowitych wektor 8 wartości 16-bitowych całkowitych wektor 4 wartości 32-bitowych całkowitych lub zmiennoprzecinkowych wektor 2 wartości 64-bitowych całkowitych lub zmiennoprzecinkowych
Przesłania Instrukcje arytmetyczne operuja tylko na wyrównanych do 16 bajtów adresach w pamięci. Dwa rodzaje przesłań do/z rejestrów: MOVDQU jeśli adres nie jest wyrównany (Unaligned) MOVDQA jeśli adres jest wyrównany (Aligned) Zerowanie rejestru pxor xmm1,xmm1
Dodawanie Dla wektorów całkowitych już w MMX SSE dodaje operacje dla wektorków liczb rzeczywistych pojedynczej precyzji (Single), np. ADDPS (gdzie P jest od Packed) W SSE2 rozszerzone na liczby podwójnej precyzji (Double), np. ADDPD. Dodano też operacje dla pojedynczych wartości, tzw. skalarów (Scalar), np. ADDSS i ADDSD.
Dodawanie: przykład Załóżmy, że mamy dodać dwa wektory trójwymiarowe, reprezentowane w pojedynczej precyzji. Musza one być reprezentowane na 128 bitach, więc przyjmijmy, że górna wartość jest wyzerowana. movups xmm0,[eax] movups xmm1,[ebx] addps xmm0,xmm1 movups [edx],xmm0
Mnożenie Podobnie jak dodawanie: MULPS/MULPD dla wektorów, MULPSS/MULSD dla skalarow
Operacje skalar/wektor Przed dodaniem do wektora należy skalar zreplikować, żeby wygladał jak wektor Najprościej będzie, gdy użyjemy operacji tasowania : shufps xmm1,xmm2,maska Operacja ta w pierwszym argumencie rozrzuca dwie kopie skalara z pierwszego argumentu i dwie kopie z drugiego. O wyborze skalarów decyduje maska 8-bitowa.
Tasowanie
Dodawanie skalara do wektora Przy tasowaniu pierwszy argument może być taki sam jak drugi. movss xmm0,fscalar shufps xmm0,xmmo,00000000b addps xmm0,xmm1
Porównania Operacje porównywania w SSE nie ustawiaja flag (nie ma tylu flag). W pierwszym argumencie umieszczana jest prawda (same jedynki) albo fałsz (same zera) oczywiście osobno dla każdego elementu. Tak więc operacja porównywania jest destrukcyjna! cmpd xmm0,xmm1 ;wynik w xmm0 movmskpd eax,xmm0 cmp eax,0 jne tam Uwaga: dla skalarów instrukcje COMISD i UCOMISD bezpośrednio zmieniaja EFLAGS, więc po nich zwykły skok warunkowy.
Porównania
SSE3 Zawiera zbiór skalarnych operacji na liczbach zmiennopozycyjnych pojedynczej i podwójnej precyzji trzymanych w dolnych częściach rejestrów XMM. Operacje zmiennopozycyjne typu rejestr-rejestr (a nie stosowe), np. GCC używa FPU już tylko w rzadkich, specjalnych przypadkach. Stałe zmiennopozycyjne musza być pobierane z pamięci, nie można ich umieszczać bezpośrednio w instrukcjach. Przy porównywaniu liczb zmiennopozycyjnych cztery wyniki (także w C): <, =, > oraz żadna z tych możliwości (gdy któraś z liczb to NaN).
SSE3 Wprowadzono bardzo ciekawe instrukcje dodawania horyzontalnego HADDPS/HADDPD, dodajac a sasiaduj ace pary liczb w argumentach i zapisujac a wynik w pierwszym argumencie. Użyjemy jej do policzenia iloczynu skalarnego naszych wektorów movups xmm0,[eax] ;Pierwszy wektor movups xmm1,[ebx] ;Drugi wektor mulps xmm0,xmm1 ;Iloczyny haddps xmm0,xmm0 ;Półsumy haddps xmm0,xmm0 movss [edx],xmm0