Czym są opóźnione-cykle-frontend i opóźnione-cykle-zaplecze w wyniku „perf stat”?

83

Czy ktoś wie, jakie znaczenie mają stalled-Cycles-frontend i stalled-Cycles-backend w wyniku perf stat? Szukałem w internecie, ale nie znalazłem odpowiedzi. Dzięki

$ sudo perf stat ls                     

Performance counter stats for 'ls':

      0.602144 task-clock                #    0.762 CPUs utilized          
             0 context-switches          #    0.000 K/sec                  
             0 CPU-migrations            #    0.000 K/sec                  
           236 page-faults               #    0.392 M/sec                  
        768956 cycles                    #    1.277 GHz                    
        962999 stalled-cycles-frontend   #  125.23% frontend cycles idle   
        634360 stalled-cycles-backend    #   82.50% backend  cycles idle
        890060 instructions              #    1.16  insns per cycle        
                                         #    1.08  stalled cycles per insn
        179378 branches                  #  297.899 M/sec                  
          9362 branch-misses             #    5.22% of all branches         [48.33%]

   0.000790562 seconds time elapsed
Dafan
źródło
Nie jestem pewien, jakie jest prawdziwe pytanie. Pytasz, czym jest frontend i backend procesora? Przeczytaj to wprowadzenie na bardzo wysokim poziomie . Czy to odpowiada na twoje pytanie?
Ali
Szukałem i szukałem podobnej odpowiedzi ... To był najbardziej pomocny zasób, jaki znalazłem od firmy Intel: software.intel.com/en-us/articles/ ...
Jmoney38
Nie, prawie nikt nie wie, co to naprawdę oznacza. Ale odniesienia do podręcznika (jak w odpowiedzi Manuela Selvy) w połączeniu z tym postem (którego jeszcze nie do końca rozumiem) są najbliższe, jakie znalazłem: sites.utexas.edu/jdm4372/2014/06/04/ ...
jberryman

Odpowiedzi:

60

Teoria:

Zacznijmy od tego: dzisiejsze procesory są superskalarne, co oznacza, że ​​mogą wykonywać więcej niż jedną instrukcję na cykl (IPC). Najnowsze architektury Intela mogą obsługiwać do 4 IPC (4 dekodery instrukcji x86). Nie wprowadzajmy do dyskusji fuzji makro / mikro, aby bardziej komplikować sprawę :).

Zazwyczaj obciążenia nie osiągają IPC = 4 ze względu na różne spory zasobów. Oznacza to, że procesor marnuje cykle (liczba instrukcji jest podawana przez oprogramowanie i procesor musi je wykonać w jak najmniejszej liczbie cykli).

Całkowite cykle spędzane przez procesor możemy podzielić na 3 kategorie:

  1. Cykle, w których instrukcje przechodzą na emeryturę (przydatna praca)
  2. Cykle spędzone na zapleczu (zmarnowane)
  3. Cykle spędzone w Front-End (zmarnowane).

Aby uzyskać IPC równy 4, liczba wycofanych cykli musi być zbliżona do całkowitej liczby cykli. Należy pamiętać, że na tym etapie wszystkie mikrooperacje (uOps) wycofują się z potoku i przekazują wyniki do rejestrów / pamięci podręcznych. Na tym etapie możesz mieć nawet więcej niż 4 uOps wycofania, ponieważ liczba ta wynika z liczby portów wykonawczych. Jeśli tylko 25% cykli przechodzi na 4 uOps, wówczas ogólny IPC wyniesie 1.

Te cykle stalled w back-end to strata, ponieważ CPU musi czekać na zasobach (zwykle pamięci) lub zakończyć długie opóźnienia instrukcje (np transcedentals - sqrt, odwrotności, podziałów, itd.).

Te cykle stalled w front-end to strata, bo to oznacza, że Front-End nie żywią tylnym końcu z mikro-działalności. Może to oznaczać, że brakuje ci w pamięci podręcznej instrukcji lub złożonych instrukcji, które nie zostały jeszcze zdekodowane w pamięci podręcznej mikrooperacji. Kod skompilowany dokładnie na czas zwykle wyraża to zachowanie.

Innym powodem przeciągnięcia jest chybiona prognoza gałęzi. Nazywa się to złymi spekulacjami. W takim przypadku wydawane są uOps, ale są one odrzucane, ponieważ BP przewidziano nieprawidłowo.

Implementacja w profilerach:

Jak interpretujesz zatrzymane cykle BE i FE?

Różne osoby profilujące mają różne podejścia do tych metryk. W vTune kategorie od 1 do 3 sumują się, dając 100% cykli. Wydaje się to rozsądne, ponieważ albo masz zablokowany procesor (żadne uOps nie są wycofywane), albo wykonujesz użyteczną pracę (uOps) wycofując się. Zobacz więcej tutaj: https://software.intel.com/sites/products/documentation/doclib/stdxe/2013SP1/amplifierxe/snb/index.htm

W perfekcyjnym zwykle tak się nie dzieje. To jest problem, ponieważ kiedy widzisz 125% cykli zablokowanych w przedniej części , nie wiesz, jak naprawdę to zinterpretować. Możesz powiązać metrykę> 1 z faktem, że są 4 dekodery, ale jeśli będziesz kontynuować rozumowanie, IPC nie będzie pasować.

Co więcej, nie wiesz, jak duży jest problem. 125% czego? Co w takim razie oznaczają # cykle?

Osobiście wyglądam trochę podejrzanie w przypadku zatrzymanych cykli BE i FE w PERF i mam nadzieję, że zostanie to naprawione.

Prawdopodobnie ostateczną odpowiedź uzyskamy, debugując kod stąd: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/builtin-stat.c

VAndrei
źródło
Jakie zdarzenia są używane w VTune jako FE i BE? Manuel opublikował wydarzenia z perf na Sandy Bridge. Czasami dekoder nie może zdekodować 4 instrukcji ( realworldtech.com/sandy-bridge/4 - są 3 proste dekodery, które nie mogą dekodować złożonych poleceń).
osgx
Prawdą jest, że istnieje również złożony dekoder, ale może on również dekodować proste instrukcje. Zaktualizowałem swój post linkiem do liczników vTune. Używa tych samych liczników co perf, ale myślę, że vTune łączy się inaczej.
VAndrei
4
Vtune używa „IDQ_UOPS_NOT_DELIVERED.CORE / SLOTS” software.intel.com/en-us/articles/ jako „Frontend bound” i „1 - (Front-End Bound + Retiring + Bad Speculation)” jako „Backend bound” where ” Retiring = UOPS_RETIRED.RETIRE_SLOTS / SLOTS "," Bad Speculation = (UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) / SLOTS "i" SLOTS = 4 * pipeline_CLED "z równą szerokością maszyny. ”.
osgx
1
A dla Sandy Bridge, podręcznik optymalizacji Intel.com/content/dam/www/public/us/en/documents/manuals/… daje to samo w "B.3.2 Hierarchical Top-Down Performance Characterization Methodology" "% FE_Bound = 100 * (IDQ_UOPS_NOT_DELIVERED.CORE / N);% Bad_Speculation = 100 * ((UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) / N);% Retiring = 100 * (UOPS_RETIED); * (1 - (FE_Bound + Retiring + Bad_Speculation)); N = 4 * CPU_CLK_UNHALTED.THREAD "
osgx
@osgx Thanks. Teraz wiemy, co oznaczają metryki w vTune i że sumują się do 100%. Następne pytanie brzmi: dlaczego perf oblicza je inaczej? Czy to błąd, czy też kryje się za tym znaczenie?
VAndrei
43

Aby przekonwertować ogólne zdarzenia wyeksportowane przez perf do surowej dokumentacji procesora, możesz uruchomić:

more /sys/bus/event_source/devices/cpu/events/stalled-cycles-frontend 

Pokaże ci coś takiego

event=0x0e,umask=0x01,inv,cmask=0x01

Zgodnie z dokumentacją Intela SDM tom 3B (mam rdzeń i5-2520):

UOPS_ISSUED.ANY:

  • Zwiększa w każdym cyklu liczbę Uops wydaną przez RAT do RS.
  • Ustaw Cmask = 1, Inv = 1, Any = 1, aby policzyć zablokowane cykle tego rdzenia.

Dla zdarzenia stalled-Cycles-backend tłumaczącego na event = 0xb1, umask = 0x01 w moim systemie ta sama dokumentacja mówi:

UOPS_DISPATCHED.THREAD:

  • Zlicza całkowitą liczbę błędów wysyłanych w każdym cyklu
  • Ustaw Cmask = 1, INV = 1, aby liczyć cykle utknięcia.

Zazwyczaj cykle zatrzymane to cykle, w których procesor czeka na coś (na przykład pamięć do podania po wykonaniu operacji ładowania) i nie ma żadnych innych rzeczy do zrobienia. Co więcej, frontendowa część procesora jest elementem sprzętu odpowiedzialnym za pobieranie i dekodowanie instrukcji (konwertowanie ich na UOP), gdzie część zaplecza jest odpowiedzialna za efektywne wykonywanie UOP.

Manuel Selva
źródło
dzięki za odpowiedź. więc jaka jest różnica między zatrzymaniem a bezczynnością?
Dafan,
2
Zatrzymany i bezczynny to to samo. Procesor jest bezczynny, ponieważ utknął, ponieważ potok instrukcji nie porusza się.
Milind Dumbare
@Milind, czy nie powinno być różnicy, zatrzymanie powinno być „nie postępujemy, ponieważ następny etap na to nie pozwala”, a bezczynność powinno być „nie ma nic do przetworzenia”?
Surt
13

Cykl procesora zostaje „zatrzymany”, gdy potok nie jest w trakcie jego wykonywania.

Potok procesora składa się z wielu etapów: front-end to grupa tych etapów, która odpowiada za fazy pobierania i dekodowania, podczas gdy zaplecze wykonuje instrukcje. Istnieje bufor między front-endem a back-endem, więc gdy pierwszy jest zablokowany, drugi może nadal mieć trochę pracy.

Zaczerpnięte z http://paolobernardi.wordpress.com/2012/08/07/playing-around-with-perf/

Milind Dumbare
źródło
2
Jak możemy mieć więcej przestojów niż cykli?
osgx
11

Według autora tych zdarzeń definiują one luźno i są aproksymowane przez dostępne liczniki wydajności procesora. Jak wiem, perf nie obsługuje formuł do obliczania syntetycznego zdarzenia na podstawie kilku zdarzeń sprzętowych, więc nie może używać metody związanej z blokadą front-end / back-end z podręcznika Intel Optimization manual (Implemented in VTune) http: // www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf „B.3.2 Hierarchiczna top-down metodologia charakteryzacji wydajności”

%FE_Bound = 100 * (IDQ_UOPS_NOT_DELIVERED.CORE / N ); 
%Bad_Speculation = 100 * ( (UOPS_ISSUED.ANY – UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES ) / N) ; 
%Retiring = 100 * ( UOPS_RETIRED.RETIRE_SLOTS/ N) ; 
%BE_Bound = 100 * (1 – (FE_Bound + Retiring + Bad_Speculation) ) ; 
N = 4*CPU_CLK_UNHALTED.THREAD" (for SandyBridge)

Prawidłowe formuły mogą być używane z niektórymi zewnętrznymi skryptami, tak jak zostało to zrobione w pmu-tools Andi Kleen ( toplev.py): https://github.com/andikleen/pmu-tools (źródło), http://halobates.de/blog/ p / 262 (opis):

% toplev.py -d -l2 numademo  100M stream
...
perf stat --log-fd 4 -x, -e
{r3079,r19c,r10401c3,r100030d,rc5,r10e,cycles,r400019c,r2c2,instructions}
{r15e,r60006a3,r30001b1,r40004a3,r8a2,r10001b1,cycles}
numademo 100M stream
...
BE      Backend Bound:                      72.03%
    This category reflects slots where no uops are being delivered due to a lack
    of required resources for accepting more uops in the    Backend of the pipeline.
 .....
FE      Frontend Bound:                     54.07%
This category reflects slots where the Frontend of the processor undersupplies
its Backend.

Commit, który wprowadził zdarzenia stalled-Cycles-frontend i stalled-Cycles-backend zamiast oryginalnego uniwersalnego stalled-cycles:

http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/commit/?id=8f62242246351b5a4bc0c1f00c0c7003edea128a

author  Ingo Molnar <mingo@el...>   2011-04-29 11:19:47 (GMT)
committer   Ingo Molnar <mingo@el...>   2011-04-29 12:23:58 (GMT)
commit  8f62242246351b5a4bc0c1f00c0c7003edea128a (patch)
tree    9021c99956e0f9dc64655aaa4309c0f0fdb055c9
parent  ede70290046043b2638204cab55e26ea1d0c6cd9 (diff)

Zdarzenia perf: dodawanie ogólnych definicji zdarzeń wstrzymanych cykli front-end i back-end Dodaj dwa ogólne zdarzenia sprzętowe: cykle wstrzymania front-end i back-end.

Te zdarzenia mierzą warunki, w których procesor wykonuje kod, ale jego możliwości nie są w pełni wykorzystywane. Zrozumienie takich sytuacji i ich analiza jest ważnym podzadaniem przepływów pracy optymalizacji kodu.

Oba zdarzenia ograniczają wydajność: większość opóźnień w interfejsie jest zwykle spowodowana błędnymi przewidywaniami gałęzi lub błędami pobierania instrukcji, przestoje zaplecza mogą być spowodowane różnymi niedoborami zasobów lub nieefektywnym planowaniem instrukcji.

Ważniejsze są blokady front-endu: kod nie może działać szybko, jeśli strumień instrukcji nie jest podtrzymywany.

Nadmiernie wykorzystany back-end może powodować blokady front-endu i dlatego też należy go mieć na oku.

Dokładny skład jest bardzo zależny od logiki programu i zestawu instrukcji.

Używamy luźno terminów „stall”, „front-end” i „back-end” i staramy się używać najlepszych dostępnych zdarzeń z określonych procesorów, które przybliżają te pojęcia.

DW: Peter Zijlstra DW: Arnaldo Carvalho de Melo DW: Frederic Weisbecker Link: http://lkml.kernel.org/n/[email protected] Podpisano przez: Ingo Molnar

    /* Install the stalled-cycles event: UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
-       intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0x1803fb1;
+       intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;

-   PERF_COUNT_HW_STALLED_CYCLES        = 7,
+   PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
+   PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
osgx
źródło
Czy ostatecznie jest to błąd w perf? Ponieważ FE + BE +? nie dodawaj do znanej wartości teoretycznej, trudno jest ocenić, jak duży jest problem twojego kodu. Kiedy widzisz 75% utknięcia FE, należy to porównać z czymś. Mówiąc, że 75% ze 100% kodu utknie w FE lub BE ma zupełnie inne znaczenie i wartość. Z tego co widzę, nawet toplev.py ma ten sam problem. Jeśli to nie jest problem, w jaki sposób interpretujemy wskaźniki? Co sprawia, że ​​wskaźniki są wysokie lub niskie?
VAndrei,
VAndrei, czy masz krótki i powtarzalny przykład dla SandyBridge (+ -1 generacja); zarówno dla perf statFE> 100%, jak i dla toplev.py? Właśnie zacząłem od krótkich prostych pętli i mam cykle 3G dla instrukcji 3G (1G to gałęzie z odsetkiem chybionych 0,00%) ze straganami 2G FE ( perf stat) i 1G BE straganami (IPC = 1,00). Myślę, że problemem jest poprawne zdefiniowanie „przeciągnięcia” dla złożonego rdzenia OOO, a innym jest poprawna interpretacja toplev.pywyników.
osgx
Kod, który tutaj zamieściłem: stackoverflow.com/questions/28961405/ ... powinien być powiązany z front-endem. Jest w nim wiele braków w gałęziach, które generowałyby stragany FE. Jeśli chodzi o BE bound, potrzebujesz obciążenia, które czeka na dane z pamięci RAM. Przydziel 1/2 rozmiaru pamięci fizycznej w buforze i użyj LCG (jak w moim kodzie), aby wykonać operację odczytu / modyfikacji / zapisu w losowej lokalizacji w buforze. To generuje niewielką liczbę instrukcji poza transakcją RMW, a rdzeń zatrzyma się w BE oczekując na dane z pamięci RAM.
VAndrei,
Generowanie obciążeń związanych z FE jest sporym wyzwaniem. Spróbuj, czy rozgałęziający się mikroznak działa, ale jeśli nie, potrzebujesz czegoś bardziej złożonego. Blokada FE byłaby generowana przez pomyłki dużej liczby instrukcji w pamięci podręcznej. Aby to zrobić, potrzebujesz dużego kodu z dalekimi przeskokami, które doprowadzą do wielu pominięć I $. W tym momencie nie mam pomysłu na to, jak wykonać obciążenie związane z FE w mikroznakach.
VAndrei
Myślę, że byłbyś zainteresowany tym linkiem: stackoverflow.com/questions/1756825/… Możesz użyć niektórych z omawianych technik, aby opróżnić I $ i tym samym wygenerować blokady FE.
VAndrei