Forum: PC-Programmierung Kopieren von 64bit werten unterbrechbar?


von alex (Gast)


Lesenswert?

Hallo Zusammen,

ich habe einen Shared-Memory-bereich, der von zwei Programmen aus 
manipiliert werden kann. Es sollen 64 bit Werte in diesen Bereich 
geschrieben und gelesen werden. Die Frage die sich mir stellt: werden 
die 64 bit in einem Rutsch geschrieben/gelesen, oder 2x32Bit? Wenn 2 x 
32 Bit geschrieben werden, ist der kopierbefehl unterbrechbar? Ich habe 
einen Intel Core 2 Duo mit 32bit Windows XP.

Schon mal im Voraus vielen Dank für die Antworten!

Gruß Alex

von (prx) A. K. (prx)


Lesenswert?

alex schrieb:

> geschrieben und gelesen werden. Die Frage die sich mir stellt: werden
> die 64 bit in einem Rutsch geschrieben/gelesen, oder 2x32Bit?

Skalar: Normale Integers in zwei, Fliesskomma/MMX/SSE in einem Zugriff.

memcpy&Co: implementierungsabhängig.

> 32 Bit geschrieben werden, ist der kopierbefehl unterbrechbar?

Ja.

von Tobi (Gast)


Lesenswert?

Moin,

diese Operation ist im Falle eines 32-Bit Systems auf jedenfall NICHT 
Atomar, kann also unterbrochen werden.

von (prx) A. K. (prx)


Lesenswert?

Kleiner Tipp noch, wenn Performance eine Rolle spielt: Wenn beide 
Threads sehr oft auf den gleichen Platz (64 Byte Cache-Line) dieses 
Speichers zugreifen, dann kann schönstes Chache-Pingpong entstehen und 
beide erheblich abbremsen.

von alex (Gast)


Lesenswert?

Es sind Fließkomma Zahlen. Verstehe ich das jetzt richtig, dass da kein 
Interrupt dazwischen kommen kann?

von Peter (Gast)


Lesenswert?

>Kleiner Tipp noch, wenn Performance eine Rolle spielt: Wenn beide
>Threads sehr oft auf den gleichen Platz (64 Byte Cache-Line) dieses
>Speichers zugreifen, dann kann schönstes Chache-Pingpong entstehen und
>beide erheblich abbremsen.

Kann man das vermeiden, indem der gemeinsame MEM-Bereich auf volatile 
gesezt wird?

von (prx) A. K. (prx)


Lesenswert?

alex schrieb:

> Es sind Fließkomma Zahlen. Verstehe ich das jetzt richtig, dass da kein
> Interrupt dazwischen kommen kann?

Korrekt.

von ... .. (docean) Benutzerseite


Lesenswert?

alex schrieb:
> Es sind Fließkomma Zahlen. Verstehe ich das jetzt richtig, dass da kein
> Interrupt dazwischen kommen kann?

ob das nun 64bit ints oder floats sind ist dem rechner egal... der 
zugriff auf 64 bitt dauert immer länger als einen takt daher ist das 
unterbrechbar

(von Sondersachen wie MMX, SEE Befehale mal abgesehn)

von Klaus W. (mfgkw)


Lesenswert?

Peter schrieb:
>>Kleiner Tipp noch, wenn Performance eine Rolle spielt: Wenn beide
>>Threads sehr oft auf den gleichen Platz (64 Byte Cache-Line) dieses
>>Speichers zugreifen, dann kann schönstes Chache-Pingpong entstehen und
>>beide erheblich abbremsen.
>
> Kann man das vermeiden, indem der gemeinsame MEM-Bereich auf volatile
> gesezt wird?

volatile hat eine andere Bedeutung.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Kann man das vermeiden, indem der gemeinsame MEM-Bereich auf volatile
> gesezt wird?

Das musst du sowieso.

Am Problem ändert das aber nichts. Wer schreibt, der wird (bei Intel 
Core 2) exklusiver Besitzer dieser einen Cache-Line. Da beisst die Maus 
keinen Faden ab. Wenn dann der andere Core daraus liest, dann gibt's 
Zusatzaufwand, der 2-3stellige Takte kosten kann. Wie das beim Core 2 
Duo exakt abläuft habe ich nicht parat, bei Dualcore fängt das 
wahrscheinlich der gemeinsame L2 Cache ab, bei den Dual-Die Quadcores 
dürfte das je nach Lokation der Threads als Höchststrafe ablaufen, d.h. 
über den DRAM-Speicher.

PS: Das ist je nach Implementierung ein bischen anders. AMD anders als 
Intel, Core 2 anders als Core i, usw.

von alex (Gast)


Lesenswert?

Hmm, jetzt steht Aussage gegen Aussage:
prx meint, es ist Atomar, docean mein, es ist nicht... was nun?

von Εrnst B. (ernst)


Lesenswert?

alex schrieb:
> Hmm, jetzt steht Aussage gegen Aussage:
> prx meint, es ist Atomar, docean mein, es ist nicht... was nun?

Gegenfrage:

Kennst du den Zielrechner genau, und kannst 100%ig ausschliessen, dass 
die Software jemals auf einem anderen Rechner läuft?
Nein? => Geh davon aus dass es nicht atomar ist.

Willst du dich mit Inline-ASM oder SSE-Intrinsics auseinandersetzen?
Ja? => setz SSE vorraus, und implementier dir den atomaren Zugriff 
selber.

von U.R. Schmitt (Gast)


Lesenswert?

Wie hochperformant muss das sein?
Wie kritisch ist das?
Ein shared Memory ist oft (ich sage NICHT immer) ein Zeichen eines 
schlechten Designs.
Es gibt in Windows und allen anderen modernen Betriebssystemen deutlich 
besser strukturierte Möglichkeiten zur Interprozesskommunikation und 
Synchronisation.
Shared Memory würde ich nur im absoluten Notfall (kritische Performance) 
benutzen und mich dann wenn irgendmöglich über eine kleine API drumherum 
so absichern, daß zu einer Zeit nur einer draufzugreifen kann. Und vor 
allem würde ich mich NICHT auf spezielle Eigenarten eines Prozessors 
oder einer Prozessorlinie verlassen, was tust Du wenn Du in 2 Jahren 
einen AMD Rechner bekommst?
just my 2 cent
Gruß

von (prx) A. K. (prx)


Lesenswert?

... ... schrieb:

> ob das nun 64bit ints oder floats sind ist dem rechner egal...

Keineswegs. 64bit Integers werden bei 32-Bit x86 in getrennten 
Lade/Speicherbefehlen abgewickelt und sind damit unterbrechbar. So kann 
es vorkommen, dass ein paralleler Thread teils alte teils neue Daten 
sieht. Anders sieht das bei Integers erst mit x64 aus.

64bit x87/MMX/SSE Daten jedoch werden mit einer einzelnen 
Speicheroperation geladen/gespeichert. Vorausgesetzt sie sind aligned, 
d.h. die Adresse ist durch 8 teilbar.

> zugriff auf 64 bitt dauert immer länger als einen takt daher ist das
> unterbrechbar

Ein einzelner Lese- oder Schreibzugriff ist bezogen auf diese 
Speicherstelle atomar, egal ob er einen Takt oder 100 Takte benötigt. Es 
kann nicht geschehen, dass ein parallel laufender skalarer Zugriff auf 
die gleiche Speicherstelle teils alte teils neue Daten erhält.

von Klaus W. (mfgkw)


Lesenswert?

Genau.
Und damit kommt man der Sache doch gleich näher:
Kompilieren, ansehen was der Compiler an Code erzeugt und
schon hat man die Befehle, um die es geht.
Vorher kann man wohl wenig aussagen.

von alex (Gast)


Lesenswert?

Εrnst B✶ schrieb:
> Kennst du den Zielrechner genau, und kannst 100%ig ausschliessen, dass
> die Software jemals auf einem anderen Rechner läuft?
> Nein? => Geh davon aus dass es nicht atomar ist.

Ich kann es nicht ausschließen, aber ich könnte es evtl. vorgeben :-)

> Willst du dich mit Inline-ASM oder SSE-Intrinsics auseinandersetzen?
> Ja? => setz SSE vorraus, und implementier dir den atomaren Zugriff
> selber.
Natürlich will ich so wenig Aufwand wie möglich treiben, aber wenn das 
der einzige vernünftige und sichere weg ist... warum nicht.

U.R. Schmitt schrieb:
> Es gibt in Windows und allen anderen modernen Betriebssystemen deutlich
> besser strukturierte Möglichkeiten zur Interprozesskommunikation und
> Synchronisation.
Das Problem ist, dass ich bestehende Dinge verwenden muss. Ich habe auf 
der einen Seite eine echtzeitfähige SoftSPS, auf der anderen Seite ein 
Windowsprogramm, wo es nicht so zeitkritisch ist. Der einzige 
vernünftige Weg Daten mit der SoftSPS zu tauschen ist ein Shared 
Memory...

Naja, so wies aussieht sollte ich ein kleines Handshake einführen, um 
sicher zu gehen, dass die Daten nicht mal schnell von der SoftSPS 
geändert werden, wenn das Windowsprogramm gerade die Hälfte davon 
gelesen hat...

Danke für die Infos!

von (prx) A. K. (prx)


Lesenswert?

U.R. Schmitt schrieb:

> allem würde ich mich NICHT auf spezielle Eigenarten eines Prozessors
> oder einer Prozessorlinie verlassen, was tust Du wenn Du in 2 Jahren
> einen AMD Rechner bekommst?

Wird weiterhin funktionieren, nur können sich die Optimierungsstrategien 
etwas ändern. Wenn die Laufzeit solcher Codeteile signifikant ist, dann 
lohnt sich Optimierung, wenn nicht kann es egal sein. Atomar sind sie 
innerhalb dieser Maschinenklasse immer, nur die Laufzeit der Operationen 
kann sich ändern.

Wenn man das Programm so schreiben kann, dass es ohne Performanceverlust 
auch ohne gemeinsamem Speicher auskommt, umso besser. Wenn nicht, dann 
kommt man um solche Details nicht herum. Insbesondere weil, wie schon 
skizziert, gemeinsame vs. getrennte Caches einen dramatischen 
Unterschied ausmachen können.

Mancher ist auch bei stinknormalen Programmen bei einem Pentium Pro und 
später Pentium 4 auf den Bauch gefallen, weil Intel bestimmte vorher 
völlig normale Operationsabfolgen massiv bestrafte.

von ... .. (docean) Benutzerseite


Lesenswert?

A. K. schrieb:
> 64bit x87/MMX/SSE Daten jedoch werden mit einer einzelnen
> Speicheroperation geladen/gespeichert. Vorausgesetzt sie sind aligned,
> d.h. die Adresse ist durch 8 teilbar.
>
>> zugriff auf 64 bitt dauert immer länger als einen takt daher ist das
>> unterbrechbar
>
> Ein einzelner Lese- oder Schreibzugriff ist bezogen auf diese
> Speicherstelle atomar, egal ob er einen Takt oder 100 Takte benötigt. Es
> kann nicht geschehen, dass ein parallel laufender skalarer Zugriff auf
> die gleiche Speicherstelle teils alte teils neue Daten erhält.

Ich habe doch extra MMX, SSE und Konsorten ausgeschlossen...weil das je 
nach Compiler und Einstellungen des Compilers immer anders aussieht...

Mir ist klar, das ich da die Begriffe Zugriff auf Speicher und Takt ein 
bisschen vereinfacht habe... :D

von (prx) A. K. (prx)


Lesenswert?

... ... schrieb:

> Ich habe doch extra MMX, SSE und Konsorten ausgeschlossen...weil das je
> nach Compiler und Einstellungen des Compilers immer anders aussieht...

Und ich hatte eben deshalb anfangs den Unterschied zwischen Integers und 
Fliesskommadaten erwähnt und bekam als Antwort, dass es sich um 
Fliesskommadaten handelt. Damit war dieser Fall für mich geklärt.

Wenn man die nicht grad misaligned betreibt, dann verarbeiten 
Speicheroperationen auf Daten ab 64 Bits aufwärts dabei immer mindestens 
64 Bit am Stück, egal ob Intel oder AMD, egal ob x87, 3Dnow! oder SSE.

Unterschiede gibt's da erst, wenn man mit 128 Bit SSE arbeitet, weil 
manche Implementierungen diese intern in 2 64-Bit Zugriffe zerlegen, 
andere nicht.

von ... .. (docean) Benutzerseite


Lesenswert?

A. K. schrieb:
> und bekam als Antwort, dass es sich um
> Fliesskommadaten handelt. Damit war dieser Fall für mich geklärt.

und woher wissen wir das der verwendete Compiler die befehle(also 
MMX/SSE) auch verwendet?

von (prx) A. K. (prx)


Lesenswert?

... ... schrieb:

> und woher wissen wir das der verwendete Compiler die befehle(also
> MMX/SSE) auch verwendet?

Weshalb MMX/SSE? Im 32-bit Umfeld ist m.W. nach wie vor x87 üblich, und 
auch da existieren seit jeher 64-bit Lade/Speicherbefehle, die ab 
PPro/K7 auch als 64-bit Operationen arbeiten (davor nicht unbedingt).

Theoretisch ist denkbar, dass ein Compiler zwei 32-bit Integer-Befehle 
verwendet, um einen 64-bit Fliesskommawert von links nach rechts zu 
befördern. Bis ca. 486 war das klar effizienter als FLD/FSTP.

Wenn dieser Compiler aber nicht schon mit Staub von anderthalb 
Jahrzehnten bedeckt ist, dann gehört der Autor dieses Compilers geteert 
und gefedert, weil diese Methode heute grauenhaft ineffizient ist. Denn 
damit hebelt man zumindest die meisten out-of-order Implementierungen 
aus den Angeln. Alle OoO Intel/AMD ab PPro/K7.

Daher habe ich einiges Vertrauen darin, dass Compiler, die für P6 
aufwärts Code erzeugen, auch 64-bit Lade/Speicherbefehle verwenden.

von Andreas F. (aferber)


Lesenswert?

A. K. schrieb:
> Wenn dieser Compiler aber nicht schon mit Staub von anderthalb
> Jahrzehnten bedeckt ist, dann gehört der Autor dieses Compilers geteert
> und gefedert, weil diese Methode heute grauenhaft ineffizient ist.

Wärm schonmal den Teer an ;-)
1
double x;
2
3
extern void f(double);
4
5
void t(void)
6
{
7
        f(x);
8
}
1
00000000 <t>:
2
double x;
3
4
extern void f(double);
5
6
void t(void)
7
{
8
   0:   55                      push   %ebp
9
   1:   89 e5                   mov    %esp,%ebp
10
   3:   83 ec 10                sub    $0x10,%esp
11
        f(x);
12
   6:   ff 35 04 00 00 00       pushl  0x4
13
   c:   ff 35 00 00 00 00       pushl  0x0
14
  12:   e8 fc ff ff ff          call   13 <t+0x13>
15
  17:   83 c4 10                add    $0x10,%esp
16
}
17
  1a:   c9                      leave  
18
  1b:   c3                      ret

Kompiliert mit "gcc -g -Os -march=core2 -c -o fltest.o fltest.c", mit 
"gcc version 4.4.5 20100728 (prerelease) (Debian 4.4.4-8)".

Könnte man ggf. als Optimizer-Bug betrachten, da der Code von "-O2" (mit 
FLD/FSTP) kürzer ist als der von "-Os".

Andreas

von (prx) A. K. (prx)


Lesenswert?

Interessant. Intel hat ja ein paar Optimierungen drin, die 2 Mikroops zu 
einem kombinieren - ob das hier wohl dazugehört? Jedenfalls ist das 
recht bös für AMD und wohl auch andere Intels, deren store queue dann 
beim Versuch leerläuft, in der Funktion auf den Parameter zuzugreifen.

Mit gcc 4.2.4 und k7/pentium4 macht er's jedenfalls nicht so und 
verwendet klassisch FLD/FSTP.

Ich habe hier leider grad keinen gcc 4.4 für x86 rumliegen. Kommt das 
nur bei -march=core2, oder auch bei anderen Varianten wie k8?

von (prx) A. K. (prx)


Lesenswert?

Der Intel Optimization Guide von 2009 erwähnt jedenfalls keine Ausnahme:
1
mov  mem, eax     ; Store dword to address “MEM"
2
mov  mem + 4, ebx ; Store dword to address “MEM + 4"
3
fld  mem          ; Load qword at address “MEM", stalls

von Andreas F. (aferber)


Lesenswert?

A. K. schrieb:
> Interessant. Intel hat ja ein paar Optimierungen drin, die 2 Mikroops zu
> einem kombinieren - ob das hier wohl dazugehört?

Eher nicht. Wie gesagt eher ein Bug oder Seiteneffekt einer anderen 
Optimierung. "-O2" verwendet FLD/FSTP, und der Code ist damit auch 3 
Byte kürzer als der "-Os"-Code.

> Ich habe hier leider grad keinen gcc 4.4 für x86 rumliegen. Kommt das
> nur bei -march=core2, oder auch bei anderen Varianten wie k8?

Der generierte Code ist bei allen "-march"-Varianten, die mein gcc 
kennt, vollkommen identisch.

Bei "-O2" ist die Varianz grösser, FLD/FSTP wird benutzt bei i686, 
pentiumpro, pentium2, pentium3, pentium4, prescott, nocona, core2, 
athlon, athlon-4, k8, k8-sse3, amdfam10 und c3-2. Bei pentium-m wird 
MOVSD benutzt, bei allen anderen verschiedene Kombinationen von MOV und 
PUSH.

Andreas

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.