Czy jest sens używać instrukcji LFENCE na procesorach x86/x86 64?

Często w Internecie stwierdzam, że LFENCE nie ma sensu w procesorach x86, czyli nic nie robi, więc zamiast {[3] } możemy absolutnie bezbolesnie używać SFENCE, Ponieważ MFENCE = SFENCE + LFENCE = SFENCE + NOP = SFENCE.

Ale jeśli LFENCE nie ma sensu, to dlaczego mamy cztery podejścia do uzyskania sekwencyjnej Spójności w x86 / x86_64:

  1. LOAD (bez ogrodzenia) i STORE + MFENCE
  2. LOAD (bez ogrodzenia) i LOCK XCHG
  3. MFENCE + LOAD oraz STORE (bez ogrodzenia)
  4. LOCK XADD ( 0 ) i STORE (bez ogrodzenia)

Wzięte stąd: http://www.cl.cam.ac.uk / ~pes20/cpp/cpp0xmappings.html

Oraz występy Herba Suttera na stronie 34 u dołu: https://skydrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&wdo=2&authkey=!AMtj_EflYn2507c

Gdyby LFENCE nic nie zrobił, wtedy podejście (3) miałoby następujące znaczenie: SFENCE + LOAD and STORE (without fence), ale nie ma punkt w robieniu SFENCE przed LOAD. Ie jeśli LFENCE nic nie robi, podejście (3) nie ma sensu.

Czy to ma sens w procesorach x86 / x86_64?

Odpowiedź:

1. LFENCE wymagane w przypadkach opisanych w zaakceptowanej Odpowiedzi, poniżej.

2. podejście (3) powinno być oglądane Nie niezależnie, ale w połączeniu z poprzednimi poleceniami. Na przykład approach (3):

MFENCE
MOV reg, [addr1]  // LOAD-1
MOV [addr2], reg  //STORE-1

MFENCE
MOV reg, [addr1]  // LOAD-2
MOV [addr2], reg  //STORE-2

Możemy przepisz kod podejścia (3) w następujący sposób:

SFENCE
MOV reg, [addr1]  // LOAD-1
MOV [addr2], reg  //STORE-1

SFENCE
MOV reg, [addr1]  // LOAD-2
MOV [addr2], reg  //STORE-2

I tutaj SFENCE ma sens, aby zapobiec zmianie kolejności STORE-1 I LOAD-2. W tym celu po komendzie STORE-1 SFENCE spłukuje Store-Buffer.

Author: Flow, 2013-12-01

3 answers

Bottom line (TL; DR): LFENCE samo w sobie wydaje się bezużyteczne przy porządkowaniu pamięci, jednak nie czyni SFENCE substytutem MFENCE. Logika "arytmetyczna" w pytaniu nie ma zastosowania.


Oto fragment Intel ' s Software Developers Manual, volume 3 , sekcja 8.2.2( wydanie 325384-052us z września 2014), tego samego, którego użyłem w another answer

  • odczyty nie są zmieniane na inne odczyty.
  • zapisy nie są zmieniane na starsze odczyty.
  • zapis do pamięci nie jest zmieniany z innymi zapisami, z następującymi wyjątkami:
    • zapis wykonywany za pomocą instrukcji CLFLUSH;
    • W przeciwieństwie do tego, w jaki sposób można przesyłać strumieniowo pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np. pliki wideo), pliki wideo (np.]}
    • operacje łańcuchowe (patrz sekcja 8.2.4.1).
  • odczyty mogą być zmieniane ze starszymi zapisami na inne lokalizacje, ale nie ze starszymi zapisami do tej samej lokalizacji.
  • odczytu lub zapisu nie można zmienić kolejności za pomocą instrukcji We / Wy, instrukcji zablokowanych lub instrukcji serializujących.
  • Reads nie może przekazać wcześniejszych instrukcji LFENCE i MFENCE.
  • zapis nie może przekazać wcześniejszych instrukcji LFENCE, SFENCE i MFENCE.
  • instrukcje nie mogą przejść wcześniejszych odczytów.
  • instrukcje SFENCE nie mogą przejść wcześniejszych zapisów.
  • Instrukcja MFENCE nie może przekaż wcześniejsze odczyty lub zapisy.

Stąd wynika, że:

  • MFENCE jest pełnym ogrodzeniem pamięci dla wszystkich operacji na wszystkich typach pamięci, bez względu na to, czy są one czasowe, czy nie.
  • SFENCE zapobiega tylko zmianie kolejności zapisów (w innej terminologii jest to bariera StoreStore) i jest użyteczna tylko razem z nie-czasowymi magazynami i innymi instrukcjami wymienionymi jako wyjątki.
  • LFENCE zapobiega zmianie kolejności odczytów z kolejnymi odczytami i zapisami (tj. łączy bariery LoadLoad i LoadStore). Jednak pierwsze dwa pociski mówią, że bariery LoadLoad i LoadStore są zawsze na miejscu, bez wyjątków. Dlatego samo LFENCE jest bezużyteczne do porządkowania pamięci.

Na poparcie ostatniego twierdzenia, spojrzałem na wszystkie miejsca, gdzie LFENCE jest wymieniony we wszystkich 3 tomach podręcznika Intela, i nie znalazłem żadnego, który mówiłby, że LFENCE jest wymagane dla spójności pamięci. Even MOVNTDQA - jedyna do tej pory nie-czasowa Instrukcja obciążenia - wspomina MFENCE, ale Nie LFENCE.


Update: zobacz odpowiedzi na dlaczego jest (a nie jest?) SFENCE + LFENCE odpowiednik MFENCE? na Poprawne odpowiedzi do domysłów poniżej

Czy MFENCE jest równoważna "sumie" pozostałych dwóch płotów, czy nie, jest podchwytliwym pytaniem. Na pierwszy rzut oka, wśród trzech instrukcji ogrodzenia tylko MFENCE zapewnia barierę obciążenia magazynowego, tzn. zapobiega zmianie kolejności odczytów z wcześniejszymi zapisami. Poprawna odpowiedź wymaga jednak znajomości więcej niż powyższe zasady, a mianowicie, ważne jest, aby wszystkie instrukcje dotyczące ogrodzenia były uporządkowane względem siebie. To sprawia, że sekwencja SFENCE LFENCE jest potężniejsza niż zwykłe połączenie pojedynczych efektów: ta sekwencja zapobiega również zmianie kolejności obciążenia (ponieważ ładunki nie mogą przejść LFENCE, które nie mogą przejść SFENCE, które nie mogą przejść przechowalni), a tym samym stanowi pełne ogrodzenie pamięci (patrz również notatka ( * ) poniżej). Należy jednak pamiętać, że kolejność ma tu znaczenie, a Sekwencja LFENCE SFENCE nie ma tej samej synergii efekt.

Choć można powiedzieć, że MFENCE ~ SFENCE LFENCE i LFENCE ~ NOP, to nie oznacza to MFENCE ~ SFENCE. Celowo używam równoważności ( ~ ), a nie równości ( = ), aby podkreślić, że reguły arytmetyczne nie mają tu zastosowania. Wzajemny efekt SFENCE, po którym następuje LFENCE, czyni różnicę; nawet jeśli ładunki nie są ze sobą zmieniane, LFENCE jest wymagane, aby zapobiec ponownemu uporządkowaniu ładunków za pomocą SFENCE.

( * ) nadal może być poprawne stwierdzenie, że MFENCE jest silniejsza niż kombinacja dwóch pozostałych ogrodzenia. W szczególności, uwaga do instrukcji CLFLUSH w tomie 2 podręcznika Intela mówi, że "CLFLUSH jest uporządkowana tylko przez instrukcję MFENCE. Nie ma gwarancji, że zostanie zamówiony przez inne instrukcje ogrodzenia lub serializacji lub przez inną instrukcję CLFLUSH."

(Update, clflush jest teraz zdefiniowany jako silnie uporządkowany (jak normalny sklep, więc potrzebujesz tylko mfence, jeśli chcesz zablokować później ładunki ), ale clflushopt jest słabo uporządkowany, ale może być ogrodzony przez sfence.)

 29
Author: Alexey Kukanov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 10:22:52

Rozważ następujący scenariusz - jest to krytyczny przypadek, w którym wykonanie obciążenia spekulacyjnego może teoretycznie zaszkodzić spójności sekwencyjnej

Początkowo [x]=[y] = 0

CPU0:                              CPU1: 
store [x]<--1                      store [y]<--1
load  r1<--[y]                     load r2<--[x]

Ponieważ x86 pozwala na zmianę kolejności ładowań z wcześniejszymi magazynami na różne adresy, oba ładunki mogą zwracać 0 ' s. dodanie lfence po każdym sklepie nie zapobiegnie temu, ponieważ uniemożliwiają one tylko zmianę kolejności w tym samym kontekście, ale ponieważ sklepy są wysyłane po przejściu na emeryturę, możesz mieć oba lfences i oba ładunki zobowiązują się przed wykonaniem i obserwacją zapasów.

An mfence z drugiej strony wymusiłoby działanie sklepów i dopiero wtedy umożliwiłoby wykonanie obciążeń, więc zaktualizowane dane będą wyświetlane w co najmniej jednym kontekście.

A co do sfences - jak zaznaczono w komentarzu, teoretycznie nie jest wystarczająco mocny, aby zapobiec ponownemu uporządkowaniu obciążenia nad nim, więc może nadal odczytywać nieświeże dane. Chociaż jest to prawdą, jeśli chodzi o oficjalną pamięć obowiązują zasady porządkowania, uważam, że obecna implementacja uarch x86 czyni go nieco silniejszym(choć chyba nie zobowiązując się do tego w przyszłości). Według tego opisu :

Ze względu na silny model zamawiania x86 bufor ładowania jest snooped przez coherence traffic. Sklep zdalny musi unieważnić wszystkie inne kopie linii pamięci podręcznej. Jeśli linia cache jest odczytywana przez load, a następnie unieważnione przez zdalny sklep, obciążenie musi zostać anulowane, ponieważ potencjalnie odczytać nieprawidłowe dane. Model pamięci x86 nie wymaga sprawdzam bufor sklepu.

Dlatego każde obciążenie, które nie zostało jeszcze popełnione w maszynie, powinno być przechwytywane przez sklepy z innych rdzeni, co sprawia, że efektywny czas obserwacji obciążenia w punkcie commit , a nie wykonanie (co rzeczywiście jest nie w porządku i mogło być wykonane znacznie wcześniej). Commit jest wykonywany w kolejności, dlatego obciążenie powinno być przestrzegane po poprzednich instrukcjach-czyniąc lfences prawie bezużytecznymi, jak powiedziałem powyżej w komentarzach, ponieważ spójność można utrzymać w ten sam sposób bez nich. Jest to głównie spekulacja, próbując wyjaśnić powszechną koncepcję, że lfencje są bez znaczenia w x86 - nie jestem do końca pewien, skąd pochodzą i czy są inne względy pod ręką - chętnie, aby każdy ekspert zatwierdził / zakwestionował tę teorię.

Wszystko powyższe dotyczy tylko typów WB mem kurs

 7
Author: Leeor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-02 16:17:06

Oczywiście, że sence!

LFENCE z Intel datasheet:

Wykonuje operację serializacji na wszystkich instrukcjach load-from-memory które zostały wydane przed wydaniem instrukcji LFENCE. Ten serializujący działanie gwarantuje, że każda instrukcja obciążenia poprzedzająca w kolejność programu Instrukcja LFENCE jest globalnie widoczna przed jakimkolwiek instrukcja load podążająca za instrukcją LFENCE jest globalnie widoczne.

Instrukcja zapisu Pamięci jak MOV są atomowe, jeśli są odpowiednio wyrównane. Ale ta instrukcja jest normalnie wykonywana w pamięci podręcznej procesora i nie będzie globalnie widoczna w tym momencie dla wszystkich innych wątków, ponieważ pamięć LFENCE/SFENCE or MFENCE musi być preformowana jako pierwsza.

Typowy przypadek:

Jeśli thread writer odblokuje obszar pamięci z instrukcją zapisu, taką jak memory aligned MOV, więc nie jest używana Instrukcja prefiksu LOCK, niż linia bufora, w której została utworzona MOV, będzie widoczna w bardzo krótkim czasie dla wszystkich innych wątków. LFENCE upewnij się do czytnika wątków, że również wszystkie inne linie pamięci podręcznej z thread writer są globalnie visibe !

 -1
Author: GJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-01 21:09:14