AMD Zen 3 – organizacja pamięci podręcznych

Jedną z największych zmian w makroarchitekturze AMD Zen 3 jest nowa organizacja rdzeni i wspólnych dla nich pamięci podręcznych. Poprzednio cztery rdzenie dzieliły jedną pulę cache L3. W Zen 3 – z powodów, o których pisałem w poprzedniej publikacji – zachowano tę samą pojemność cache L3 w stosunku do liczb rdzeni. Rdzenie i towarzyszące im 2-megabajtowe segmenty wspólnej pamięci pogrupowano jednak po 8.

Zen 1Zen 2Zen 3
Pamięć podręczna L2512 kB512 kB512 kB
Pamięć podręczna L3 w CCX8 MB16 MB32 MB
L3 wspólna dla…4 rdzeni4 rdzeni8 rdzeni

8 rdzeni i ich pamięć L3 tworzy CCX – core complex. Pamięć L3 w ramach jednego CCX jest wspólna dla wszystkich rdzeni.

Dostęp do pamięci L3 trwa w Zen 3 nieco dłużej, niż w poprzednich generacjach. Im większa pojemność cache, tym dłuższy czas dostępu do niej. Choć L3 w Zen 3 jest zbudowana prawie tak samo, jak w Zen 2, danych trzeba szukać w dwa razy większej pojemności, a do dużej części pamięci jest po prostu fizycznie dwa razy dalej.

Nawet z tym spowolnieniem pamięć L3 w Zen 3 jest wybitnie szybka i pojemna w porównaniu do innych wysokowydajnych procesorów, nie tylko tych o architekturze x86.

Wspólność cache L3 ma dwa główne efekty. Po pierwsze, o ile inne rdzenie nie korzystają intensywnie z pamięci, jednowątkowy program może mieć dostęp do znacznie większej puli szybkiej pamięci: może zająć całą pojemność L3. To daje wzrost wydajności niezależny od systemu operacyjnego, rekompilacji czy innych programistycznych technk optymalizacyjnych, dostępny nawet dla starych i kiepskich technicznie programów. Po drugie, wspólna pamięć (podręczna lub RAM) jest jedynym sposobem na to, żeby dwa wątki programu, przypisane do różnych rdzeni, operowały na tym samym obszarze pamięci.

Komunikacja między rdzeniami w Zen 3

Przytoczę jeszcze raz analogię z maszyną Turinga: rdzenie procesora wielordzeniowego można porównać do wielu maszyn Turinga operujących na jednej taśmie. Nie mają żadnego sposobu na skomunikowanie się ze sobą innego niż zapisanie czegoś na taśmie. Kiedy ten sam fragment taśmy trafi przed głowicę innej maszyny, nastąpi jedyna możliwa między nimi komunikacja.

W ten sposób przepustowość i opóźnienie w komunikacji między rdzeniami są nierozłącznie związane z dostępem do najszybszej wspólnej dla nich puli RAM-u. W tym przypadku to wspólna pamięć podręczna L3.

Po drugie, jeden wątek ma do dyspozycji więcej pamięci dla siebie

Opóźnienie w komunikacji między rdzeniami nie jest jednolite w ramach jednego bloku CCX. Niewielkie różnice w kolorze wewnątrz dwóch dużych zielonych pól – par wątków znajdujących się w jednym CCX – nie są błędem ani artefaktem pomiarowym. Zmierzenie go inną metodą potwierdza, że niektóre pary rdzeni komunikują się wolniej niż inne. Przyjrzałem się opóźnieniu w komunikacji między rdzeniami w ramach jednego CCX:

W tym teście wątek przypisany do jednego procesora rezerwuje kilkaset megabajtów przestrzeni adresowej, a następnie modyfikuje 192 kB – to ma na celu sprowadzenie takiej części adresów do pamięci L2, która w Zen 3 jest prywatna dla jednego rdzenia. Następnie drugi wątek, przypisany do innego procesora, próbuje odczytać te dane, i mierzy jak długo to trwało. Ten test powtarza się wielokrotnie dla różnych 192-kilobajtowych części zarezerwowanej przestrzeni adresowej. Średni czas dostępu jest podany na wykresie (tym razem, dla dokładności, w cyklach zegara, nie nanosekundach).

Adresy w pamięci są w procesorach Zen, Zen 2 i Zen 3 równomiernie rozdzielane pomiędzy segmenty pamięci cache L3. Ponieważ test wykorzystuje nie jedną linię z cache, ale duży obszar, spodziewam się, że dane są pobierane ze wszystkich segmentów. Fizyczna odległość między segmentami L3 nie powinna mieć wpływu na średni czas dostępu.

Rozkład opóźnień jest nieco skomplikowany przez to, że przetestowałem 12-rdzeniowy procesor, który w każdym CCX ma 2 rdzenie i 2 segmenty cache L3 wyłączone. Być może każdy CCX w każdym Ryzenie 9 5900X ma inny rozkład opóźnień w zależności od tego, które 2 spośród 8 rdzeni wyłączono.

Pary rdzeni są z grubsza skupione wokół trzech poziomów opóźnień: trzy pary są „najszybsze”, trzy „najwolniejsze”, a dziewięć ma średni czas komunikacji ze sobą. Wyniki testu nie pozwalają jednoznacznie określić, jak jest zrealizowana komunikacja wewnątrz CCX. AMD tego nie ujawia, a różni komentatorzy i recenzencji proponują albo pełen crossbar (połączenie każdy-z-każdym), albo dwa 6-punktowe crossbary, albo magistralę pierścieniową (patrz przypisy).

Wydaje się, że magistralę pierścieniową można wykluczyć. Nie ma sposobu na usunięcie 2 przystanków z pierścienia o 8 lub więcej przystankach w taki sposób, żeby pozostawić tylko 3 najkrótsze trasy. Na podobnej zasadzie można wykluczyć pełen crossbar oraz dwa równoległe 6-klientowe crossbary. Jak sądzę, w Zen 3 zastosowano jakiś dwu- lub więcej etapowy crossbar.

W praktyce różnica w czasie komunikacji między rdzeniami nie ma istotnego znaczenia. Pomiędzy najszybszą a najwolniejszą trasą jest ok. 20 cykli różnicy – tyle samo, co w 8-rdzeniowym procesorze Coffee Lake/Comet Lake, ale najwolniejsza trasa w Zen 3 jest tak długa, jak najkrótsza w Coffee Lake. Komunikacja w ramach jednego CCX jest ok. dwukrotnie szybsza od komunikacji pomiędzy różnymi CCX, ma znacznie większą przepustowość i kosztuje znacznie mniej energii. Dlatego choć warto dbać o przypisanie wielowątkowych programów do rdzeni znajdujących się w jednym CCX (systemy Windows 10 i Linux robią to automatycznie), to nie trzeba brać pod uwagę różnic pomiędzy rdzeniami wewnątrz CCX.

Przypisy i źródła

Wszystkie testy zostały wykonane w systemie Ubuntu 20.10 z jądrem Linux 5.8.0. Numeracja wątków logicznych została zmieniona na tę odpowiadającą systemom Windows: sąsiadujące numery odpowiadają dwóm wątkom SMT jednego rdzenia.

 

mbrzostek