Instrukcje SSE: które procesory mogą wykonywać operacje na pamięci atomic 16B?
Rozważ pojedynczy dostęp do pamięci (pojedynczy odczyt lub pojedynczy zapis, a nie Odczyt+Zapis) Instrukcja SSE na procesorze x86. Instrukcja uzyskuje dostęp do 16 bajtów (128 bitów) pamięci, a dostęp do lokalizacji pamięci jest wyrównany do 16 bajtów.
Dokument "Intel® 64 Architecture Memory Ordering White Paper" stwierdza, że dla "instrukcji odczytywających lub zapisujących quadword (8 bajtów), którego adres jest wyrównany na granicy 8 bajtów" operacja pamięci wydaje się być wykonywana jako pojedynczy dostęp do pamięci niezależnie od typu pamięci.
Pytanie: czy istnieją procesory Intel/AMD/etc x86, które gwarantują, że odczyt lub zapis 16 bajtów (128 bitów) wyrównanych do granicy 16 bajtów jest wykonywany jako pojedynczy dostęp do pamięci? jest tak, który konkretny typ PROCESORA to jest (Core2 / Atom/K8 / Phenom/...)? Jeśli podasz odpowiedź (Tak/nie) na to pytanie, proszę również podać metodę , która została użyta do określenia odpowiedzi - wyszukiwanie dokumentów PDF, testowanie brute force, dowód matematyczny lub cokolwiek innego inną metodą, której użyłeś do ustalenia odpowiedzi.
To pytanie dotyczy problemów takich jak http://research.swtch.com/2010/02/off-to-races.html
Aktualizacja:
Stworzyłem prosty program testowy w języku C, który można uruchomić na komputerach. Skompiluj i uruchom go na swoim Phenomie, Athlonie, Bobcat, Core2, atomie, Sandy Bridge lub jakimkolwiek innym procesorze obsługującym SSE2. Dzięki.
// Compile with:
// gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.
#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;
unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));
void* thread1(void *arg) {
for (int i=0; i<100*1000*1000; i++) {
int mask = _mm_movemask_ps((__m128)x);
n1[mask]++;
x = (v4si){0,0,0,0};
}
return NULL;
}
void* thread2(void *arg) {
for (int i=0; i<100*1000*1000; i++) {
int mask = _mm_movemask_ps((__m128)x);
n2[mask]++;
x = (v4si){-1,-1,-1,-1};
}
return NULL;
}
int main() {
// Check memory alignment
if ( (((uintptr_t)&x) & 0x0f) != 0 )
abort();
memset(n1, 0, sizeof(n1));
memset(n2, 0, sizeof(n2));
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
for (unsigned i=0; i<16; i++) {
for (int j=3; j>=0; j--)
printf("%d", (i>>j)&1);
printf(" %10u %10u", n1[i], n2[i]);
if(i>0 && i<0x0f) {
if(n1[i] || n2[i])
printf(" Not a single memory access!");
}
printf("\n");
}
return 0;
}
PROCESOR, który mam w notebooku to Core Duo (nie Core2). To procesor nie przeszedł testu, implementuje 16-bajtową pamięć odczytu/zapisu z ziarnistością 8 bajtów. Wyjście to:
0000 96905702 10512
0001 0 0
0010 0 0
0011 22 12924 Not a single memory access!
0100 0 0
0101 0 0
0110 0 0
0111 0 0
1000 0 0
1001 0 0
1010 0 0
1011 0 0
1100 3092557 1175 Not a single memory access!
1101 0 0
1110 0 0
1111 1719 99975389
6 answers
[[7]}W Intel® 64 i IA-32 architectures Developer ' s Manual: Vol. 3A , która obecnie zawiera specyfikacje białej księgi zamówień pamięci, o której wspomniałeś, mówi się w sekcji 8.2.3.1, jak sam zauważyłeś, że
The Intel-64 memory ordering model guarantees that, for each of the following memory-access instructions, the constituent memory operation appears to execute as a single memory access: • Instructions that read or write a single byte. • Instructions that read or write a word (2 bytes) whose address is aligned on a 2 byte boundary. • Instructions that read or write a doubleword (4 bytes) whose address is aligned on a 4 byte boundary. • Instructions that read or write a quadword (8 bytes) whose address is aligned on an 8 byte boundary. Any locked instruction (either the XCHG instruction or another read-modify-write instruction with a LOCK prefix) appears to execute as an indivisible and uninterruptible sequence of load(s) followed by store(s) regardless of alignment.
Teraz, ponieważ Powyższa lista nie zawiera tego samego języka dla podwójnego czworokąta (16 bajtów), wynika z tego, że architektura nie gwarantuje, że instrukcje, które mają dostęp do 16 bajtów pamięci, są atomowe.
To powiedziawszy, ostatni akapit podpowiada wyjście, a mianowicie instrukcję CMPXCHG16B z prefiksem blokady. Możesz użyć instrukcji CPUID, aby dowiedzieć się, czy twój procesor obsługuje CMPXCHG16B (bit funkcji "CX16").
W odpowiednim dokumencie AMD, amd64 Technology AMD64 Architecture Programmer ' s Manual Volume 2: System Programming , nie mogę znaleźć podobnego przejrzystego języka.
EDIT: test program results
(Program testowy zmodyfikowany w celu zwiększenia # iteracji przez współczynnik 10)
Na Xeon X3450 (x86-64):
0000 999998139 1572 0001 0 0 0010 0 0 0011 0 0 0100 0 0 0101 0 0 0110 0 0 0111 0 0 1000 0 0 1001 0 0 1010 0 0 1011 0 0 1100 0 0 1101 0 0 1110 0 0 1111 1861 999998428
Na Xeon 5150 (32-bit):
0000 999243100 283087 0001 0 0 0010 0 0 0011 0 0 0100 0 0 0101 0 0 0110 0 0 0111 0 0 1000 0 0 1001 0 0 1010 0 0 1011 0 0 1100 0 0 1101 0 0 1110 0 0 1111 756900 999716913
Na opteronie 2435 (x86-64):
0000 999995893 1901 0001 0 0 0010 0 0 0011 0 0 0100 0 0 0101 0 0 0110 0 0 0111 0 0 1000 0 0 1001 0 0 1010 0 0 1011 0 0 1100 0 0 1101 0 0 1110 0 0 1111 4107 999998099
Czy to oznacza, że Intel i / lub AMD gwarantują, że 16-bajtowy dostęp do pamięci jest atomowy na tych maszynach? IMHO, nie ma. Nie ma go w dokumentacji jako gwarantowanego zachowania architektonicznego, a zatem nie można wiedzieć, czy na tych konkretnych procesorach 16-bajtowy dostęp do pamięci jest naprawdę atomowy, czy program testowy tylko nie uruchamia ich z tego czy innego powodu. A zatem poleganie na nim jest niebezpieczne.
EDIT 2: Jak sprawić, by program testowy nie powiódł się
Ha! Udało mi się doprowadzić program do niepowodzenia. Na tym samym Opteron 2435 jak wyżej, z tym samym binarnym, ale teraz uruchamiając go za pomocą narzędzia "numactl" określającego, że każdy wątek działa na osobnym gnieździe, otrzymałem:0000 999998634 5990 0001 0 0 0010 0 0 0011 0 0 0100 0 0 0101 0 0 0110 0 0 0111 0 0 1000 0 0 1001 0 0 1010 0 0 1011 0 0 1100 0 1 Not a single memory access! 1101 0 0 1110 0 0 1111 1366 999994009Więc co to oznacza? Cóż, Opteron 2435 może, lub nie, zagwarantować, że 16-bajtowy dostęp do pamięci będzie atomic dla dostępu wewnątrz gniazd, ale przynajmniej protokół Cache działający na interkonekcie HyperTransport między dwoma gniazdami nie daje takiej gwarancji.
Edycja 3: ASM dla funkcji wątku, na życzenie "GJ."
W tym artykule omówiono funkcje wątku dla GCC 4.4 x86-64 w systemie Opteron 2435:]}
.globl thread2
.type thread2, @function
thread2:
.LFB537:
.cfi_startproc
movdqa .LC3(%rip), %xmm1
xorl %eax, %eax
.p2align 5,,24
.p2align 3
.L11:
movaps x(%rip), %xmm0
incl %eax
movaps %xmm1, x(%rip)
movmskps %xmm0, %edx
movslq %edx, %rdx
incl n2(,%rdx,4)
cmpl $1000000000, %eax
jne .L11
xorl %eax, %eax
ret
.cfi_endproc
.LFE537:
.size thread2, .-thread2
.p2align 5,,31
.globl thread1
.type thread1, @function
thread1:
.LFB536:
.cfi_startproc
pxor %xmm1, %xmm1
xorl %eax, %eax
.p2align 5,,24
.p2align 3
.L15:
movaps x(%rip), %xmm0
incl %eax
movaps %xmm1, x(%rip)
movmskps %xmm0, %edx
movslq %edx, %rdx
incl n1(,%rdx,4)
cmpl $1000000000, %eax
jne .L15
xorl %eax, %eax
ret
.cfi_endproc
I dla kompletności .LC3, czyli dane statyczne zawierające wektor (-1, -1, -1, -1) użyty przez thread2:
.LC3:
.long -1
.long -1
.long -1
.long -1
.ident "GCC: (GNU) 4.4.4 20100726 (Red Hat 4.4.4-13)"
.section .note.GNU-stack,"",@progbits
Zauważ również, że jest to składnia AT & T ASM, a nie Programiści Windows Intel syntax mogą być bardziej zaznajomieni z tą składnią. Na koniec, jest to z march = native, co sprawia, że GCC preferuje MOVAPS; ale to nie ma znaczenia, jeśli użyję March = core2 to użyje MOVDQA do przechowywania na X, I nadal mogę odtworzyć błędy.
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
2011-10-07 13:05:51
"AMD Architecture Programmer' s Manual Volume 1: Application Programming" mówi w sekcji 3.9.1: "CMPXCHG16B
może być używany do wykonywania 16-bajtowego dostępu atomowego w trybie 64-bitowym (z pewnymi ograniczeniami wyrównania)."
Nie ma jednak takiego komentarza na temat instrukcji SSE. W rzeczywistości w 4.8.3 jest komentarz, że prefiks blokady "powoduje wyjątek nieprawidłowego kodu opcode, gdy jest używany z 128-bitowymi instrukcjami multimedialnymi". Dlatego wydaje mi się dość rozstrzygające, że AMD procesory nie gwarantują atomic 128-bitowego dostępu dla instrukcji SSE, a jedynym sposobem na uzyskanie atomic 128-bitowego dostępu jest użycie CMPXCHG16B
.
" Intel 64 And IA-32 Architectures Software Developer ' s Manual Volume 3A: System Programming Guide, Part 1" mówi w 8.1.1 "Instrukcja x87 lub Instrukcja SSE, która uzyskuje dostęp do danych większych niż quadword, może być zaimplementowana przy użyciu wielu dostępów do pamięci."Jest to dość rozstrzygające, że 128-bitowe instrukcje SSE nie są gwarantowane atomic przez ISA. Tom 2a dokumentów Intela mówi o CMPXCHG16B
: "instrukcja ta może być używana z prefiksem blokady, aby umożliwić wykonanie instrukcji atomicznie."
Ponadto producenci procesorów nie opublikowali pisemnych gwarancji operacji atomic 128B SSE dla określonych modeli procesorów, gdzie tak jest.
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
2015-10-10 04:14:24
W podręczniku architektury Intel Vol 3A. sekcja 8.1.1 (maj 2011), pod sekcją gwarantowane operacje atomowe, znajduje się Ostrzeżenie:
Instrukcja x87 lub Instrukcja SSE, która uzyskuje dostęp do danych większych quadword może być zaimplementowany przy użyciu wielu dostępów do pamięci. Jeśli taka instrukcja przechowuje w pamięci, niektóre z dostępów mogą zakończyć (zapis do pamięci), podczas gdy inna powoduje, że operacja usterka ze względów architektonicznych (np. z powodu page-table entry that is oznaczony jako "not present"). W tym przypadku skutki zrealizowanego dostęp może być widoczny dla oprogramowania, nawet jeśli ogólnie Instrukcja spowodowała błąd. Jeśli unieważnienie TLB zostało opóźnione (patrz 4.10.4.4), takie błędy strony mogą wystąpić, nawet jeśli wszystkie dostępy są do tej samej strony.
Tak więc instrukcje SSE nie są gwarantowane jako atomowe, nawet jeśli bazowa Architektura używa pojedynczego dostępu do pamięci (jest to jeden z powodów, dla których pamięć wprowadzono szermierkę).
Połącz to z tym stwierdzeniem z podręcznika optymalizacji Intel, sekcja 13.3 (kwiecień 2011)
Instrukcje AVX i FMA nie wprowadzają żadnych nowych gwarantowanych atomów operacje pamięci.
I fakt, że żadna z operacji load lub store dla SIMD nie gwarantuje atomiczności, możemy dojść do wniosku, że Intel nie obsługuje żadnej formy atomic SIMD (jeszcze).
Jako dodatkowy bit, jeśli pamięć jest dzielona wzdłuż bufora linie lub granice stron (przy użyciu rzeczy takich jak movdqu
, które pozwalają na dostęp bez wyrównania), następujące procesory będą nie wykonywać dostęp atomowy, niezależnie od wyrównania, ale późniejsze procesory będą (ponownie z podręcznika architektury Intel):
Intel Core 2 Duo, Intel ® Atom™, Intel Core Duo, Pentium M, Pentium 4, Procesory Intel Xeon, rodziny P6, Pentium i Intel486. Intel Core 2 Duo, Intel Atom, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon i P6 Rodzina procesorów
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
2011-10-07 11:02:58
ISA x86 nie gwarantuje atomiczności dla niczego większego niż 8B, więc implementacje są wolne od implementacji SSE / AVX obsługują sposób, w jaki Pentium III / Pentium M / Core Duo: wewnętrzne dane są obsługiwane w połówkach 64-bitowych. 128-bitowy sklep odbywa się jako dwa 64-bitowe sklepy. Ścieżka danych do / z pamięci podręcznej ma tylko 64B szerokości w mikroarchitekturze Yonah (Core Duo). (Źródło: mikroarchitektura Agnera Foga ).
Nowsze implementacje czy mają szersze ścieżki danych Core 2 Duo (conroe/merom) był pierwszym mikroprocesorem Intela P6 ze ścieżkami danych 128b. (IDK o P4, ale na szczęście jest na tyle stary, że zupełnie nieistotny.)
Dlatego OP stwierdza, że 128b ops nie są atomowe na Intel Core Duo (Yonah), ale inne plakaty stwierdzają, że są atomowe na późniejszych projektach Intela, począwszy od Core 2 (Merom).
Diagramy na tym Realworldtech piszą o Merom vs. Yonah pokazuje 128-bitową ścieżkę pomiędzy ALU i L1 data-cache w Merom (i P4), podczas gdy Yonah o niskiej mocy ma 64-bitową ścieżkę danych. Ścieżka danych między L1 i L2 cache jest 256b we wszystkich 3 projektach.
[1]}kolejnym skokiem w szerokości ścieżki danych był Intel Haswell, wyposażony w 256b (32B) AVX/AVX2 loads/stores i 64byte ścieżkę między L1 i L2 cache. Spodziewam się, że ładunki/sklepy 256b są atomowe w Haswell, Broadwell i Skylake, ale nie mam żadnego do przetestowania. I forget if Skylake ponownie poszerzył ścieżki w przygotowaniu do AVX512 w Skylake-EP (wersja serwera), lub jeśli być może początkowa implementacja AVX512 będzie jak SNB/IvB AVX, i mają 512B obciążenia / sklepy zajmują port obciążenia / store dla 2 cykli.Jak podkreśla janneb w swojej doskonałej, eksperymentalnej odpowiedzi, protokół spójności pamięci podręcznej między gniazdami w systemie wielordzeniowym może być węższy niż ten, który można uzyskać w CPU shared-last-level-cache. Nie ma wymagań architektonicznych na atomiczność dla szerokich obciążeń/sklepów, więc projektanci mogą je dowolnie tworzyć atomowe w gnieździe, ale niematomiczne w gniazdach, jeśli jest to wygodne. IDK jak szeroka jest logiczna ścieżka danych między gniazdami dla rodziny bulldozer AMD lub dla Intela. (Mówię "logiczne", ponieważ nawet jeśli dane są przesyłane w mniejszych kawałkach, może to nie zmodyfikować linii pamięci podręcznej, dopóki nie zostanie w pełni odebrana.)
Znalezienie podobnych artykułów na temat procesorów AMD powinno pozwolić na wyciągnięcie rozsądnych wniosków na temat tego, czy 128b operacje są atomowe lub nie. Po prostu sprawdzanie tabel instrukcji jest pewną pomocą:
K8 dekoduje movaps reg, [mem]
do 2 m-op, podczas gdy K10 i bulldozer-family dekodują go do 1 m-op. mała moc AMD bobcat dekoduje go do 2 ops, podczas gdy jaguar dekoduje 128b movaps do 1 m-op. (obsługuje AVX1 podobne do procesorów z rodziny bulldozer: 256b insns (nawet ALU ops) są podzielone na dwa 128B ops. Intel SnB dzieli tylko ładunki/sklepy 256b, mając jednocześnie ALUS o pełnej szerokości.)
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
2015-10-13 02:53:32
EDIT: W ciągu ostatnich dwóch dni zrobiłem kilka testów na moich trzech komputerach i nie odtworzyłem żadnego błędu pamięci, więc nie mogę powiedzieć nic dokładniej. Może ten błąd pamięci jest również zależny od systemu operacyjnego.
EDIT: Programuję w Delphi, a nie w C, ale powinienem zrozumieć C. Więc przetłumaczyłem kod, tutaj masz procedury wątków, w których główna część jest wykonana w asemblerze:
procedure TThread1.Execute;
var
n :cardinal;
const
ConstAll0 :array[0..3] of integer =(0,0,0,0);
begin
for n := 0 to 100000000 do
asm
movdqa xmm0, dqword [x]
movmskps eax, xmm0
inc dword ptr[n1 + eax *4]
movdqu xmm0, dqword [ConstAll0]
movdqa dqword [x], xmm0
end;
end;
{ TThread2 }
procedure TThread2.Execute;
var
n :cardinal;
const
ConstAll1 :array[0..3] of integer =(-1,-1,-1,-1);
begin
for n := 0 to 100000000 do
asm
movdqa xmm0, dqword [x]
movmskps eax, xmm0
inc dword ptr[n2 + eax *4]
movdqu xmm0, dqword [ConstAll1]
movdqa dqword [x], xmm0
end;
end;
Wynik: żadnego błędu na moim quad core PC i nie błąd na moim dwurdzeniowym komputerze zgodnie z oczekiwaniami!
- komputer z procesorem Intel Pentium4
- komputer z procesorem Intel Core2 Quad Q6600
- komputer z procesorem Intel Core2 Duo P8400
Czy możesz pokazać, jak debuger widzi kod procedury wątku? Proszę...
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-10-19 04:09:16
Do tej pory zamieszczono wiele odpowiedzi i stąd wiele informacji jest już dostępnych(jako efekt uboczny dużo zamieszania). Chciałbym przedstawić fakty z podręcznika Intela dotyczące gwarantowanych operacji atomowych ...
W najnowszych procesorach Intela z rodziny nehalem i sandy bridge gwarantowany jest odczyt lub zapis do quadworda wyrównanego do granicy 64 bitów.
Nawet niepodpisane 2, 4 lub 8 bajtowe odczyty lub zapisy są gwarantowane jako atomowe, pod warunkiem, że są pamięci podręcznej i zmieścić się w linii pamięci podręcznej.
Powiedziawszy, że test zamieszczony w tym pytaniu przechodzi na procesor Intel i5 oparty na sandy bridge.
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
2011-10-10 10:46:43