mikrocontroller.net

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


Autor: alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: alex (Gast)
Datum:

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

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alex schrieb:

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

Korrekt.

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: alex (Gast)
Datum:

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

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: U.R. Schmitt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)
double x;

extern void f(double);

void t(void)
{
        f(x);
}       
00000000 <t>:
double x;

extern void f(double);

void t(void)
{
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 10                sub    $0x10,%esp
        f(x);
   6:   ff 35 04 00 00 00       pushl  0x4
   c:   ff 35 00 00 00 00       pushl  0x0
  12:   e8 fc ff ff ff          call   13 <t+0x13>
  17:   83 c4 10                add    $0x10,%esp
}
  1a:   c9                      leave  
  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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

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

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.