Jetzt musste ich mir für alle Typen der XMMath-Library minimale Wrapper bauen, nur um den operator=(...) volatile zur Verfügung zu stellen. Benutzen die ihre eigene Doku nicht?! Ist das ein Fall für Microsoft Connect, solange die noch nichts released haben?http://msdn.microsoft.com/en-us/library/windows/desktop/ff476457 hat geschrieben:Don't read from a subresource mapped for writing
When you pass D3D11_MAP_WRITE, D3D11_MAP_WRITE_DISCARD, or D3D11_MAP_WRITE_NO_OVERWRITE to the MapType parameter, you must ensure that your app does not read the subresource data to which the pData member of D3D11_MAPPED_SUBRESOURCE points because doing so can cause a significant performance penalty. […]
Note
Even the following C++ code can read from memory and trigger the performance penalty because the code can expand to the following x86 assembly code.
C++ code:x86 assembly code:Code: Alles auswählen
*((int*)MappedResource.pData) = 0;
Use the appropriate optimization settings and language constructs to help avoid this performance penalty. For example, you can avoid the xor optimization by using a volatile pointer or by optimizing for code speed instead of code size.Code: Alles auswählen
xor [eax],0
Jammer-Thread
Re: Jammer-Thread
Was ist das für eine räudige Scheiße! Die XMMath-Library vom nächsten Platform-SDK beitet keine operator=(…) volatile! Dabei ist es von der MSDN sogar vorgegeben, volatile zu benutzen, wenn man nicht im Optimierungsmodus /Ot (Favor Fast Code) ist (halt in jedem Debug-Build):
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Nein, das musst du persönlich behandeln.
Für SSE-Schreiboperationen ist, im Gegensatz zu x86-nativen Datentypen, keine strenge Ordnung beim Schreiben vorgeschrieben:
Konkret bedeutet das, dass du vor dem Freigeben der Map eine Schreibblockade einfügen musst, damit die Schreiboperationen wirksam werden, bevor der Speicher wieder zur GPU geschickt wird.
Für einen selbstgeschriebenen Zuweisungsoperator, auf dem die linke Seite volatile ist, bedeutet das: Auch er muss diese Schreibblockade aufweisen. Schon aus Prinzip, weil der Speicher ja volatile deklariert ist und deshalb um sofortige Realisierung aller Zugriffe bettelt (sonst viel Spaß, falls du den Operator mal in einem nebenläufigen Programm einsetzt, wofür volatile ja eigentlich da ist).
In letzter Konsequenz: Deine for-Schleife, die die Map mit Vektordaten befüllen soll, ruiniert den Schreibdurchsatz und die Caches, weil nach jedem einzelnen Vektor eine Schreibblockade folgt.
Behandel das also lieber vor Ort Sonderfall.
Für SSE-Schreiboperationen ist, im Gegensatz zu x86-nativen Datentypen, keine strenge Ordnung beim Schreiben vorgeschrieben:
Das bedeutet, dass die CPU die einzelnen Schreiboperationen – samt deren Sichtbarkeit in den Caches – für unbestimmte Zeit vertagen und dann in anderer Reihenfolge realisieren darf.http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650 hat geschrieben:String operations (MOVS and STOS) and 16-byte SSE reads can be internally reordered
Konkret bedeutet das, dass du vor dem Freigeben der Map eine Schreibblockade einfügen musst, damit die Schreiboperationen wirksam werden, bevor der Speicher wieder zur GPU geschickt wird.
Für einen selbstgeschriebenen Zuweisungsoperator, auf dem die linke Seite volatile ist, bedeutet das: Auch er muss diese Schreibblockade aufweisen. Schon aus Prinzip, weil der Speicher ja volatile deklariert ist und deshalb um sofortige Realisierung aller Zugriffe bettelt (sonst viel Spaß, falls du den Operator mal in einem nebenläufigen Programm einsetzt, wofür volatile ja eigentlich da ist).
In letzter Konsequenz: Deine for-Schleife, die die Map mit Vektordaten befüllen soll, ruiniert den Schreibdurchsatz und die Caches, weil nach jedem einzelnen Vektor eine Schreibblockade folgt.
Behandel das also lieber vor Ort Sonderfall.
Re: Jammer-Thread
So wie ich das gerade sehe, kann man gar nicht volatile __m128 einander zuweisen:Krishty hat geschrieben:Für einen selbstgeschriebenen Zuweisungsoperator, auf dem die linke Seite volatile ist, bedeutet das: Auch er muss diese Schreibblockade aufweisen.
Code: Alles auswählen
volatile __m128 a;
volatile __m128 b;
__m128 c;
a = b; // C2678
a = c; // C2678
Und so wie ich das sehe, kann man dem __m128 auch keine Operatoren hinzufügen; zumindest bin ich immer mit ähnlichen Dingen wie hier gescheitert.error C2678: binary '=' : no operator found which takes a left-hand operand of type 'volatile __m128' (or there is no acceptable conversion)
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmmintrin.h(70): could be '__m128 &__m128::operator =(const __m128 &)'
while trying to match the argument list '(volatile __m128, volatile __m128)'
error C2678: binary '=' : no operator found which takes a left-hand operand of type 'volatile __m128' (or there is no acceptable conversion)
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmmintrin.h(70): could be '__m128 &__m128::operator =(const __m128 &)'
while trying to match the argument list '(volatile __m128, __m128)'
Da die XMMath aber für alle Datentypen unions auf float-Arrays anbietet, kopiere ich im Augenblick die float-Arrays. Das ist Mist, aber es funktioniert; wahrscheinlich kommst du aber gleich zu einer besseren Lösung.
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Achso – ich dachte, die Datentypen seien immernoch alle __m128-Wrapper. Mit einzelnen floats müsste es tatsächlich funktionieren. Dann wird der Grund schlicht und einfach sein, dass keine Möglichkeit einer atomaren Zuweisung besteht, und volatile ganz einfach unbrauchbar ist.eXile hat geschrieben:Da die XMMath aber für alle Datentypen unions auf float-Arrays anbietet, kopiere ich im Augenblick die float-Arrays. Das ist Mist, aber es funktioniert; wahrscheinlich kommst du aber gleich zu einer besseren Lösung.
Re: Jammer-Thread
Halt, Kommando zurück! Ich habe mich verwirren lassen, weil die noch zwei weitere, vollkommen unabhängige Vektortypen deklarieren, die sie aber gar nicht für ihre Mathe-Funktionen verwenden.
Für XMVECTOR, der __m128-Wrapper:
Für XMMATRIX, der Standard-Matrixklasse:
In allen Mathe-Funktionen gibt's keine Überraschungen: Falls keine Intrinsics benutzt werden sollen, wird XMVECTOR.vector4_f32 und XMMATRIX.m benutzt, ansonsten XMVECTOR als __m128 und XMMATRIX.r als __m128.
Es ist eher verwunderlich, warum das gerade hier funktioniert. Ist so eine union-Geschichte wie in XMMATRIX überhaupt erlaubt (also ein union mit __m128 und float[4])? Wenn __m128 und volatile-Zuweisungen nicht funktioniere, ist das alles fürs Mappen unbrauchbar?
Für XMVECTOR, der __m128-Wrapper:
Code: Alles auswählen
struct __vector4
{
union
{
float vector4_f32[4];
uint32_t vector4_u32[4];
};
};
// Vector intrinsic: Four 32 bit floating point components aligned on a 16 byte
// boundary and mapped to hardware vector registers
#if defined(_XM_SSE_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef __m128 XMVECTOR;
#elif defined(_XM_ARM_NEON_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef __n128 XMVECTOR;
#else
typedef __vector4 XMVECTOR;
#endif
Code: Alles auswählen
#if (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)) && defined(_XM_NO_INTRINSICS_)
struct XMMATRIX
#else
__declspec(align(16)) struct XMMATRIX
#endif
{
union
{
XMVECTOR r[4];
struct
{
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
};
float m[4][4];
};
XMMATRIX() {}
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, GXMVECTOR R3) { r[0] = R0; r[1] = R1; r[2] = R2; r[3] = R3; }
XMMATRIX(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33);
explicit XMMATRIX(/*_In_reads_(16)*/ const float *pArray);
float operator() (size_t Row, size_t Column) const { return m[Row][Column]; }
float& operator() (size_t Row, size_t Column) { return m[Row][Column]; }
XMMATRIX& operator= (const XMMATRIX& M) { r[0] = M.r[0]; r[1] = M.r[1]; r[2] = M.r[2]; r[3] = M.r[3]; return *this; }
XMMATRIX operator+ () const { return *this; }
XMMATRIX operator- () const;
XMMATRIX& operator+= (CXMMATRIX M);
XMMATRIX& operator-= (CXMMATRIX M);
XMMATRIX& operator*= (CXMMATRIX M);
XMMATRIX& operator*= (float S);
XMMATRIX& operator/= (float S);
XMMATRIX operator+ (CXMMATRIX M) const;
XMMATRIX operator- (CXMMATRIX M) const;
XMMATRIX operator* (CXMMATRIX M) const;
XMMATRIX operator* (float S) const;
XMMATRIX operator/ (float S) const;
friend XMMATRIX operator* (float S, CXMMATRIX M);
};
Es ist eher verwunderlich, warum das gerade hier funktioniert. Ist so eine union-Geschichte wie in XMMATRIX überhaupt erlaubt (also ein union mit __m128 und float[4])? Wenn __m128 und volatile-Zuweisungen nicht funktioniere, ist das alles fürs Mappen unbrauchbar?
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
XNA Math hatte zwei Vektortypen:
Für Matrizen gab es keine solchen Typen, und das sieht bei XMMath genauso aus. Als Grund mutmaße ich: 4×4-Matrizen sind so groß, dass sie eh nicht in Registern übergeben oder als Rvalues benutzt werden können (eine einzige Kopie würde alle x86-SSE-Register vollständig aufgefüllt haben, dann wäre nicht einmal mehr Platz für einen Operanden). Darum haben sie schlicht drauf geschissen und es mit den unions so bequem wie möglich gemacht. Da Matrizen nur durch deren Funktionen / K’toren manipuliert werden und nicht von dir selber, ist das in den meisten Fällen sicher.
Für’s Mappen ist das alles sehr wohl brauchbar – aber nur als Hack. Beim Mappen sagt das volatile dem Compiler einfach, dass er nicht optimieren soll (spezieller: dass ein impliziter Zugriff auf den so deklarierten Speicher nicht stattfinden darf, weil er damit implizite Acquire-Semantik verursachen würde**). Die Semantik, die volatile sonst für Methoden und Operatoren hat (Acquire und Release bei Lesen und Schreiben zu garantieren) musst du in dem Augenblick einfach ignorieren, weil SSE damit nicht wirklich kompatibel ist (es sei denn, du baust Speicherbarrieren und Mutexe in alle volatile-deklarierten Methodenaufrufe ein).
** ist schon ein Bisschen her, dass ich damit gearbeitet habe; bitte korrigieren, falls ich A & R durcheinanderschmeiße.
- einen, der auf __m128 basierte und nach Möglichkeit 1:1 auf ein Register abgebildet wurde – also nur als lokale Variable oder rvalue existieren dürfte; und
- einen, der auf float[4] basierte und für Speicherung ausgelegt war (z.B. als Attribut oder in Datenstrukturen).
Für Matrizen gab es keine solchen Typen, und das sieht bei XMMath genauso aus. Als Grund mutmaße ich: 4×4-Matrizen sind so groß, dass sie eh nicht in Registern übergeben oder als Rvalues benutzt werden können (eine einzige Kopie würde alle x86-SSE-Register vollständig aufgefüllt haben, dann wäre nicht einmal mehr Platz für einen Operanden). Darum haben sie schlicht drauf geschissen und es mit den unions so bequem wie möglich gemacht. Da Matrizen nur durch deren Funktionen / K’toren manipuliert werden und nicht von dir selber, ist das in den meisten Fällen sicher.
Für’s Mappen ist das alles sehr wohl brauchbar – aber nur als Hack. Beim Mappen sagt das volatile dem Compiler einfach, dass er nicht optimieren soll (spezieller: dass ein impliziter Zugriff auf den so deklarierten Speicher nicht stattfinden darf, weil er damit implizite Acquire-Semantik verursachen würde**). Die Semantik, die volatile sonst für Methoden und Operatoren hat (Acquire und Release bei Lesen und Schreiben zu garantieren) musst du in dem Augenblick einfach ignorieren, weil SSE damit nicht wirklich kompatibel ist (es sei denn, du baust Speicherbarrieren und Mutexe in alle volatile-deklarierten Methodenaufrufe ein).
** ist schon ein Bisschen her, dass ich damit gearbeitet habe; bitte korrigieren, falls ich A & R durcheinanderschmeiße.
Re: Jammer-Thread
Sorry, dass ich so nachhake, aber ich versuche es zu verstehen. Die Aquire&Release-Semantik beim Lesen&Schreiben ist ja eigentlich gut, denn das verhindert die von der MSDN angesprochenen ungewollten Lesezugriffe.Krishty hat geschrieben:Für’s Mappen ist das alles sehr wohl brauchbar – aber nur als Hack.
Die Optionen die jetzt so dastehen:
- Auf volatile verzichten (so wie wohl 99 % aller Direct3D-Benutzer) und zügig mittels des eingebauten als __m128 kopieren und hoffen, dass alles gut geht? (Eventuell noch mittels _mm_sfence von außen absichern.)
Code: Alles auswählen
XMMATRIX& operator= (const XMMATRIX& M) { r[0] = M.r[0]; r[1] = M.r[1]; r[2] = M.r[2]; r[3] = M.r[3]; return *this; }
- Die MSDN beachten, volatile einsetzen und mittels des selbstgebastelten kopieren? (Jaja, Vergleiche von &M == this gab's auch in deren Code nirgendwo, und memcpy könnte man wohl auch benutzen.)
Code: Alles auswählen
VXMMATRIX volatile & operator=(const XMMATRIX& M) volatile { _11 = M._11; _12 = M._12; _13 = M._13; _14 = M._14; _21 = M._21; _22 = M._22; _23 = M._23; _24 = M._24; _31 = M._31; _32 = M._32; _33 = M._33; _34 = M._34; _41 = M._41; _42 = M._42; _43 = M._43; _44 = M._44; return *this; }
- Irgendwas anderes? Was wäre die un-hack-igste Möglichkeit, dieses Problem (Benutzung von __m128 und gleichzeitig Beachtung der MSDN) zu lösen?
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Richtig; allerdings möchtest du mit volatile nicht nur die Zugriffe deines Threads auf dieses Objekt ordnen, sondern alle Zugriffe.eXile hat geschrieben:Sorry, dass ich so nachhake, aber ich versuche es zu verstehen. Die Aquire&Release-Semantik beim Lesen&Schreiben ist ja eigentlich gut, denn das verhindert die von der MSDN angesprochenen ungewollten Lesezugriffe.Krishty hat geschrieben:Für’s Mappen ist das alles sehr wohl brauchbar – aber nur als Hack.
Daher: Deklarierst du VXMMATRIX volatile & operator=(const XMMATRIX& M) volatile, möchtest du damit garantieren, dass global jeder andere Zugriff auf *this abgeschlossen ist, bevor die Zuweisung Wirkung entfaltet. Du möchtest, einfach gesagt, eine atomare Zuweisung garantieren:
matrixMutex.lock(); // irgendwie realisiert; nur darf diese Matrix ab jetzt nicht mehr von woanders verändert werden
_11 = M._11; _12 = M._12; _13 = M._13; _14 = M._14;
_21 = M._21; _22 = M._22; _23 = M._23; _24 = M._24;
_31 = M._31; _32 = M._32; _33 = M._33; _34 = M._34;
_41 = M._41; _42 = M._42; _43 = M._43; _44 = M._44;
// Falls die Zuweisung via SSE-MOVs geschähe, müsste hier außerdem ein _mm_sfence() hin
matrixMutex.unlock() // Wirkung durchgesetzt; der nächste Zugriff darf kommen
Dass das Leistungsverschwendung ist, falls du einfach nur ein paar Matrizen in einen Puffer kopieren möchtest, sollte klar sein (ein Lock pro Objekt – Java lässt grüßen ;) ) – in diesem Fall weißt du ja, dass niemand anders in den Speicher schreibt. Das volatile ist ja hier bloß dafür da, dass der Compiler nicht auf die Idee kommt, implizit aus dem Speicher zu lesen; nicht, um Zugriffe auf Matrizen tatsächlich atomar zu machen.
Du möchtest an dieser Stelle also durchaus Aquire-Semantik – allerdings keine Methode, die überall funktioniert, wo du jemals A&R für eine VXMMATRIX benötigst (z.B. in einem nebenläufigen Programm, wo zwei Threads auf dieselbe Matrix zugreifen), weil die zu schwer wäre. Anstatt also einen operator = (…) volatile zu deklarieren, schreibst du eine lokale Funktion, die nur für den einen Zweck eingesetzt wird, jetzt die Daten ohne Lesezugriff in diesen Puffer zu kopieren, indem sie jedem volatile float ein entsprechendes float zuweist.
Eben weil ein einmal volatile deklarierter Operator überall Ordnung garantieren muss – und nicht nur in dem Spezialfall einer Kopie von RAM zu VRAM – und das bedeuten würde, alle Matrizen jederzeit thread-safe zu machen, hat Microsoft keinen beigelegt. Stattdessen bleibt es dir überlassen, eine Lösung für deinen Spezialfall auszutüfteln.
(Alles ohne Gewähr. Ich hasse Multithreading und meide es wie die Pest; darum kenne ich volatile-Correctness nur aus Sicht der Compilertheorie ab C++0x und kaum aus tatsächlicher Anwendung. Ich bin trotzdem von mir überzeugt und glaube, dass von den Leuten, die das Schlüsselwort einsetzen, nur ein Bruchteil die tatsächliche Bedeutung verstanden hat, sondern stattdessen noch ausschließlich an das sich ständig aktualisierende 80er-Jahre-C-Sensorregister glaubt. Das Wort hätte es vor C++0x niemals in den Standard schaffen dürfen.)
Re: Jammer-Thread
Und bis vor wenigen Minuten gehörte ich auch zu diesen Leuten. Danke Dir!Krishty hat geschrieben:Ich bin trotzdem von mir überzeugt und glaube, dass von den Leuten, die das Schlüsselwort einsetzen, nur ein Bruchteil die tatsächliche Bedeutung verstanden hat, sondern stattdessen noch ausschließlich an das sich ständig aktualisierende 80er-Jahre-C-Sensorregister glaubt. Das Wort hätte es vor C++0x niemals in den Standard schaffen dürfen.
Da meine Daten für den Constant-Buffer eh nur POD sind, werde ich die einfach zwischen Map und Unmap in den volatile Speicher memcpy'en. Hat auch noch den Vorteil, das die Zeit des Mappens kleiner gehalten wird. ;)
Re: Jammer-Thread
Side note: Wenn man in einen via API gemappten Speicher kopiert, ist es Aufgabe der API dafuer zu sorgen, dass waehrend des unmap-Aufrufes alle offenen Schreiboperationen abgeschlossen werden, genauso wie sie währen des Map-Aufrufes sicherstellen muss, dass ein Lesezugriff die gewuenschten Daten liefert.
Es gibt ja noch die Caches, um die man sich u.U. auf Treiberseite kuemmern muss, und die willst Du jetzt nicht auch von Hand kontrollieren? Oder Dir Gedanken darueber machen müssen, mit welchen Speicherattributen dein Mapping denn angelegt wurde?
Es wird nur kritisch, wenn der Compiler aus welchen Gruenden auch immer annehmen sollte, ein Map oder Unmap-Aufruf waere seiteneffektfrei und deshalb Lade/Schreiboperationen "ueber" die Funktionsaufrufe zieht. Und das sollte wirklich nicht passieren.
Fuer Thread-Thread Datenaustausch via regulärem Speicher (Heap, evtl. Stack) gelten Deine Anmerkungen.
Zum "Don't read from a subresource mapped for writing" eine Anmerkung. Das liegt einfach daran, dass das Mapping im meisten Fall ein Uncached, Write-Through Mapping ist. D.h. jeder Lesezugriff geht direkt ins RAM, ohne irgendwie vom Cache abgefangen zu werden. Daher die Performance-Einbußen. Vorteil: Wenn man nur schreibt, dann wird dadurch kein kostbarer Platz im Cache reserviert, der u.U. Daten rauswirft, die man braucht, nur um solche zu halten, die man nicht mehr haben will...
Also: memcpy tut es, SSE stores auch. Ohne Probleme.
Es gibt ja noch die Caches, um die man sich u.U. auf Treiberseite kuemmern muss, und die willst Du jetzt nicht auch von Hand kontrollieren? Oder Dir Gedanken darueber machen müssen, mit welchen Speicherattributen dein Mapping denn angelegt wurde?
Es wird nur kritisch, wenn der Compiler aus welchen Gruenden auch immer annehmen sollte, ein Map oder Unmap-Aufruf waere seiteneffektfrei und deshalb Lade/Schreiboperationen "ueber" die Funktionsaufrufe zieht. Und das sollte wirklich nicht passieren.
Fuer Thread-Thread Datenaustausch via regulärem Speicher (Heap, evtl. Stack) gelten Deine Anmerkungen.
Zum "Don't read from a subresource mapped for writing" eine Anmerkung. Das liegt einfach daran, dass das Mapping im meisten Fall ein Uncached, Write-Through Mapping ist. D.h. jeder Lesezugriff geht direkt ins RAM, ohne irgendwie vom Cache abgefangen zu werden. Daher die Performance-Einbußen. Vorteil: Wenn man nur schreibt, dann wird dadurch kein kostbarer Platz im Cache reserviert, der u.U. Daten rauswirft, die man braucht, nur um solche zu halten, die man nicht mehr haben will...
Also: memcpy tut es, SSE stores auch. Ohne Probleme.
- Lynxeye
- Establishment
- Beiträge: 145
- Registriert: 27.02.2009, 16:50
- Echter Name: Lucas
- Wohnort: Hildesheim
- Kontaktdaten:
Re: Jammer-Thread
Side Note zur Side Note:
Der Fall, den die MSDN nennt, ist aber ein ziemlicher Sonderfall, da der MS Compiler anscheinend immer noch glaubt es ist eine gute Idee eine 0 per xor zu erzeugen, statt sie als Konstante zu setzen. Das war auf alten Pentium Prozessoren der Fall, bei modernen CPUs ist das aber nicht mehr so. Du solltest also auch ohne volatile auskommen, wenn du einfach für den Fall auf ein memset() ausweichst.
Das Mapping wird in der Regel Uncached,Write-Combined sein, das heißt deine Schreiboperationen werden in einem WC Puffer gehalten und in größeren Paketen geschrieben. Dieser Puffer wird entweder durch die API geflusht, sobald du ein unmap() durchführst oder von der Hardware selbst sobald du eine Leseoperation auf den betreffenden Speicherbereich durchführst, das ist der größere Performancekiller.Jörg hat geschrieben: Zum "Don't read from a subresource mapped for writing" eine Anmerkung. Das liegt einfach daran, dass das Mapping im meisten Fall ein Uncached, Write-Through Mapping ist. D.h. jeder Lesezugriff geht direkt ins RAM, ohne irgendwie vom Cache abgefangen zu werden. Daher die Performance-Einbußen.
Der Fall, den die MSDN nennt, ist aber ein ziemlicher Sonderfall, da der MS Compiler anscheinend immer noch glaubt es ist eine gute Idee eine 0 per xor zu erzeugen, statt sie als Konstante zu setzen. Das war auf alten Pentium Prozessoren der Fall, bei modernen CPUs ist das aber nicht mehr so. Du solltest also auch ohne volatile auskommen, wenn du einfach für den Fall auf ein memset() ausweichst.
Re: Jammer-Thread
Ja natuerlich, fuer reine Datenpuffer mit irrelevanter individueller Schreibreihenfolge ist das besser geeignet.Lynxeye hat geschrieben:Das Mapping wird in der Regel Uncached,Write-Combined sein
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: Jammer-Thread
Visual Studio 11: Kostenlose Express-Version unterstützt nur Metro-Apps - Visual Studio Express ist tot. Wenn ich die Bilder schon sehe. Eigentlich will ich nur den neuen Compiler - ob man sich den dann irgendwie in VS10 einbauen kann?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
- dot
- Establishment
- Beiträge: 1743
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
Das wird wohl spätestens mit der nächsten Version wieder besser hoff ich. Im Moment wollen sie eben einfach nur Metro pushen. War ja mit der ersten Express Version auch nicht anders, damals wollte man eben .NET pushen...
Re: Jammer-Thread
Also ich bin ja überaus gespannt auf Clang + Eclipse. Sobald das gut läuft, könnte es sehr gut sein, dass ich mich von Visual Studio verabschiede. Jedenfalls wenn dann Eclipse für C++ so gut ist, wie für Java (immerhin ist Eclipse der Grund, aus dem Java erst erträglich geworden ist).
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: Jammer-Thread
Eclipse ist doch so ziemlich die mieseste IDE auf dem Markt.Jonathan hat geschrieben:Also ich bin ja überaus gespannt auf Clang + Eclipse. Sobald das gut läuft, könnte es sehr gut sein, dass ich mich von Visual Studio verabschiede. Jedenfalls wenn dann Eclipse für C++ so gut ist, wie für Java (immerhin ist Eclipse der Grund, aus dem Java erst erträglich geworden ist).
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da :)
"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
DirectGL, endlich ist es da :)
"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Stimmt, das hatte ich vergessen – vor Aufrufen unbekannter Wirkung muss der Compiler sowieso einen konstanten Zustand herstellen.Jörg hat geschrieben:Es wird nur kritisch, wenn der Compiler aus welchen Gruenden auch immer annehmen sollte, ein Map oder Unmap-Aufruf waere seiteneffektfrei und deshalb Lade/Schreiboperationen "ueber" die Funktionsaufrufe zieht. Und das sollte wirklich nicht passieren.
Sicher? Zumindest von Intel-CPUs weiß ich, dass sie es tatsächlich als Nullen mit Aufbrechen von Abhängigkeiten implementieren und nicht als wirkliches Lesen; XOR; Schreiben. Die xor-Version ist dabei kürzer als die Konstante; es passt also bei gleicher Wirkung mehr Maschinentext in den Cache.Lynxeye hat geschrieben:da der MS Compiler anscheinend immer noch glaubt es ist eine gute Idee eine 0 per xor zu erzeugen, statt sie als Konstante zu setzen. Das war auf alten Pentium Prozessoren der Fall, bei modernen CPUs ist das aber nicht mehr so.
- dot
- Establishment
- Beiträge: 1743
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
Das bildet sich der MS Compiler nicht einfach nur ein. Wie Krishty schon gesagt hat, ist das ganz besonders bei modernen CPUs genau so der Fall, nicht nur weil die Instruction kleiner ist, sondern auch was Instruction Level Parallelism angeht. Siehe dazu das Intel Software Optimization Manual ;)Lynxeye hat geschrieben:Der Fall, den die MSDN nennt, ist aber ein ziemlicher Sonderfall, da der MS Compiler anscheinend immer noch glaubt es ist eine gute Idee eine 0 per xor zu erzeugen, statt sie als Konstante zu setzen. Das war auf alten Pentium Prozessoren der Fall, bei modernen CPUs ist das aber nicht mehr so.
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: Jammer-Thread
Soll das ein Witz sein? Ich kann die Anzahl mittels Stream Output geschriebener Primitive nur per SO Query zurück zur CPU lesen, sie aber nicht einfach auf der GPU in einen (Constant) Buffer schreiben? Wie zur Hölle soll ich jetzt Stream Output Buffers im Compute Shader vararbeiten?!?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Wo hat denn das Laden einer Konstante (natürlich angenommen, sie füllt das gesamte Register aus!) Nachteile bezüglich Nebenläufigkeit gegenüber einem XOR?dot hat geschrieben:sondern auch was Instruction Level Parallelism angeht.
- dot
- Establishment
- Beiträge: 1743
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
mov wird von der CPU nicht als dependency breaking erkannt wie du schon gesagt hast, xor reg, reg schon...
Intel Software Optimization Manual hat geschrieben:Some micro-ops can execute to completion during rename and are removed from the
pipeline at that point, effectively costing no execution bandwidth. These include:[...]
- Zero idioms (dependency breaking idioms)
- NOP
- VZEROUPPER
- FXCHG
Instruction parallelism can be improved by using common instructions to clear
register contents to zero. The renamer can detect them on the zero evaluation of the
destination register.
Use one of these dependency breaking idioms to clear a register when possible.Since zero idioms are detected and removed by the renamer, they have no execution
- XOR REG,REG
- SUB REG,REG
- PXOR/VPXOR XMMREG,XMMREG
- PSUBB/W/D/Q XMMREG,XMMREG
- VPSUBB/W/D/Q XMMREG,XMMREG
- XORPS/PD XMMREG,XMMREG
- VXORPS/PD YMMREG, YMMREG
latency.
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Nachtrag: Du hast absolut recht.
Furthermore, they do not consume an issue port or an execution unit. So using zero idioms are preferable than moving 0’s into the register.
- dot
- Establishment
- Beiträge: 1743
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
Ich wollte gerade den gleichen Satz posten :D
- Lynxeye
- Establishment
- Beiträge: 145
- Registriert: 27.02.2009, 16:50
- Echter Name: Lucas
- Wohnort: Hildesheim
- Kontaktdaten:
Re: Jammer-Thread
Ok, da hab ich wirklich falsch gelegen. Auch AMD meint das selbe:
Warum diskutieren wir eigtl. die solche Sachen immer im Jammerthread?
Ändert aber nichts an der Ursprungsaussage, dass der angeführte =0 Fall der MSDN eher die Ausnahme denn die Regel ist.Software Optimization Guide for AMD Family 15h Processors hat geschrieben: Rationale
AMD Family 15h processors are able to avoid the false read dependency on the XOR instruction.
Acceptable
mov reg, 0
Preferred
xor reg, reg
Warum diskutieren wir eigtl. die solche Sachen immer im Jammerthread?
- dot
- Establishment
- Beiträge: 1743
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
Wär auch blöd wenn AMD es genau anders rum machen würd wie Intel :D
Gute Frage. Ist wohl so dass die wirklich interessanten Themen beim Jammern hochkommen ;)Lynxeye hat geschrieben:Warum diskutieren wir eigtl. die solche Sachen immer im Jammerthread?
- Krishty
- Establishment
- Beiträge: 8305
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Ich persönlich poste ja kaum noch woanders und kann dementsprechend schwer woanders darüber diskutieren – das erklärt zumindest mir diesen Zufall ;)
Re: Jammer-Thread
Warum lesen sich eigentlich OpenGL-Präsentationen genauso wie damals im Jahre 2003? Die Präsentationen sehen in ihrer Essenz vollkommen gleich aus. Irgendwie hört man immer die gleichen Aussagen, frei nach dem Motto „hurrrr wenn wir weiter so viele Versionen veröffentlichen sind wir bald™ \($10^{100}$\)-mal schneller als alles dagewesene“; jedes Jahr natürlich. Ich glaub' keinem mehr von irgendeiner Seite irgendwas.
(Wobei bindless Texturen eigentlich schon schön wären. Kommt vermutlich erst in Direc3D vNext.)
(Wobei bindless Texturen eigentlich schon schön wären. Kommt vermutlich erst in Direc3D vNext.)
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: Jammer-Thread
Jedes Mal, wenn ich von Dozenten an der Uni vom Java GC vorgeschwärmt bekomme (und dabei beiläufig C++ runtergeputzt wird), wünschte ich mir, ein gewisses Forenmitglied hätte bereits so viel informatischen Ruhm erlangt, dass ich mit Autorität zitieren könnte:
Traurig, dass C++ mit all seinem Balast und Macken noch immer die einzig mir bekannte Sprache ist, die Ressourcenverwaltung (und damit einhergehend Fehlerbehandlung) sinnvoll ermöglicht.Ein Garbage Collector ist ein Designfehler.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: Jammer-Thread
Meinen Dozenten war es nach dem dritten Semester egal, in welchen Programmiersprachen wir die Probleme gelöst haben. In manchen Fällen (Ray-Tracer schreiben) fällt die Wahl ganz natürlich auf C++; welches wir natürlich im Studium nie behandelt haben.CodingCat hat geschrieben:Jedes Mal, wenn ich von Dozenten an der Uni vom Java GC vorgeschwärmt bekomme
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: Jammer-Thread
Es geht nicht um irgendwelche Aufgaben, es geht um die vermittelte Idealvorstellung und die fehlenden Konzepte für strukturierte und verlässliche Programmierung. Dass Java mit seiner verkorksten Ausnahmebehandlung, und damit einhergehend der misslungenen Ressourcenverwaltung durch den GC, gegenüber C++ als Ideal dargestellt wird, tut einfach in der Seele weh.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite