Jammer-Thread
- Schrompf
- Moderator
- Beiträge: 5157
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Jammer-Thread
Öhm.... vielleicht hab ich da ja was verkackt, aber bei mir war in GLSL der mat4-Konstruktor aus 16 float wirklich row major, während die Standard-Storage column_major war.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- dot
- Establishment
- Beiträge: 1746
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: Jammer-Thread
Kanns sein, dass du Vektor * Matrix rechnest statt umgekehrt? Dann kommst du mit der so verkehrten Matrix nämlich zum richtigen Ergebnis... ;)
Re: Jammer-Thread
ist mal wieder typisch, da benutzt man ein richtig geiles neues feature in der webaudio api und was sehe ich heute per zufall in der console: deprecated. nachgekuckt und irgendwie hat irgendwer gefunden das ding sei nicht gut. reg mich grad tierisch auf.
https://groups.google.com/a/chromium.or ... 1SI1GoHYO8
https://groups.google.com/a/chromium.or ... 1SI1GoHYO8
Blood of the Undead https://falkenbrew.itch.io/blood-of-the-undead
Re: Jammer-Thread
Die Summe aller natürlichen Zahlen ist -1/12 ...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Artificial Mind
- Establishment
- Beiträge: 802
- Registriert: 17.12.2007, 17:51
- Wohnort: Aachen
Re: Jammer-Thread
http://en.wikipedia.org/wiki/1_%2B_2_%2 ... _%E2%8B%AFJonathan hat geschrieben:Die Summe aller natürlichen Zahlen ist -1/12 ...
Und ich bevorzuge die Formulierung "man kann der divergenten Summe der natürlichen Zahlen die Zahl -1/12 zuweisen und dadurch einige interessante Resultate erzielen".
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Immer die Return Codes prüfen. Habe ein zwei Jahre altes Memory Leak beim Kopieren des Back Buffers gefunden, weil ich UnlockRect() auf dem falschen Surface durchgeführt habe -.-
Re: Jammer-Thread
std::ios::binary vergessen. Jedesmal. JEDESMAL!
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
So sehr ich auch Abwärtskompatibilität verteidige, so sehr bin ich Feind davon, jedes Jahr eine neue API für den selben Scheiß rauszubringen. … und nur um ein Dreieck auf den Bildschirm zu kriegen muss man von COM bis GDI alles einbinden -.-- Chromanoid
- Moderator
- Beiträge: 4286
- Registriert: 16.10.2002, 19:39
- Echter Name: Christian Kulenkampff
- Wohnort: Lüneburg
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Ich dachte, das seit einigen Jahren hinter mir gelassen zu haben, aber … Visual C++ 2012 unterscheidet bei float noch immer zwischen pass-by-ref und pass-by-value. In der Größenordnung von einem Drittel mehr Memory Roundtrips in float-lastigen Funktionen. Schreibt für eure Mathe besser keine Templates, die ihre supergenerischen Parameter via T const & nehmen.
Ich hatte das vor einigen Jahren mal getestet, weil Visual C++ 2010 lächerlich schlimm drunter litt, und da sah es gut aus. War wohl zu synthetisch. Bestimmt ist da wieder ein Fehler, dass bei einer bestimmten Anzahl lokaler floats, die nicht als Parameter kommen, und deren Name mit q beginnt, bei der Anwesenheit eines SSE-Befehls im rechts-rechts-linken Unterzweig des Syntaxbaums alles auf den Stapel geklatscht wird, falls eine Überladung der Funktion zwei Zeilen weiter oben eine Referenz erwartet.
Ich hatte das vor einigen Jahren mal getestet, weil Visual C++ 2010 lächerlich schlimm drunter litt, und da sah es gut aus. War wohl zu synthetisch. Bestimmt ist da wieder ein Fehler, dass bei einer bestimmten Anzahl lokaler floats, die nicht als Parameter kommen, und deren Name mit q beginnt, bei der Anwesenheit eines SSE-Befehls im rechts-rechts-linken Unterzweig des Syntaxbaums alles auf den Stapel geklatscht wird, falls eine Überladung der Funktion zwei Zeilen weiter oben eine Referenz erwartet.
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
long ist der nutzloseste Datentyp evar.
- Schrompf
- Moderator
- Beiträge: 5157
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Jammer-Thread
Und trotzdem gefährlich, weil auf GCC 64bit mit 64bit-Architekturen, auf Visual C++ nur 32bit auf allen Architekturen. Eine der Freuden, wenn man eine Programmiersprache nutzt, die nun schon 30+ Jahre auf dem Buckel hat. Wobei long wohl noch aus C-Zeiten stammt, also nochmal 10 Jahre älter ist.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Top-OR
- Establishment
- Beiträge: 330
- Registriert: 02.03.2011, 16:32
- Echter Name: Jens H.
- Wohnort: Esslingen/Dessau
- Kontaktdaten:
Re: Jammer-Thread
Da kommt hier schon wieder einer ins Forum, registriert sich und "sucht" mit dem ersten Post nen Grafiker für das X-te NICHT beschriebene Luftschloss-Projekt und sagt NIX drüber (ich habe Furzgeräusche gehört, die mehr Informationsgehalt haben) und ich kann nichtmal ne kodderige Gegenfrage druntersetzen, weil der Thread gesperrt ist.
Mimimimimimimi... Ich will jammern!
Leute, wenn das Projekt Fleisch auf den Knochen hat und kein Luftschloss ist, dann ZEIGT doch auch was, wenn ihr Leute wollt, die sich da engagieren wollen sollen.
Ohne zu wissen, worums geht, rennt doch da keiner (bzw. die wenigsten) los...
Mimimimimimimi... Ich will jammern!
Leute, wenn das Projekt Fleisch auf den Knochen hat und kein Luftschloss ist, dann ZEIGT doch auch was, wenn ihr Leute wollt, die sich da engagieren wollen sollen.
Ohne zu wissen, worums geht, rennt doch da keiner (bzw. die wenigsten) los...
--
Verallgemeinerungen sind IMMER falsch.
Verallgemeinerungen sind IMMER falsch.
-
- Establishment
- Beiträge: 426
- Registriert: 23.01.2013, 15:55
Re: Jammer-Thread
Ich bin ein Freund von size_t, int32_t, int64_t und Konsorten.
Das Spart den "long" und co. Ärger für alle von Anfang an. (In exotischen System kommen durchaus noch andere Konstellationen vor)
Das Spart den "long" und co. Ärger für alle von Anfang an. (In exotischen System kommen durchaus noch andere Konstellationen vor)
- Schrompf
- Moderator
- Beiträge: 5157
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Jammer-Thread
Jo, der ist dieses Mal besonders dreist. Nichtmal die eigene Webseite verraten wollen, aber nur "Bewerbungen" mit "Link auf Portfolio" akzeptieren. Aber nuja, es sind ja gar keine Links drin. Deswegen können wir das Ding einfach dem wohlverdienten Tod durch Desinteresse überlassen.Top-OR hat geschrieben:Da kommt hier schon wieder einer ins Forum, registriert sich und "sucht" mit dem ersten Post nen Grafiker für das X-te NICHT beschriebene Luftschloss-Projekt und sagt NIX drüber (ich habe Furzgeräusche gehört, die mehr Informationsgehalt haben) und ich kann nichtmal ne kodderige Gegenfrage druntersetzen, weil der Thread gesperrt ist.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Das erspart einem aber dummerweise nicht die longs aus den Windows-Headern … naja; CTRL+H, Replace All, feddich.Spiele Programmierer hat geschrieben:Ich bin ein Freund von size_t, int32_t, int64_t und Konsorten.
Das Spart den "long" und co. Ärger für alle von Anfang an. (In exotischen System kommen durchaus noch andere Konstellationen vor)
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Ihr wisst ja, wie der Heap unter Windows funktioniert, seit er auf Low Fragmentation umgestellt wurde, oder? Da werden Blöcke in einer Handvoll Größenklasse reserviert (ein Block für alles <= 16 B; einer für alles <= 64 B; einer für alles <= 128 B; usw) und mit Allokationen gefüllt. Damit ist der Speicher sehr schwer zu fragmentieren, denn selbst wenn man alle Größen durcheinander reserviert, werden im Speicher eng zusammenliegende Blöcke gefüllt. Es hilft oft auch der Lokalität, weil z.B. alle std::strings des Programms im selben Block landen.
Jetzt gibt es doch noch einen Weg, das Ding fragmentiert zu kriegen: Wenn so ein Block voll ist, wird nämlich ein Zusätzlicher reserviert. Und der wird, wenn er leer ist, erstmal nicht wieder freigegeben – eine gültige Annahme, denn wenn ein Programm viel reserviert und wieder freigibt, reserviert es in naher Zukunft vielleicht wieder eine ähnliche Menge (anderes Dokument öffnen, Level wechseln, etc). "Cache" nennen sie das. Dumm nur, dass diese Blöcke wohl nie mehr freigegeben werden.
Mit Windows 8.1 haben sie HeapSetInformation() das Flag HeapOptimizeResources eingeführt, das mit diesen Caches aufräumt. 8.1?! Gehtmirwech! Ich will das ab Vista! Gnnnnnnnngh
Jetzt gibt es doch noch einen Weg, das Ding fragmentiert zu kriegen: Wenn so ein Block voll ist, wird nämlich ein Zusätzlicher reserviert. Und der wird, wenn er leer ist, erstmal nicht wieder freigegeben – eine gültige Annahme, denn wenn ein Programm viel reserviert und wieder freigibt, reserviert es in naher Zukunft vielleicht wieder eine ähnliche Menge (anderes Dokument öffnen, Level wechseln, etc). "Cache" nennen sie das. Dumm nur, dass diese Blöcke wohl nie mehr freigegeben werden.
Mit Windows 8.1 haben sie HeapSetInformation() das Flag HeapOptimizeResources eingeführt, das mit diesen Caches aufräumt. 8.1?! Gehtmirwech! Ich will das ab Vista! Gnnnnnnnngh
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Boah ist Visual C++ scheiße. Hier ist eine meiner inneren Schleifen – drei Vertices in die Render-Schlange einreihen:
Vertex * Rasterizer::enqueueTriangle() __restrict {
if(myDesiredTexture != myLastTexture) { // Texture change required?
enqueueTextureChange(*myDesiredTexture);
}
auto const result = reinterpret_cast<Vertex *>(myToEndOfCommandParameters);
myToEndOfCommandParameters += 3 * sizeof(Vertex);
*myToEndOfCommands++ = Command::drawTriangle;
return result;
}
void Rasterizer::enqueueTextureChange(
Texture2D * texture
) __restrict {
myLastTexture = &texture;
*myToEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(myToEndOfCommandParameters) = texture;
myToEndOfCommandParameters += sizeof texture;
}
Und hier ist der glorreiche Haufen Molchsperma, den Visual C++ 2013 x64 auswichst:
mov rdx,rcx
mov rcx,qword ptr [rcx+4020h]
cmp rcx,qword ptr [rdx+4018h]
je +43h
mov rax,qword ptr [rdx+4028h]
mov qword ptr [rdx+4018h],rcx
mov byte ptr [rax],2
inc rax
mov qword ptr [rdx+4028h],rax
mov rax,qword ptr [rdx+4030h]
mov qword ptr [rax],rcx
add rax,8
mov qword ptr [rdx+4030h],rax
mov rax,qword ptr [rdx+4030h]
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
mov rcx,qword ptr [rdx+4028h]
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
ret
Ich habe das Laden zweier Attribute („Member-Variablen“) farbig hervorgehoben. Warum werden die Dinger denn doppelt geladen und geschrieben? Na, ganz einfach: Weil sie eben zwei Mal benutzt werden!

Aber sie werden in unterschiedlichen Methoden benutzt. Vielleicht geht beim Inlining ja Information verloren? Inlinen wir mal von Hand:
Vertex * Rasterizer::enqueueTriangle() __restrict {
if(myDesiredTexture != myLastTexture) { // Texture change required?
myLastTexture = myDesiredTexture;
*myToEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(myToEndOfCommandParameters) = myDesiredTexture;
myToEndOfCommandParameters += sizeof myDesiredTexture;
}
auto const result = reinterpret_cast<Vertex *>(myToEndOfCommandParameters);
myToEndOfCommandParameters += 3 * sizeof(Vertex);
*myToEndOfCommands++ = Command::drawTriangle;
return result;
}
mov rdx,rcx
mov rcx,qword ptr [rcx+4020h]
cmp rcx,qword ptr [rdx+4018h]
je +43h
mov rax,qword ptr [rdx+4028h]
mov qword ptr [rdx+4018h],rcx
mov byte ptr [rax],2
inc rax
mov qword ptr [rdx+4028h],rax
mov rax,qword ptr [rdx+4030h]
mov qword ptr [rax],rcx
add rax,8
mov qword ptr [rdx+4030h],rax
mov rax,qword ptr [rdx+4030h]
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
mov rcx,qword ptr [rdx+4028h]
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
ret
1:1 identisch.

Also tue ich, was ich seit Monaten *immer* tun muss: Visual C++ von Hand diktieren, wann es welches Attribut zu laden und zu speichern hat:
__declspec(noinline) Vertex * Rasterizer::enqueueTriangle() __restrict {
// Fetch all attributes because Visual C++ sucks:
auto const desiredTexture = myDesiredTexture;
auto toEndOfCommands = myToEndOfCommands;
auto toEndOfCommandParameters = myToEndOfCommandParameters;
if(desiredTexture != myLastTexture) { // Texture change required?
myLastTexture = desiredTexture;
*toEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(toEndOfCommandParameters) = desiredTexture;
toEndOfCommandParameters += sizeof desiredTexture;
}
auto const result = reinterpret_cast<Vertex *>(toEndOfCommandParameters);
toEndOfCommandParameters += 3 * sizeof(Vertex);
*toEndOfCommands++ = Command::drawTriangle;
// Write back all attributes because Visual C++ sucks:
myToEndOfCommands = toEndOfCommands;
myToEndOfCommandParameters = toEndOfCommandParameters;
return result;
}

Und plötzlich haben wir vier Speicherzugriffe weniger. Und die Maschinenbefehle sind nur noch halb so lang, weil der 32-Bit-Versatz 0x40XX weniger oft reingeschrieben werden muss. Und ich musste extra Inlining abschalten um die Methode überhaupt noch im Debugger ansteuern zu können.
mov r8,qword ptr [rcx+4020h]
mov rdx,rcx
mov rcx,qword ptr [rcx+4028h]
mov rax,qword ptr [rdx+4030h]
cmp r8,qword ptr [rdx+4018h]
je +35h
mov byte ptr [rcx],2
inc rcx
mov qword ptr [rax],r8
add rax,8
mov qword ptr [rdx+4018h],r8
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
ret
Jetzt ist mein Quelltext doppelt so lang und meine Engine 2 % schneller. WTF?!

Vertex * Rasterizer::enqueueTriangle() __restrict {
if(myDesiredTexture != myLastTexture) { // Texture change required?
enqueueTextureChange(*myDesiredTexture);
}
auto const result = reinterpret_cast<Vertex *>(myToEndOfCommandParameters);
myToEndOfCommandParameters += 3 * sizeof(Vertex);
*myToEndOfCommands++ = Command::drawTriangle;
return result;
}
void Rasterizer::enqueueTextureChange(
Texture2D * texture
) __restrict {
myLastTexture = &texture;
*myToEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(myToEndOfCommandParameters) = texture;
myToEndOfCommandParameters += sizeof texture;
}
Und hier ist der glorreiche Haufen Molchsperma, den Visual C++ 2013 x64 auswichst:
mov rdx,rcx
mov rcx,qword ptr [rcx+4020h]
cmp rcx,qword ptr [rdx+4018h]
je +43h
mov rax,qword ptr [rdx+4028h]
mov qword ptr [rdx+4018h],rcx
mov byte ptr [rax],2
inc rax
mov qword ptr [rdx+4028h],rax
mov rax,qword ptr [rdx+4030h]
mov qword ptr [rax],rcx
add rax,8
mov qword ptr [rdx+4030h],rax
mov rax,qword ptr [rdx+4030h]
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
mov rcx,qword ptr [rdx+4028h]
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
ret
Ich habe das Laden zweier Attribute („Member-Variablen“) farbig hervorgehoben. Warum werden die Dinger denn doppelt geladen und geschrieben? Na, ganz einfach: Weil sie eben zwei Mal benutzt werden!
Aber sie werden in unterschiedlichen Methoden benutzt. Vielleicht geht beim Inlining ja Information verloren? Inlinen wir mal von Hand:
Vertex * Rasterizer::enqueueTriangle() __restrict {
if(myDesiredTexture != myLastTexture) { // Texture change required?
myLastTexture = myDesiredTexture;
*myToEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(myToEndOfCommandParameters) = myDesiredTexture;
myToEndOfCommandParameters += sizeof myDesiredTexture;
}
auto const result = reinterpret_cast<Vertex *>(myToEndOfCommandParameters);
myToEndOfCommandParameters += 3 * sizeof(Vertex);
*myToEndOfCommands++ = Command::drawTriangle;
return result;
}
mov rdx,rcx
mov rcx,qword ptr [rcx+4020h]
cmp rcx,qword ptr [rdx+4018h]
je +43h
mov rax,qword ptr [rdx+4028h]
mov qword ptr [rdx+4018h],rcx
mov byte ptr [rax],2
inc rax
mov qword ptr [rdx+4028h],rax
mov rax,qword ptr [rdx+4030h]
mov qword ptr [rax],rcx
add rax,8
mov qword ptr [rdx+4030h],rax
mov rax,qword ptr [rdx+4030h]
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
mov rcx,qword ptr [rdx+4028h]
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
ret
1:1 identisch.
Also tue ich, was ich seit Monaten *immer* tun muss: Visual C++ von Hand diktieren, wann es welches Attribut zu laden und zu speichern hat:
__declspec(noinline) Vertex * Rasterizer::enqueueTriangle() __restrict {
// Fetch all attributes because Visual C++ sucks:
auto const desiredTexture = myDesiredTexture;
auto toEndOfCommands = myToEndOfCommands;
auto toEndOfCommandParameters = myToEndOfCommandParameters;
if(desiredTexture != myLastTexture) { // Texture change required?
myLastTexture = desiredTexture;
*toEndOfCommands++ = Command::setTexture;
*reinterpret_cast<Texture2D * *>(toEndOfCommandParameters) = desiredTexture;
toEndOfCommandParameters += sizeof desiredTexture;
}
auto const result = reinterpret_cast<Vertex *>(toEndOfCommandParameters);
toEndOfCommandParameters += 3 * sizeof(Vertex);
*toEndOfCommands++ = Command::drawTriangle;
// Write back all attributes because Visual C++ sucks:
myToEndOfCommands = toEndOfCommands;
myToEndOfCommandParameters = toEndOfCommandParameters;
return result;
}
Und plötzlich haben wir vier Speicherzugriffe weniger. Und die Maschinenbefehle sind nur noch halb so lang, weil der 32-Bit-Versatz 0x40XX weniger oft reingeschrieben werden muss. Und ich musste extra Inlining abschalten um die Methode überhaupt noch im Debugger ansteuern zu können.
mov r8,qword ptr [rcx+4020h]
mov rdx,rcx
mov rcx,qword ptr [rcx+4028h]
mov rax,qword ptr [rdx+4030h]
cmp r8,qword ptr [rdx+4018h]
je +35h
mov byte ptr [rcx],2
inc rcx
mov qword ptr [rax],r8
add rax,8
mov qword ptr [rdx+4018h],r8
mov byte ptr [rcx],6
inc rcx
mov qword ptr [rdx+4028h],rcx
lea rcx,[rax+48h]
mov qword ptr [rdx+4030h],rcx
ret
Jetzt ist mein Quelltext doppelt so lang und meine Engine 2 % schneller. WTF?!
Zuletzt geändert von Krishty am 28.03.2015, 16:19, insgesamt 1-mal geändert.
- Schrompf
- Moderator
- Beiträge: 5157
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Jammer-Thread
Ich mag Deine wortgewaltigen und wohlillustrierten Rants. Immer hart an der Geschmacksgrenze, zumindest an meiner, aber sehr anschaulich und höchst unterhaltsam.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: Jammer-Thread
Was bei dir da passiert, kenne ich aus der Mikrocontroller-Programmierung und wird eigentlich mit dem Schlüsselwort volatile erzwungen - sonst aber tunlichst vermieden...... Das ist mega pervers, wenn der Compilder das dort hinzuinterpretiert, nur weil er irgendwo das tracking verliert.
Allerdings habe ich mich nochmal zu __restrict belesen, da ich es nur aus dem Bereich der Variablen kenne, um den Compiler zu sagen, dass Pointeradressbereiche nicht überlappen. (bitte korrigiert mich) Fakt ist, dass MSDN __restrict ausdrücklich sagt, dass dein obriger Syntax so nicht sein soll. (für Funktionen immer __declspec(restrict)...)
Und das hat mich ins grübeln gebracht: das beobachtete Verhalten erklärt sich ja nicht nur durch ein hinzugedichtetes volatile, sondern auch durch die Annahme, dass dein Compiler evtl davon ausgeht, dass die Membervariablen adressmäßig aufeinander liegen. Nunja... so sinnlos eine solche Annahme ist, so sehr assoziiere ich das auch mit __restrict. Vllt läuft da wirklich was schief?
Allerdings habe ich mich nochmal zu __restrict belesen, da ich es nur aus dem Bereich der Variablen kenne, um den Compiler zu sagen, dass Pointeradressbereiche nicht überlappen. (bitte korrigiert mich) Fakt ist, dass MSDN __restrict ausdrücklich sagt, dass dein obriger Syntax so nicht sein soll. (für Funktionen immer __declspec(restrict)...)
Und das hat mich ins grübeln gebracht: das beobachtete Verhalten erklärt sich ja nicht nur durch ein hinzugedichtetes volatile, sondern auch durch die Annahme, dass dein Compiler evtl davon ausgeht, dass die Membervariablen adressmäßig aufeinander liegen. Nunja... so sinnlos eine solche Annahme ist, so sehr assoziiere ich das auch mit __restrict. Vllt läuft da wirklich was schief?
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Dochdoch, das ist schon so gedacht:
__declspec(restrict) bei der Deklaration einer Funktion sagt, dass der zurückgegebene Typ nicht aliast. Das möchtest du z.B. bei malloc() haben, weil der zurückgegebene Speicher sonst noch nirgends im Programm bekannt ist und deshalb mit nichts überlappen kann.
__restrict hinter einer Methode macht den this-Zeiger der Methode nicht-überlappend, ähnlich wie const hinter der Methode ihn const macht. eXile und CodingCat predigen das schon seit Jahren, aber ich konnte bis ungefähr 2012 keine Wirkung beobachten. Dann sind dadurch in der Klasse tatsächlich ein paar Befehle weggefallen, und so habe ich es behalten.
Du hast recht damit, dass Visual C++ Attribute als überlappend annimmt. Deshalb hat man u.a. Leistungsgewinne knapp am zweistelligen Prozentbereich, wenn man alles von Klassen mit Methoden auf structs mit freien Funktionen umstellt (zumindest war das 2010 so, als ich's zuletzt probiert habe). Damals ist mir das aber nur zwischen Methodenaufrufen aufgefallen (A schreibt, dann liest B erneut, selbst wenn beide geinlinet werden). Jetzt ist mir zum ersten Mal aufgefallen, dass tatsächlich auch innerhalb der selben Funktion immer wieder neu geladen wird. Total irre. Vielleich steckt irgendeine kleinliche Win32- oder COM-Regel dahinter; ich weiß es nicht.
__declspec(restrict) bei der Deklaration einer Funktion sagt, dass der zurückgegebene Typ nicht aliast. Das möchtest du z.B. bei malloc() haben, weil der zurückgegebene Speicher sonst noch nirgends im Programm bekannt ist und deshalb mit nichts überlappen kann.
__restrict hinter einer Methode macht den this-Zeiger der Methode nicht-überlappend, ähnlich wie const hinter der Methode ihn const macht. eXile und CodingCat predigen das schon seit Jahren, aber ich konnte bis ungefähr 2012 keine Wirkung beobachten. Dann sind dadurch in der Klasse tatsächlich ein paar Befehle weggefallen, und so habe ich es behalten.
Du hast recht damit, dass Visual C++ Attribute als überlappend annimmt. Deshalb hat man u.a. Leistungsgewinne knapp am zweistelligen Prozentbereich, wenn man alles von Klassen mit Methoden auf structs mit freien Funktionen umstellt (zumindest war das 2010 so, als ich's zuletzt probiert habe). Damals ist mir das aber nur zwischen Methodenaufrufen aufgefallen (A schreibt, dann liest B erneut, selbst wenn beide geinlinet werden). Jetzt ist mir zum ersten Mal aufgefallen, dass tatsächlich auch innerhalb der selben Funktion immer wieder neu geladen wird. Total irre. Vielleich steckt irgendeine kleinliche Win32- oder COM-Regel dahinter; ich weiß es nicht.
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Hmmm … ich schreibe in toEndOfCommandParameters, was ein char * ist. Muss gemäß C++-Standard nicht bei char * *immer* Aliasing angenommen werden weil jedes Objekt dahin gecastet werden kann oder so?
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Code: Alles auswählen
void fuck() { }
namespace Foo {
enum Fuckers { fuck };
}
template <typename T> void fuck(T *, T *) {
fuck(); // ERROR: 'fuck' is ambiguous: could be 'void fuck()' or 'Foo::Fuckers::fuck'
}
void func() {
using namespace Foo;
::fuck(0, 0);
}
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Bitte sagt mir, dass dieses Verhalten ein Bug ist:
Das hier kompiliert:Jetzt bewegt breakFollowingFunction() mal über broken() und guckt, was passiert.
Die beiden Funktionen haben *nichts* miteinander zu tun. Ich kann nicht einmal erahnen, wie die Compiler-internen Strukturen aussehen müssen, um so ein Verhalten zu produzieren. Hat mich eine Stunde gekostet, das zu isolieren.
Das hier kompiliert:
Code: Alles auswählen
void fuck() { }
template <
typename T
> void fuck(T *) {
fuck();
}
namespace MustNotConsider {
enum { fuck };
}
namespace Important {
using namespace MustNotConsider;
template <typename T> void troublemaker() { }
void broken() {
int * dummy = nullptr;
::fuck(dummy);
}
void breakFollowingFunction() {
troublemaker<float>();
}
}
Die beiden Funktionen haben *nichts* miteinander zu tun. Ich kann nicht einmal erahnen, wie die Compiler-internen Strukturen aussehen müssen, um so ein Verhalten zu produzieren. Hat mich eine Stunde gekostet, das zu isolieren.
Re: Jammer-Thread
Borland und GCC compilieren das Minimalbeispiel NICHT.
Es wird für fuck(0,0) das Template nicht gefunden!
Borland:
::fuck(0, 0) -> Keine Übereinstimmung für 'fuck(int,int)' gefunden
fuck(0, 0) -> Mehrdeutigkeit zwischen 'fuck<T>(T *,T *)' und 'Foo::fuck'
GCC
::fuck(0, 0) -> too many arguments to function 'void fuck()'
fuck(0, 0) -> Foo::Fuckers Foo::fuck
candidates are: template<class T> void fuck(T*, T*)
candidates are: void fuck()
reference to 'fuck' is ambiguous
Kurzum: Borland hat das gleiche Problem wie VSC++ (Oder Clang? Clang erzeug zumindest EXAKT den gleichen Text, wie du oben kommentiert hast) und GCC kackt rum, weil es einen Funktionsaufruf mit 2 Parametern nicht dem Template zurodnen kann.
Cl
Es wird für fuck(0,0) das Template nicht gefunden!
Borland:
::fuck(0, 0) -> Keine Übereinstimmung für 'fuck(int,int)' gefunden
fuck(0, 0) -> Mehrdeutigkeit zwischen 'fuck<T>(T *,T *)' und 'Foo::fuck'
GCC
::fuck(0, 0) -> too many arguments to function 'void fuck()'
fuck(0, 0) -> Foo::Fuckers Foo::fuck
candidates are: template<class T> void fuck(T*, T*)
candidates are: void fuck()
reference to 'fuck' is ambiguous
Kurzum: Borland hat das gleiche Problem wie VSC++ (Oder Clang? Clang erzeug zumindest EXAKT den gleichen Text, wie du oben kommentiert hast) und GCC kackt rum, weil es einen Funktionsaufruf mit 2 Parametern nicht dem Template zurodnen kann.
Cl
Re: Jammer-Thread
Dein zweites Problem:
Clang: beschwert sich nicht (egal wie rum)
GCC: beschwert sich nicht (egal wie rum)
Borland: Ich sag einfach mal die gesamten Details :-D
[bcc32 Fehler] E2015 Mehrdeutigkeit zwischen 'fuck<T>(T *)' und 'MustNotConsider::fuck'
Vollständiger Parser-Kontext
Main.cpp(527): namespace Important
Main.cpp(539): Entscheidung zum Instantiieren: void void fuck<int>(int *)
--- Zurücksetzen des Parser-Kontexts für die Instantiierung...
Main.cpp(519): Analyse: void void fuck<int>(int *)
Clang: beschwert sich nicht (egal wie rum)
GCC: beschwert sich nicht (egal wie rum)
Borland: Ich sag einfach mal die gesamten Details :-D
[bcc32 Fehler] E2015 Mehrdeutigkeit zwischen 'fuck<T>(T *)' und 'MustNotConsider::fuck'
Vollständiger Parser-Kontext
Main.cpp(527): namespace Important
Main.cpp(539): Entscheidung zum Instantiieren: void void fuck<int>(int *)
--- Zurücksetzen des Parser-Kontexts für die Instantiierung...
Main.cpp(519): Analyse: void void fuck<int>(int *)
- Krishty
- Establishment
- Beiträge: 8344
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Jammer-Thread
Ach scheiße. Ich habe im ersten Beispiel auch das Template vergessen -.- My bad …
… das Zweite ist aber schon ziemlich aussagekräftig. Da schließen GCC und Clang aus, dass das using in die Template-Instanzierung einfließt (was ja auch schwachsinnig wäre). Ich habe es mit Visual Studio 2012 kompiliert; die Fehlermeldung musste ich selber schreiben weil Visual C++ nicht einmal die richtige Stelle im Quelltext gefunden hat um den Fehler anzuzeigen. Buärgh.
Weitergejammert: Ich habe eine Stunde damit verbracht, via SSE2 vier signed shorts zu floats zu konvertieren. Und der Gewinn gegenüber der skalaren Version ist Null, wenn nicht gar Verlust. Ich schreib’s trotzdem mal hierhin, falls es jemand braucht:
__m128 floatx4From(short const * toABCD) {
// 64-bit load:
auto abcd0000 = _mm_loadl_epi64(reinterpret_cast<__m128i const *>(toABCD));
// short to int: interleave with replicated sign bits
auto abcd = _mm_unpacklo_epi16(abcd0000, _mm_srai_epi16(abcd0000, 15));
// int to float:
return _mm_cvtepi32_ps(abcd);
}
… das Zweite ist aber schon ziemlich aussagekräftig. Da schließen GCC und Clang aus, dass das using in die Template-Instanzierung einfließt (was ja auch schwachsinnig wäre). Ich habe es mit Visual Studio 2012 kompiliert; die Fehlermeldung musste ich selber schreiben weil Visual C++ nicht einmal die richtige Stelle im Quelltext gefunden hat um den Fehler anzuzeigen. Buärgh.
Weitergejammert: Ich habe eine Stunde damit verbracht, via SSE2 vier signed shorts zu floats zu konvertieren. Und der Gewinn gegenüber der skalaren Version ist Null, wenn nicht gar Verlust. Ich schreib’s trotzdem mal hierhin, falls es jemand braucht:
__m128 floatx4From(short const * toABCD) {
// 64-bit load:
auto abcd0000 = _mm_loadl_epi64(reinterpret_cast<__m128i const *>(toABCD));
// short to int: interleave with replicated sign bits
auto abcd = _mm_unpacklo_epi16(abcd0000, _mm_srai_epi16(abcd0000, 15));
// int to float:
return _mm_cvtepi32_ps(abcd);
}
- Schrompf
- Moderator
- Beiträge: 5157
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Jammer-Thread
Linux ist zum Kotzen. Ja, immernoch. Jedes Mal, wenn mich irgendeine der Microsoftschen Rückwärts-Um-Die-Ecke-Indirekt-Lösungen ankotzt, denke ich mir: hey, Linux soll angeblich für Coder wie geschaffen sein, dann wechsel doch. Und dann komme ich in Linux an und stelle fest: ne, da stolpert man nur von einem selbstgebuddelten Grab ins andere. Und wird derweil noch von wechselnden Binary Interfaces und Paketkonflikten verarscht, gegen die die Windows DLL Hell ein RosaGlitzerParadies ist.
Aktuelles Hass-Objekt: die das Linux Input Subsystem. Da waren sie wieder heldenhaft stolz darauf, ein Hardware Interface auf ihr Filesystem abzubilden. Nur dass halt jedes Programm dann die Eingabe-Events lesen kann. Na huch, damit könnte man ja dann Passwörter mitschnüffeln! Also sind die Input Devices nur noch mit Rootrechten lesbar. Input Devices. Nur mit Root-Rechten. Und damit das ganze System faktisch nutzlos. Schön ein neues Grab selbstgebuddelt. Habt ihr toll gemacht.
Einzig Joysticks, Gamepads und so werden noch mit Schreib/Leserechten für normale User eingebunden. Irgendwann in vielleicht einem halben Jahr fällt dann einem der Helden dort auf, dass man auf SteamOS ja auch Passwörter und Kreditkartendaten mit dem Gamepad eingibt. Dann werden wahrscheinlich auch die Eingabegeräte nur noch mit Rootrechten lesbar sein.
Aktuelles Hass-Objekt: die das Linux Input Subsystem. Da waren sie wieder heldenhaft stolz darauf, ein Hardware Interface auf ihr Filesystem abzubilden. Nur dass halt jedes Programm dann die Eingabe-Events lesen kann. Na huch, damit könnte man ja dann Passwörter mitschnüffeln! Also sind die Input Devices nur noch mit Rootrechten lesbar. Input Devices. Nur mit Root-Rechten. Und damit das ganze System faktisch nutzlos. Schön ein neues Grab selbstgebuddelt. Habt ihr toll gemacht.
Einzig Joysticks, Gamepads und so werden noch mit Schreib/Leserechten für normale User eingebunden. Irgendwann in vielleicht einem halben Jahr fällt dann einem der Helden dort auf, dass man auf SteamOS ja auch Passwörter und Kreditkartendaten mit dem Gamepad eingibt. Dann werden wahrscheinlich auch die Eingabegeräte nur noch mit Rootrechten lesbar sein.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Chromanoid
- Moderator
- Beiträge: 4286
- Registriert: 16.10.2002, 19:39
- Echter Name: Christian Kulenkampff
- Wohnort: Lüneburg
Re: Jammer-Thread
Ja, das ist glaube ich ein nicht zu unterschätzendes großes Problem in Unix-Systemen. UAC ist jetzt auch nicht so toll, aber immerhin etwas. Ich weiß gar nicht wie da bei den populären Unix-OS momentan der Stand ist. Der interessante Ansatz eine VM pro Anwendungsdomäne ist für Spiele aber wahrscheinlich auch nicht so toll.
- Lynxeye
- Establishment
- Beiträge: 145
- Registriert: 27.02.2009, 16:50
- Echter Name: Lucas
- Wohnort: Hildesheim
- Kontaktdaten:
Re: Jammer-Thread
Ich verstehe offen gesagt das Problem gerade nicht. Wieso solltest du als normaler User die Events direkt vom Kernel abholen können? Mit den Kernelinterfaces sollte nur dein Windowsystem reden (also normalerweise der X Server), welches dann auch die entsprechenden Berechtigungen hat. Als normale Applikation reicht dir das Windowsystem die an dich adressierten Events doch durch. Genauso darf auch dein Grafiktreiber nicht einfach so mit dem Kernel reden, sondern bekommt vom Windowserver die entsprechende Berechtigung zugeteilt.