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
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.
Moin, diese Operation ist im Falle eines 32-Bit Systems auf jedenfall NICHT Atomar, kann also unterbrochen werden.
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.
Es sind Fließkomma Zahlen. Verstehe ich das jetzt richtig, dass da kein Interrupt dazwischen kommen kann?
>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?
alex schrieb: > Es sind Fließkomma Zahlen. Verstehe ich das jetzt richtig, dass da kein > Interrupt dazwischen kommen kann? Korrekt.
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)
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.
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.
Hmm, jetzt steht Aussage gegen Aussage: prx meint, es ist Atomar, docean mein, es ist nicht... was nun?
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.
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ß
... ... 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.
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.
Ε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!
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.
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
... ... 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.
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?
... ... 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.
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
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?
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 |
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.