Opóźnienie instrukcji procesora w procesorach x86 i x64

14

Szukam tabeli lub czegoś podobnego, który mógłby mi pomóc obliczyć wydajność kodu asemblera.

Jak wiem przesunięcie bitów wymaga 1 zegara procesora, ale naprawdę patrzę, ile kosztuje dodanie (odejmowanie powinno zająć to samo), mnożenie i jak przypuszczalnie obliczyć czas podziału, jeśli znam wartości, które dzielą.

Naprawdę potrzebuję informacji o wartościach całkowitych, ale mile widziane są również czasy wykonania zmiennoprzecinkowego.

ST3
źródło
Możliwe to samo na SO: stackoverflow.com/questions/692718/...
Ciro Santilli 法轮功 病毒 审查 六四 事件 法轮功

Odpowiedzi:

10

Zasadniczo każda z tych operacji wymaga wykonania jednego cyklu zegara, jeśli argumenty znajdują się w rejestrach na różnych etapach potoku.

Co masz na myśli przez opóźnienie? Ile cykli operacji w ALU?

Ta tabela może być przydatna: http://www.agner.org/optimize/instruction_tables.pdf

Ponieważ współczesne procesory są super skalarne i mogą być wykonywane poza kolejnością, często można uzyskać całkowitą liczbę instrukcji na cykl przekraczającą 1. Argumenty makropolecenia są najważniejsze, ale operacja ma również znaczenie, ponieważ dzielenie trwa dłużej niż XOR (<1 opóźnienie cyklu).

Wiele instrukcji x86 może zająć wiele cykli, aby ukończyć niektóre etapy, jeśli są złożone (na przykład polecenia REP lub gorszy MWAIT).

Jon Brauer
źródło
3
Mnożenie liczb całkowitych to opóźnienie co najmniej 3c na wszystkich najnowszych procesorach x86 (i wyższe na niektórych starszych procesorach). Na wielu procesorach jest w pełni potokowy, więc przepustowość wynosi 1 na zegar, ale możesz to osiągnąć tylko wtedy, gdy masz trzy niezależne mnożniki w locie. (Pomnożenie FP na Haswell ma opóźnienie 5c, przepustowość 0,5c, więc potrzebujesz 10 w locie, aby nasycić przepustowość). Podział ( divi idiv) jest jeszcze gorszy: jest mikrokodowany i ma znacznie większe opóźnienia niż addlub shr, a nawet nie jest w pełni potokowany na żadnym procesorze. Wszystko to pochodzi bezpośrednio z tabel instrukcji Agner Fog, więc dobrze, że to połączyłeś.
Peter Cordes,
7

Obliczanie wydajności kodu asemblera nie jest najlepszym sposobem, aby przejść w dzisiejszych czasach potoku Super Scalar poza wykonaniem. Będzie się różnić w zależności od typu procesora. Będzie się różnić w zależności od instrukcji zarówno przed jak i po (możesz dodać dodatkowy kod i czasami uruchamiać go szybciej!). Niektóre operacje (zwłaszcza podział) mogą mieć zakres czasów wykonania nawet na starszych, bardziej przewidywalnych układach. W rzeczywistości jedynym sposobem jest odmierzanie czasu wielu iteracji.

Brian Knoblauch
źródło
Wiem o tym, ale nie potrzebuję tego w prawdziwym projekcie, ale w jednym rodzaju zabawnym projekcie programistycznym.
ST3
Niezależnie od tego, czy potrzebujesz tego na żywo, czy dla zabawy, nie zmienia to odpowiedzi dla tej linii procesorów. Czy zamiast tego zastanawiałeś się nad przejściem na bardziej deterministyczny procesor, taki jak układ Propeller?
Brian Knoblauch,
3
Nawet przy skalarnym niepoprawne odgałęzienia implementacji i niepoprawność pamięci podręcznej mogą powodować zmiany w czasie wykonywania.
Paul A. Clayton,
W przypadku rzeczy związanych wyłącznie z procesorem (bez pominięcia pamięci podręcznej, nieprzewidzianych oddziałów) zachowanie procesora jest rozumiane na tyle szczegółowo, że analiza statyczna może często przewidzieć prawie dokładnie liczbę cykli na iterację, jaką pętla zajmie określony procesor (np. Intel Haswell). np. zobacz tę odpowiedź SO, gdzie patrząc na asm generowany przez kompilator, pozwól mi wyjaśnić, dlaczego wersja rozgałęziona działała prawie dokładnie 1,5x szybciej niż wersja CMOV na procesorze Sandybridge OP, ale znacznie bliżej na moim Skylake.
Peter Cordes,
Jeśli piszesz ręcznie asm ze względu na wydajność, warto poszukać opóźnień i wąskich gardeł w przepustowości procesorów Intel i AMD. Jest to trudne, a czasem to, co jest optymalne dla AMD, nie jest tym, co jest optymalne dla Intela.
Peter Cordes,
4

Informacje na temat procesora Intel można znaleźć w instrukcjach dla programistów Intel . Na przykład opóźnienie wynosi 1 cykl dla dodawania liczb całkowitych i 3 cykle dla mnożenia liczb całkowitych.

Nie wiem o mnożeniu, ale spodziewam się, że dodanie zawsze zajmie jeden cykl.

UmNyobe
źródło
Jeden cykl, z wyjątkiem sytuacji, gdy jest „wolny” (równolegle, gdy rurociągi są prawidłowo ustawione) lub trwa dłużej z powodu braku pamięci podręcznej. :-)
Brian Knoblauch
2
Obecnie (2018) informacje te są dostępne w załączniku C o nazwie „Czas oczekiwania i przepustowość instrukcji” dokumentu 248966 „Podręcznik referencyjny optymalizacji architektury Intel® 64 i IA-32”, dostępny również na stronie, do której link znajduje się w odpowiedzi
Stefanct