Wygląda na to, że chcesz sposobu, aby ocenić, jak twój kod jest związany z FPU lub jak efektywnie używasz FPU, zamiast liczyć liczbę flopów zgodnie z tą samą anachroniczną definicją „flop”. Innymi słowy, potrzebujesz metryki, która osiąga ten sam szczyt, jeśli każda jednostka zmiennoprzecinkowa pracuje z pełną wydajnością w każdym cyklu. Spójrzmy na Intel Sandy Bridge, aby zobaczyć, jak może się to potrząsnąć.
Obsługiwane sprzętowo operacje zmiennoprzecinkowe
Ten układ obsługuje instrukcje AVX , więc rejestry mają długość 32 bajtów (mieszcząc 4 podwójne). Architektura superskalarna pozwala na nakładanie się instrukcji, przy czym większość instrukcji arytmetycznych zajmuje kilka cykli, nawet jeśli nowa instrukcja może zacząć od następnego cyklu. Te semantyki są zwykle skracane przez zapisanie opóźnienia / odwrotnej przepustowości, wartość 5/2 oznaczałaby, że wykonanie instrukcji zajmuje 5 cykli, ale możesz rozpocząć nową instrukcję co drugi cykl (zakładając, że operandy są dostępne, więc nie ma danych zależność i nie czekanie na pamięć).
Istnieją trzy zmiennoprzecinkowe jednostki arytmetyczne na rdzeń, ale trzecia nie jest istotna w naszej dyskusji, nazwiemy odpowiednie dwie jednostki A i M, ponieważ ich podstawowymi funkcjami są dodawanie i mnożenie. Przykładowe instrukcje (patrz tabele Agner Fog )
vaddpd
: dodatek zapakowany, jednostka zajmująca A na 1 cykl, opóźnienie / odwrotność wynosi 3/1
vmulpd
: mnożenie upakowane, jednostka M, 5/1
vmaxpd
: pakowane wybierz maksimum parami, jednostka A, 3/1
vdivpd
: dzielenie upakowane, jednostka M (i część A), od 21/20 do 45/44 w zależności od danych wejściowych
vsqrtpd
: upakowany pierwiastek kwadratowy, niektóre A i M, 21/21 do 43/43 w zależności od danych wejściowych
vrsqrtps
: upakowany pierwiastek odwrotny o niskiej dokładności dla pojedynczej precyzji wprowadzania (8 floats
)
Precyzyjna semantyka tego, co może się pokrywać vdivpd
i vsqrtpd
jest najwyraźniej subtelna i AFAIK, nigdzie nie udokumentowana. W większości zastosowań myślę, że istnieje niewielka możliwość nakładania się, chociaż sformułowanie w instrukcji sugeruje, że wiele wątków może zaoferować więcej możliwości nakładania się w tej instrukcji. Możemy uderzyć w szczytowe klapy, jeśli zaczniemy a vaddpd
i vmulpd
w każdym cyklu, w sumie 8 klapek na cykl. Gęsta matryca-macierz ( dgemm
) może zbliżyć się do tego piku.
Licząc klapy dla specjalnych instrukcji, spojrzałbym na to, ile FPU jest zajęte. Załóżmy dla argumentu, że w twoim zakresie danych wejściowych vdivpd
zajęło średnio 24 cykle, w pełni zajmując jednostkę M, ale dodawanie mogło (jeśli było dostępne) być wykonywane jednocześnie dla połowy cykli. FPU jest w stanie wykonać 24 spakowanych mnożników i 24 spakowanych dodatków podczas tych cykli (idealnie przeplecione vaddpd
i vmulpd
), ale przy vdivpd
najlepszym, co możemy zrobić, to 12 dodatkowych spakowanych dodatków. Jeśli przypuszczamy, że najlepszym możliwym sposobem podziału jest użycie sprzętu (rozsądne), możemy liczyć vdivpd
jako 36 spakowanych „klap”, co oznacza, że powinniśmy liczyć każdy podział skalarny jako 36 „klap”.
Dzięki odwrotnemu pierwiastkowi kwadratowemu czasami można pokonać sprzęt, szczególnie jeśli pełna dokładność nie jest potrzebna lub gdy zakres danych wejściowych jest wąski. Jak wspomniano powyżej, vrsqrtps
instrukcja jest bardzo tania, więc (jeśli z pojedynczą precyzją) możesz wykonać jedną, vrsqrtps
a następnie jedną lub dwie iteracje Newtona, aby wyczyścić. Te iteracje Newtona są słuszne
y *= (3 - x*y*y)*0.5;
Jeśli trzeba wykonać wiele z tych operacji, może to być znacznie szybsze niż naiwna ocena y = 1/sqrt(x)
. Przed udostępnieniem sprzętowego przybliżonego pierwiastka kwadratowego niektóre wrażliwe na wydajność kody wykorzystywały niesławne operacje na liczbach całkowitych w celu znalezienia wstępnego odgadnięcia iteracji Newtona.
Dostarczone przez bibliotekę funkcje matematyczne
Możemy zastosować podobną heurystykę do funkcji matematycznych udostępnianych przez bibliotekę. Możesz profilować, aby określić liczbę instrukcji SSE, ale jak już omówiliśmy, to nie jest cała historia, a program, który spędza cały czas na ocenie funkcji specjalnych, może nie wydawać się zbliżać do szczytu, co może być prawdą, ale nie przydaje się, aby powiedzieć, że cały czas spędzasz poza kontrolą FPU.
Sugeruję użycie dobrej biblioteki matematyki wektorowej jako podstawy (np. VML Intela, część MKL). Zmierz liczbę cykli dla każdego połączenia i pomnóż przez szczytowe osiągalne klapy przez tę liczbę cykli. Jeśli więc upakowana wykładnicza wartość trwa 50 cykli, policz ją jako 100 klap razy szerokość rejestru. Niestety, biblioteki matematyki wektorowej są czasami trudne do wywołania i nie mają wszystkich specjalnych funkcji, więc możesz skończyć na matematyce skalarnej, w którym to przypadku policzysz naszą hipotetyczną wykładniczą skalarną jako 100 flopów (nawet jeśli prawdopodobnie nadal zajmuje 50 cykli, więc otrzymasz tylko 25% „szczytu”, jeśli cały czas poświęcasz na ocenę tych wykładniczych).
Jak wspomnieli inni, można liczyć cykle i sprzętowe liczniki zdarzeń za pomocą PAPI lub różnych interfejsów. W celu prostego liczenia cykli można bezpośrednio odczytywać licznik cykli, korzystając z rdtsc
instrukcji z fragmentem zestawu wbudowanego.