Pytanie Operacje atomowe i generowanie kodu dla gcc


Zwalczam patrzenie na jakiś zestaw generowany dla operacji atomowych przez gcc. Próbowałem następującej krótkiej sekwencji:

int x1;
int x2;

int foo;

void test()
{
  __atomic_store_n( &x1, 1, __ATOMIC_SEQ_CST );
  if( __atomic_load_n( &x2  ,__ATOMIC_SEQ_CST ))
    return;

  foo = 4;
}

Patrząc na atomową broń Herba Suttera na temat generowania kodu, wspomina, że ​​instrukcja obsługi X86 ma zastosowanie xchg dla magazynów atomowych i prosty mov dla odczytów atomowych. Tak więc spodziewałem się czegoś w rodzaju:

test():
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $1, %eax
    xchg    %eax, x1(%rip)
    movl    x2(%rip), %eax
    testl   %eax, %eax
    setne   %al
    testb   %al, %al
    je      .L2
    jmp     .L1
.L2:
    movl    $4, foo(%rip)
.L1:
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

Gdzie ogrodzenie pamięci jest niejawne z powodu zablokowania xchg instrukcja.

Jednak jeśli skompiluję to przy użyciu gcc -march=core2 -S test.cc Otrzymuję następujące informacje:

test():
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $1, %eax
    movl    %eax, x1(%rip)
    mfence
    movl    x2(%rip), %eax
    testl   %eax, %eax
    setne   %al
    testb   %al, %al
    je      .L2
    jmp     .L1
.L2:
    movl    $4, foo(%rip)
.L1:
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

Więc zamiast używać a xchg Operacja gcc tutaj używa a mov + mfence połączenie. Jaki jest powód tego generowania kodu, który różni się od tego wymaganego przez architekturę x86 według Herba Sutter?


11
2018-03-09 13:18


pochodzenie




Odpowiedzi:


The xchg instrukcja zakłada semantykę blokującą, gdy miejscem docelowym jest lokalizacja w pamięci. Oznacza to, że możesz zamienić zawartość rejestru na atomową zawartość zawartości pamięci.

Przykładem tego pytania jest tworzenie magazynu atomowego, a nie zamiany. Model pamięci architektury x86 gwarantuje, że w systemie wieloprocesorowym / wielordzeniowym zapasy wykonane przez jeden wątek będą widoczne w tej kolejności przez inne wątki ... dlatego ruch pamięci jest wystarczający. Powiedziawszy to, istnieją starsze procesory Intela i niektóre klony, w których występują błędy w tym obszarze, oraz xchg jest wymagany jako obejście tych procesorów. Zobacz sekcję Ważne optymalizacje tego artykułu wikipedii na temat spinlocków:

http://en.wikipedia.org/wiki/Spinlock#Example_implementation

Które stany

Powyższa prosta implementacja działa na wszystkich procesorach korzystających z architektury x86. Możliwych jest jednak kilka optymalizacji wydajności:

Na późniejszych implementacjach architektury x86, spin_unlock może bezpiecznie użyć odblokowanego MOV zamiast wolniej zablokowanego XCHG. Wynika to z subtelnych zasad porządkowania pamięci, które je obsługują, nawet jeśli MOV nie jest pełną barierą pamięci. Jednak niektóre procesory (niektóre procesory Cyrix, niektóre wersje Intel Pentium Pro (z powodu błędów) i wcześniejsze systemy Pentium i i486) zrobią coś złego, a dane chronione przez blokadę mogą zostać uszkodzone. W większości architektur innych niż x86 należy użyć jawnej bariery pamięci lub instrukcji atomowych (jak w przykładzie). W niektórych systemach, takich jak IA-64, istnieją specjalne instrukcje "odblokowania", które zapewniają wymaganą kolejność pamięci.

Bariera pamięci, mfence, zapewnia, że ​​wszystkie sklepy zostały ukończone (bufory magazynowe w rdzeniu procesora są puste, a wartości przechowywane w pamięci podręcznej lub w pamięci), ale także zapewnia, że ​​żadne przyszłe obciążenia nie są wykonywane.

Fakt, że plik MOV jest wystarczający do odblokowania muteksu (bez konieczności serializacji lub zapełnienia pamięci) został "oficjalnie" wyjaśniony w odpowiedzi na Linusa Torvaldsa przez architekta firmy Intel w 1999 r.

http://lkml.org/lkml/1999/11/24/90.

Domyślam się, że później okazało się, że nie działa dla niektórych starszych procesorów x86.


9
2018-03-09 13:55