Jakie jest znaczenie „nieczasowych” dostępów do pamięci w x86

123

To jest pytanie niskiego poziomu. W asemblerze x86 są dwie instrukcje SSE:

MOVDQA xmmi, m128

i

MOVNTDQA xmmi, m128

Podręcznik programisty IA-32 mówi, że NT w MOVNTDQA oznacza Non-Temporal , a poza tym to to samo, co MOVDQA.

Moje pytanie brzmi: co to znaczy Non-Temporal ?

Nathan Fellman
źródło
6
Zauważ, że SSE4.1 MOVNTDQA xmmi, m128jest ładowaniem NT, podczas gdy wszystkie inne instrukcje NT są przechowywane, z wyjątkiem prefetchnta. Przyjęta tutaj odpowiedź wydaje się mówić tylko o sklepach. Oto, co udało mi się znaleźć w przypadku obciążeń NT . TL: DR: miejmy nadzieję, że procesor zrobi coś pożytecznego ze wskazówką NT, aby zminimalizować zanieczyszczenie pamięci podręcznej, ale nie zastępują one silnie uporządkowanej semantyki "normalnej" pamięci WB, więc muszą używać pamięci podręcznej.
Peter Cordes
5
Aktualizacja: obciążenia NT mogą nie dać nic użytecznego poza regionami pamięci UCSW na większości procesorów (np. Rodzina Intel SnB). Jednak sklepy NT / streaming zdecydowanie działają na normalnej pamięci.
Peter Cordes,
4
@Peter: Masz na myśli pamięć USWC, prawda? Nigdy wcześniej nie słyszałem o pamięci UCSW lub USWC. Wygooglowanie niewłaściwego akronimu nie było pomocne :-)
Andrew Bainbridge
4
@AndrewBainbridge: Tak, atrybut typu pamięci WC. Spekulatywne łączenie zapisu, którego nie można zapisać w pamięci podręcznej. Myślę, że pisałem wielkie litery UnCacheable i pamiętałem, że miał mieć 4 litery. : P
Peter Cordes

Odpowiedzi:

147

Non-Temporal SSE instrukcje (MOVNTI, MOVNTQ itp.), Nie są zgodne z normalnymi regułami spójności pamięci podręcznej. Dlatego po magazynach nieczasowych musi następować instrukcja SFENCE, aby ich wyniki były widoczne dla innych procesorów w odpowiednim czasie.

Gdy dane są generowane, a nie (natychmiast) ponownie wykorzystywane, fakt, że operacje składowania pamięci najpierw odczytują pełny wiersz pamięci podręcznej, a następnie modyfikują dane w pamięci podręcznej, negatywnie wpływa na wydajność. Ta operacja wypycha dane z pamięci podręcznych, które mogą być ponownie potrzebne, na rzecz danych, które nie będą wkrótce używane. Jest to szczególnie prawdziwe w przypadku dużych struktur danych, takich jak macierze, które są wypełniane, a następnie używane później. Zanim ostatni element matrycy zostanie wypełniony, sam rozmiar eliminuje pierwsze elementy, sprawiając, że buforowanie zapisów jest nieskuteczne.

W tej i podobnych sytuacjach procesory zapewniają obsługę nieczasowych operacji zapisu. W tym kontekście nieczasowe oznacza, że ​​dane nie będą wkrótce ponownie wykorzystane, więc nie ma powodu, aby je buforować. Te nieczasowe operacje zapisu nie odczytują wiersza pamięci podręcznej, a następnie modyfikują go; zamiast tego nowa treść jest bezpośrednio zapisywana w pamięci.

Źródło: http://lwn.net/Articles/255364/

Espo
źródło
15
Dobra odpowiedź, chciałbym tylko zwrócić uwagę, że na procesorze z instrukcjami NT, nawet z instrukcją nieczasową (tj. Normalną instrukcją), pamięć podręczna linii nie jest „odczytywana, a następnie modyfikowana”. W przypadku zwykłej instrukcji zapisywanej w wierszu, którego nie ma w pamięci podręcznej, wiersz jest rezerwowany w pamięci podręcznej, a maska ​​wskazuje, które części wiersza są aktualne. Ta strona nazywa to „bez stoiska w sklepie”: ptlsim.org/Documentation/html/node30.html . Nie mogłem znaleźć dokładniejszych odniesień, słyszałem o tym tylko od facetów, których zadaniem jest wdrażanie symulatorów procesorów.
Pascal Cuoq
2
Właściwie ptlsim.org jest stroną internetową o symulatorze procesora z dokładnością do cyklu, dokładnie tym samym, co robią faceci, którzy powiedzieli mi o „bez stoiska w sklepie”. Lepiej też o nich wspomnę na wypadek, gdyby kiedykolwiek zobaczyli ten komentarz: unisim.org
Pascal Cuoq
1
Z odpowiedzi i komentarzy tutaj stackoverflow.com/questions/44864033/ ... wynika, że SFENCEmoże to nie być potrzebne. Przynajmniej w tym samym wątku. Mógłbyś też spojrzeć?
Serge Rogatch
1
@SergeRogatch to zależy od scenariusza, o którym mówisz, ale tak, są scenariusze, w których sfencejest to wymagane dla sklepów NT, podczas gdy nigdy nie jest to wymagane tylko dla zwykłych sklepów. Magazyny NT nie są uporządkowane względem innych sklepów (NT lub nie), jak widzą inne wątki , bez rozszerzenia sfence. Jednak w przypadku odczytów z tego samego wątku, co w przypadku sklepów, nigdy nie jest to potrzebne sfence: dany wątek zawsze będzie widział własne magazyny w kolejności programu, niezależnie od tego, czy są to magazyny NT, czy nie.
BeeOnRope
40

Espo jest strzałem w dziesiątkę. Chciałem tylko dodać moje dwa centy:

Wyrażenie „nieczasowe” oznacza brak czasowej lokalizacji. Pamięci podręczne wykorzystują dwa rodzaje lokalności - przestrzenną i czasową, a używając instrukcji nieczasowych, sygnalizujesz procesorowi, że nie spodziewasz się, że element danych zostanie użyty w najbliższej przyszłości.

Jestem trochę sceptyczny co do ręcznie kodowanego zestawu, który używa instrukcji kontroli pamięci podręcznej. Z mojego doświadczenia wynika, że ​​te rzeczy prowadzą do większej liczby złych błędów niż jakikolwiek efektywny wzrost wydajności.

Pramod
źródło
pytanie o „zestaw ręcznie zakodowany, który używa instrukcji sterujących pamięcią podręczną”. Wiem, że wyraźnie powiedziałeś „kodowane ręcznie”, co w przypadku czegoś takiego jak JavaVM. Czy to lepszy przypadek użycia? JavaVM / Compiler przeanalizował statyczne i dynamiczne zachowanie programu i używa tych nieczasowych instrukcji.
Pat
4
Nie należy unikać wykorzystywania znanych właściwości lokalnych (lub ich braku) domeny, algorytmu lub aplikacji, w której występuje problem. Unikanie zanieczyszczenia pamięci podręcznej jest rzeczywiście bardzo atrakcyjnym i skutecznym zadaniem optymalizacji. Skąd ta niechęć do zgromadzeń? Istnieje ogromna liczba możliwości uzyskania korzyści, których kompilator nie może wykorzystać
awdz9nld
5
Z pewnością prawdą jest, że doświadczony programista niskiego poziomu może przewyższyć kompilator dla małych jąder. To jest świetne do publikowania artykułów i postów na blogach i zrobiłem jedno i drugie. Są także dobrymi narzędziami dydaktycznymi i pomagają zrozumieć, co się „naprawdę” dzieje. Jednak z mojego doświadczenia wynika, że ​​w praktyce, gdy masz prawdziwy system, nad którym pracuje wielu programistów, a poprawność i łatwość konserwacji są ważne, korzyści wynikające z kodowania niskopoziomowego są prawie zawsze większe niż ryzyko.
Pramod
4
@Pramod ten sam argument łatwo uogólnia się ogólnie na optymalizację i nie jest tak naprawdę przedmiotem dyskusji - wyraźnie, że kompromis został już rozważony lub w inny sposób uznany za nieistotny, biorąc pod uwagę fakt, że mówimy już o instrukcjach nieczasowych
awdz9nld
7

Zgodnie z podręcznikiem dewelopera oprogramowania architektury Intel® 64 i IA-32, tom 1: Architektura podstawowa, rozdział „Programming with Intel Streaming SIMD Extensions (Intel SSE)”:

Buforowanie danych czasowych i nieczasowych

Dane, do których odwołuje się program, mogą być tymczasowe (dane zostaną ponownie użyte) lub nieczasowe (dane będą przywoływane raz i nie będą ponownie wykorzystywane w najbliższej przyszłości). Na przykład kod programu jest generalnie czasowy, podczas gdy dane multimedialne, takie jak lista wyświetlania w aplikacji graficznej 3-D, są często nieczasowe. Aby efektywnie wykorzystać pamięci podręczne procesora, ogólnie pożądane jest buforowanie danych czasowych, a nie buforowanie danych nieczasowych. Przeciążanie pamięci podręcznych procesora danymi nieczasowymi jest czasami nazywane „zanieczyszczaniem pamięci podręcznych”. Instrukcje sterowania buforowaniem SSE i SSE2 umożliwiają programowi zapisywanie danych nieczasowych w pamięci w sposób minimalizujący zanieczyszczenie pamięci podręcznych.

Opis nieczasowego obciążenia i instrukcji przechowywania. Źródło: Podręcznik dewelopera oprogramowania architektury Intel 64 i IA-32, tom 2: Odniesienie do zestawu instrukcji

LOAD (MOVNTDQA - Załaduj podwójną wskazówkę bez wyrównania czasowego czwórki)

Ładuje podwójne słowo-poczwórne z operandu źródłowego (drugi operand) do operandu docelowego (pierwszy operand) przy użyciu nieczasowej wskazówki, jeśli źródłem pamięci jest typ pamięci WC (łączenie zapisu) [...]

[…] procesor nie odczytuje danych do hierarchii pamięci podręcznej ani nie pobiera odpowiedniej linii pamięci podręcznej z pamięci do hierarchii pamięci podręcznej.

Zauważ, że, jak komentuje Peter Cordes, nie jest to użyteczne w normalnej pamięci WB (z zapisem zwrotnym) na obecnych procesorach, ponieważ podpowiedź NT jest ignorowana (prawdopodobnie dlatego, że nie ma modułów wstępnych HW rozpoznających NT) i obowiązuje pełna silnie uporządkowana semantyka obciążenia . prefetchntamoże być używany jako obciążenie zmniejszające zanieczyszczenie z pamięci WB

SKLEP (MOVNTDQ - przechowuj spakowane liczby całkowite za pomocą podpowiedzi niezwiązanej z czasem)

Przenosi spakowane liczby całkowite w operandzie źródłowym (drugim operandzie) do operandu docelowego (pierwszy operand) przy użyciu nieczasowej wskazówki, aby zapobiec buforowaniu danych podczas zapisu do pamięci.

[...] procesor nie zapisuje danych w hierarchii pamięci podręcznej ani nie pobiera odpowiedniej linii pamięci podręcznej z pamięci do hierarchii pamięci podręcznej.

Korzystając z terminologii zdefiniowanej w zasadach i wydajności zapisu w pamięci podręcznej , można je uznać za zapisujące (bez przydzielania zapisu, bez pobierania przy braku zapisu).

Wreszcie, może być interesujące przejrzenie notatek Johna McAlpina dotyczących magazynów nieczasowych .

chus
źródło
3
SSE4.1 MOVNTDQArobi coś specjalnego tylko w regionach pamięci WC (nieczytelne łączenie zapisu), np. Wideo RAM. Nie jest to w ogóle przydatne w normalnej pamięci WB (z zapisem zwrotnym) na bieżącym sprzęcie, podpowiedź NT jest ignorowana i stosowana jest semantyka pełnego, silnie uporządkowanego obciążenia. prefetchntamoże być jednak przydatne jako obciążenie zmniejszające zanieczyszczenie pamięci WB. Czy obecne architektury x86 obsługują obciążenia nieczasowe (z „normalnej” pamięci)? .
Peter Cordes
2
Zgadza się, magazyny NT działają dobrze na pamięci WB i są słabo uporządkowane i zwykle są dobrym wyborem do zapisywania dużych obszarów pamięci. Ale ładunki NT nie. Podręcznik x86 na papierze pozwala podpowiedź NT zrobić coś dla ładowania z pamięci WB, ale w obecnych procesorach nic to nie robi . (Prawdopodobnie dlatego, że nie ma modułów wstępnych HW świadomych NT.)
Peter Cordes,
Dodałem te istotne informacje do odpowiedzi. Dziękuję Ci bardzo.
chus
1
@LewisKelsey: magazyny NT zastępują typ pamięci. Dlatego można je słabo uporządkować w pamięci WB. Głównym efektem jest unikanie RFO (najwyraźniej wysyłają unieważnienie, które usuwa nawet inne brudne linie, gdy docierają do pamięci). Mogą również stać się widoczne poza kolejnością, więc nie muszą czekać, aż po wcześniejszych zatwierdzeniach pamięci z pominięciem pamięci podręcznej (zwykłych) lub do momentu, gdy wcześniejsze ładowanie pamięci podręcznej z powodu braku pamięci otrzyma dane. tj. rodzaj wąskiego gardła, o który pytano w Czy pamięć poza każdym rdzeniem jest koncepcyjnie zawsze płaska / jednolita / synchroniczna w systemie wieloprocesorowym? .
Peter Cordes
1
@LewisKelsey: Maszyna zamawiająca pamięć wyczyszczona mogłaby zabić wszelkie obciążenia z magazynu UC, które nie powinny być zrobione wcześnie, jeśli to konieczne. Poza tym, zatwierdzanie kolejności nie wchodzi w grę, dopóki sklep nie wycofa się z niedziałającego zaplecza. Może się to zdarzyć dopiero po wykonaniu uop adresu sklepu, w którym to momencie można sprawdzić typ pamięci dla adresu. Adres sklepu uop sprawdza TLB podczas wykonywania; w ten sposób procesory mogą wykrywać błędne sklepy, zanim przejdą na emeryturę. Nie może czekać, aż wpis SB będzie gotowy do zatwierdzenia w L1d; w tym momencie wykonanie już minęło.
Peter Cordes