Jammer-Thread

Hier kann über allgemeine Themen diskutiert werden, die sonst in kein Forum passen.
Insbesondere über Szene, Games, Kultur, Weltgeschehen, Persönliches, Recht, Hard- und Software.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

C++ ist manchmal ätzend. Ich will einen eigenen Comparator in einer std::map einsetzen. Angeblich nimmt das Ding ein Binary Predicate. Also geb ich ihm eine banale freistehende Vergleichsfunktion.

Code: Alles auswählen

bool VergleicheDasUndMeckerNich( const IfcVector3& a, const IfcVector3& b ) { return bla blubb; }
std::map< IfcVector3, Bla, VergleicheDasUndMeckerNich> mappe;
Und VC++ so: ist kein gültiges template-Typargument für den _Pr-Parameter.

Und warum? Vermutlich, weil irgendwo da drin jemand nur an FunkyFunctor gedacht hat und es unbedingt ne Objekt-Instanz sein muss, keine normale Funktion. Grmpf.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2380
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Jonathan »

Jaaa, mit templates hatte ich heute auch wieder eine Menge Spaß. Letztendlich habe ich hinbekommen, was ich machen wollte, dafür muss ich jetzt bei fast jeder Änderung fast das ganze Programm neu kompilieren, weil ich alles inkludieren statt linken muss. Yay!

Zu deinem Problem: Ich glaube, das Problem ist, dass du einen Wert und keinen Typ hast. Du müsstest also als template Parameter die Signatur der Funktion (oder so) übergeben, hättest dann aber immer noch keinen Comparator sondern bloß den Comparator-Typen gesetzt. Du musst vermutlich den Konstruktor mit Comparator-Parameter aufrufen, dann musst du noch nichteinaml den Comparator-Typen setzen, weil den der Compiler ja von dem Parameter ableiten kann. Und wenn du die Funktion nicht direkt übergeben kannst, sollte es gehen wenn du sie in eine std::function wrapst. Insgesamt also:

Code: Alles auswählen

bool VergleicheDasUndMeckerNich( const IfcVector3& a, const IfcVector3& b ) { return bla blubb; }
std::map< IfcVector3, Bla> mappe(std::function(VergleicheDasUndMeckerNich));
(dafür müsste dann deine Funktion aber irgendwie den selben Typen wie std::less haben. Sollte aber ansich hinkommen, irgendwie.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

Danke. Ich hatte noch versucht, den Funktionszeiger als Template-Parameter anzugeben und die Funktion dann als Instanz davon im Konstruktor, aber ich bin anscheinend etwas eingerostet, was die Funktionszeiger-Syntax angeht. Aber eigentlich war das ja unnötig, solange die Funktion nur die selbe Signatur hat wie std::less(). Und das sollte wirklich möglich sein. Danke!
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

Apropos Funktionszeiger-Syntax: Habe wieder eine Stelle, wo Visual Studio für Referenzen und Zeiger auf Funktionen unterschiedliches Verhalten zeigt. Genauer: Funktionszeiger funktionieren, Funktionsreferenzen stürzen einfach ab. Ach, VS -.-
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Jonathan
Establishment
Beiträge: 2380
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Jonathan »

Kennt ihr das, wenn man "nur noch schnell was ausprobiert, und wenn es tut den Code nochmal neu und sauber schreibt"? Ich mach das gerade und mein "nur mal schnell was testen"-Hack wird echt hässlich:

Code: Alles auswählen

	if(std::is_same<RenderUpdateFunction, Residual::PositionUpdate>::value)
	{
		using t_ResidualFunction = Residual::Function<Residual::PositionUpdate, ResidualFunction>;
		...
Schlimm genug, dass ich zur Laufzeit Typen prüfe (obwohl die Abfrage nach der Template-Auswertung direkt rausfallen sollte, if(true) ist nur wirklich trivial optimierbar), nein ich benutze den Typen dann auch noch explizit, statt die Typvariable zu benutzen. Weil ich sonst aus Gründen die ich hier gar nicht näher erläutern will eklige Linker-Fehler bekäme...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

Verdammte Prinzipienreiter.

Code: Alles auswählen

class Bla {
  Bla( int blubb, float quiffel, EingabeDaten& daten = EingabeDaten()) { ... }
};
Visual Studio sprach: "Klar, mach Dein Ding, alles entspannt"
GCC jedoch wurde sehr zornig und rief entrüstet aus:
gcc hat geschrieben:error: could not convert 'EingabeDaten()' from 'EingabeDaten' to 'EingabeDaten&'
Ich kann die Ref aber nicht const machen, weil sie im Nicht-Default-Fall durchaus verändert werden muss. Und ich will sie nicht mit Move durch die Gegend schieben müssen, bis sie am Ende dort angekommen sind, wo sie hinmüssen. Mistgriebel.
Zuletzt geändert von Krishty am 18.02.2015, 17:01, insgesamt 2-mal geändert.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Jammer-Thread

Beitrag von dot »

Schrompf hat geschrieben:Ich kann die Ref aber nicht const machen, weil sie im Nicht-Default-Fall durchaus verändert werden muss.
D.h. eigentlich willst du einen zweifach überladenen Konstruktor anstatt einem mit Defaultargument... :P
Zuletzt geändert von dot am 18.02.2015, 17:04, insgesamt 2-mal geändert.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

dot hat geschrieben:
Schrompf hat geschrieben:Ich kann die Ref aber nicht const machen, weil sie im Nicht-Default-Fall durchaus verändert werden muss.
D.h. eigentlich willst du zwei Konstruktoren anstatt einem mit Defaultargument... :p
Nein, eigentlich will ich den Mist nicht doppelt schreiben :-) Ich habe mich dazu inzwischen begoogelt, und alle Welt meint dazu "Mach zwei Funktionen draus". Aber bei mir werden die Parameter noch über zwei drei Ecken weitergeleitet, und ich will eigentlich *nicht* all diese Funktionen verdoppeln, nur um es dem feinen Herrn GCC recht zu machen.

Aber es ist wohl ein Hinweis auf ein grundsätzliches Design-Problem, also werde ich dazu mal ne Diskussion aufmachen. Vielleicht fällt euch ja was ein.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Jammer-Thread

Beitrag von dot »

Schrompf hat geschrieben:Aber bei mir werden die Parameter noch über zwei drei Ecken weitergeleitet, und ich will eigentlich *nicht* all diese Funktionen verdoppeln, nur um es dem feinen Herrn GCC recht zu machen.
Dass MSVC da nicht schreit ist ein ziemlich schwerer Mangel der leider aus Kompatibilitätsgründen seit Generationen mitgeschleppt wird. Idee für eine Krücke: Schreib dir eine Funktion, die das Datenverändern macht und eine ref to const auf die veränderten Daten returned, dann können beide Ctoren einfach an die selbe Funktion weiterleiten.

Abgesehen davon würde ich mir allerdings rein prinzipiell doch schwer überlegen, ob die Konstruktion eines Objektes wirklich Seiteneffekte haben sollte... ;)
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

Klar, warum keine Seiteneffekte? Wenn Du es Dir als Move-Operation vorstellst, ist es wieder "design" und kein Seiteneffekt mehr :-) Aber ich habe inzwischen einfach die Referenz entfernt und reiche die paar Zeiger und Zahlen als Kopie rum. Bei ner CubeMap mit MipMaps sind das dann zwar schon einige Dutzend Werte, aber das passiert selten genug und der Compiler kann da sicher was optimieren.

Mein neuester Aufreger ist thematisch ziemlich ähnlich.

Code: Alles auswählen

void TuWas( Bla* bla);
TuWas( &Bla( 1, 3, 5.0));

Code: Alles auswählen

error: taking an address of a temporary [-fpermissive]
Wieder derselbe Mist. Das temporäre Objekt sollte doch bis zur Rückkehr der Ausführung aus der Funktion lebendig sein, oder? Ist das also nur deswegen ein Fehler, weil der Herr GCC denkt, dass ich evtl. irgendwo dadrin den Zeiger behalte?
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

Hach, prinzipienreitende Compiler bringen doch immer wieder Sonnenschein.

Kollisionsabfragen programmieren übrigens auch. Ich hielt die Mathematik immer für das Schlimmste, aber die Logik um Mehrfachkollisionen usw abzudecken ist auch nicht ohne :(
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
NytroX
Establishment
Beiträge: 365
Registriert: 03.10.2003, 12:47

Re: Jammer-Thread

Beitrag von NytroX »

Das temporäre Objekt sollte doch bis zur Rückkehr der Ausführung aus der Funktion lebendig sein, oder?
Nö, warum? :D
Die Argumente müssen ausgewertet werden, bevor die Funktion aufgerufen wird. Aber danach wird ja nur der Zeiger by value übergeben (genauer: kopiert), das Objekt wandert direkt aus dem Scope.
Du kannst dir das Pseudo-Lambda-code-mäßig ja so vorstellen:

Code: Alles auswählen

TuWas(
{
 Bla bla(1,3,5.0); return &bla;
} //und tschüss, bla-Objekt! Hallo, pointer ins nirgendwo :-)
);
Aus meiner Sicht ist die Warnung völlig richtig, hätte nicht gedacht dass das überhaupt annähernd funktioniert :shock: .
Ansonsten müsstest du ja halt anders scopen:

Code: Alles auswählen

{
Bla bla(1,3,5.0);
TuWas(&bla);
} //bla bleibt auf jeden Fall bis zum return erhalten
Ich denke mal, meistens wird das schon passen, weil der Compiler nicht die Destruktor-Calls nicht vor den Funktionsaufruf reinbastelt, sondern aus Effizienzgründen bis zum Ende der äußeren Funktion wartet.
Aber ich glaube das ist nicht garantiert.
Der Standard sagt:
During the initialization of a parameter, an implementation may avoid the construction
of extra temporaries by combining the conversions on the associated argument and/or the construction
of temporaries with the initialization of the parameter (see 12.2).
und
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations
take effect before the function is entered.
Anderes Beispiel:

Code: Alles auswählen

TuWas(Bla(1,3,5.0));
Geht ja auch nur, wenn Bla einen Copy- oder Move-Contructor hat; der Parameter selbst (das temporäre Bla-Objekt) muss in der Funktion ja gar nicht mehr gültig sein.
Der Compiler wird das Copy oder Move wahrscheinlich trotzdem weg-optimieren und das Objekt in-place erzeugen, würde ich mal annehmen/hoffen (ist ja explizit im Standard erlaubt).
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

NytroX hat geschrieben:
Das temporäre Objekt sollte doch bis zur Rückkehr der Ausführung aus der Funktion lebendig sein, oder?
Nö, warum? :D
Weil man sonst unmöglich aus einem Parameter lesen könnte? Natürlich bleiben temporäre Parameter bis zur Rückkehr des Aufrufers erhalten. Und Visual C++ macht es richtig, da nicht zwischen lvalue und rvalue zu unterscheiden. Der Unterschied ist so bescheuert und nutzlos, dass ihn sowieso kaum einer rafft. Der ist nur erfunden worden, damit Paragraphenreiter was zu nörgeln haben und Sprachwissenschaftler sich schlau vorkommen können. Oder weil eine arme Sau 1967 zwei Lochkarten sparen wollte.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: Jammer-Thread

Beitrag von DerAlbi »

:cry: Ach Leute :cry:
ich kann einfach nicht mehr programmieren. Alles, was mal war ist irgendwie weg. Mein Hirn windet sich erbärmlich umd Algorithmen zu finden...
ich bin zu faul komplexe Probleme anzugehen.. und aaawww mein Code sieht einfach nur noch scheiße aus. Man kanns nicht anders sagen.
Zudem hat sich noch die IDE geändert... Auf der Platform auf der ich programmiere bin ich jetzt auf ein VisualStudio-Klon angewiesen... zuletzt habe ich (vor 2 Jahren) ein 3 Jahres-Projekt in Eclipse gearbeitet und das war einfach.. soooo viel besser- intuitiv und nicht behindernd. Die Code vervollständigung und alles.. ist jetzt einfach alles Mist. Man kann entweder zu viel Eigenintelligenz einstellen,sodass man quasi immer nur am ESC-drücken ist, nur weil man irgendwo einen Variablennamen ändert und nicht in die Zeile darunter kommt.. oder man hat gleich zu wenig Eigenintelligenz. Mich kotzt VisualStudio einfach an.
Mir macht das alles keinen Spaß mehr.
Albi dumm, Studio dumm, alles dumm.
antisteo
Establishment
Beiträge: 854
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: Jammer-Thread

Beitrag von antisteo »

DerAlbi hat geschrieben::cry: Ach Leute :cry:
ich kann einfach nicht mehr programmieren. Alles, was mal war ist irgendwie weg. Mein Hirn windet sich erbärmlich umd Algorithmen zu finden...
ich bin zu faul komplexe Probleme anzugehen.. und aaawww mein Code sieht einfach nur noch scheiße aus. Man kanns nicht anders sagen.
Zudem hat sich noch die IDE geändert... Auf der Platform auf der ich programmiere bin ich jetzt auf ein VisualStudio-Klon angewiesen... zuletzt habe ich (vor 2 Jahren) ein 3 Jahres-Projekt in Eclipse gearbeitet und das war einfach.. soooo viel besser- intuitiv und nicht behindernd. Die Code vervollständigung und alles.. ist jetzt einfach alles Mist. Man kann entweder zu viel Eigenintelligenz einstellen,sodass man quasi immer nur am ESC-drücken ist, nur weil man irgendwo einen Variablennamen ändert und nicht in die Zeile darunter kommt.. oder man hat gleich zu wenig Eigenintelligenz. Mich kotzt VisualStudio einfach an.
Mir macht das alles keinen Spaß mehr.
Albi dumm, Studio dumm, alles dumm.
Dann werd' doch Consultant.

Mit fehlt auch inzwischen die Motivation, mich selbst an den Code zu setzen. Wozu bezahlt man schließlich andere dafür ....
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4261
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Jammer-Thread

Beitrag von Chromanoid »

Chromanoid hat geschrieben:Ich weiß ich krieg gleich wieder auf die Mütze, aber mich würde wirklich mal interessieren, was C++ Freunde mal abgesehen von Java als Abhängigkeit und Groovy als Sprache von Gradle halten. Für Java läuft das Buildsystem schon echt gut und ich benutze es recht gerne. Vielleicht hat ja jemand mal Lust das ganze mit seinem Projekt auszuprobieren: http://www.gradle.org/docs/current/user ... aries.html

BTW das Gradle für C++ ist noch nicht produktionsreif, aber der generelle Gradle Ansatz gefällt mir. Vielleicht hat ja der ein oder andere Spaß dran, das ganze mal auszuprobieren.
Nur mal ein Nachtrag: Unity3D wird jetzt intern mit Gradle gebaut bzw. das Buildverfahren wird von Make auf Gradle umgestellt.
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

Ich habe angefangen, in meiner Engine SIMD zu benutzen. Ich benutze SSE schon länger für Spezialfälle wie Conditional Move, schnelle Quadratwurzel, usw – aber immer nur eine Spur der Register für kleine serielle Dinge. Ich habe mich lange gesträubt, über vier floats gleichzeitig drüberzurutschen (vor allem aus Gründen der Lesbarkeit und Portierbarkeit); aber nun habe ich dennoch einen beherzten Versuch gewagt.

Tatsächlich messe ich 10 % Beschleunigung durch zwei Stellen in einer inneren Schleife, die nun mit drei floats parallel arbeiten (Vertex-Transformationen und Backface Culling). Die EXE ist um 0,5 % geschrumpft.

Das waren aber nur 20 Zeilen. Überall sonst ist der Effekt genau umgekehrt. SSE für Vektor-Normalisierung? Langsamer als seriell und 1 % größeres Programm. SSE für Kreuzprodukt? Bricht total ein. Ich habe eben drei Stunden vor einer SSE-Matrixmultiplikation verbracht, und sie erreicht gerade mal die Leistung der seriellen Variante. Alle vorherigen Versuche gingen total nach hinten los.

Die Katastrophe war dann, alle Vektorberechnungen auf Multimedia-Register umzustellen. Ich habe mich zwei Stunden lang durch Maschinenbefehle gewühlt, und letztendlich war trotzdem alles langsamer auf fetter. Dir Rückgabe ist die Pest; Visual C++ verschüttet die Rückgabewerte dauernd auf den Stapelspeicher. Zwar werden die Register drei Mal so effizient ausgenutzt (habe leider nur X, Y, & Z), aber dafür bewirkt das Shuffling dermaßen viele temporäre Werte, dass der Registerdruck dennoch steigt. Irre. Da weiß man sofort, warum andere Befehlssätze hunderte Register haben.

Außer 20 Zeilen für zwei Hotspots ist das also total für die Katz’. ryg hat’s ja gesagt.

Mit SSE3/4 könnte das anders sein, aber die Erfahrungsberichte lesen sich nicht sehr euphorisch. Mit AVX sinkt der Overhead von Shuffling und horizontalen Summen beträchtlich, und allein durch die Befehlskodierung kann man schon mit Leistungsverbesserungen rechen. Aber da kann ich nochmal 15 Jahre warten, bis das jeder Anwender unterstützt. Bah.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Jammer-Thread

Beitrag von dot »

Krishty hat geschrieben:Dir Rückgabe ist die Pest; Visual C++ verschüttet die Rückgabewerte dauernd auf den Stapelspeicher. Zwar werden die Register drei Mal so effizient ausgenutzt (habe leider nur X, Y, & Z), aber dafür bewirkt das Shuffling dermaßen viele temporäre Werte, dass der Registerdruck dennoch steigt. Irre. Da weiß man sofort, warum andere Befehlssätze hunderte Register haben.
Auch mit __vectorcall?
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: Jammer-Thread

Beitrag von DerAlbi »

Also ich finde das auch merkwürdig. Wenn man überlegt, dass z.B. ein I7 bis zu 29 Instruktionen pro Takt schafft (kA, ob das für alle cores gilt, oder für einen o_O Ist egal. Selbst wenn man das durch 8 teilst isses doch =4). Wenn man wirklich mit der vorhanden Rechenleistung datenverarbeitung betriebt und rechnet KANN man doch gar nicht schneller sein. Man ist doch unweigerlich speicherbandbreiten begrenzt, oder? Sequenzielle daten mögen gerade noch gehen.. aber wenn man ü erlegt wie arschlahm RAM eigentlich ist... gerade bei Adresswechsel. paah.
Ich glaube, dass SIMD was bringt hängt extrem vom Datenlayout ab. Ich persönlich habe mega gute erfahrungen auf einer Platform gemacht, die nativ 32bit hat und wo SIMD dann auf 4x 8bit angewendet worden ist. Damit konnte man zumindest farbvektoren im Software-3D Renderer wesentlich besser verarbeiten oder 64bit-Vektoren, wenn diese auf 4x 16Bit Fixpoint basieren. Pro texturierten Pixel hatte ich nur noch 17 Takte benötigt. (RISC)
Aber da war von vorn herein auch alles darauf ausgelegt parallelisiert zu werden. Datenlayout ist da halt wichtig. wenn man Anfängt aufnicht-ausgerichteten adressen zu arbeiten oder die floats erst zusammensucht, um sie parallel zu verarbeiten... näääh geht nich. Aber gut. Als RISC-Mensch... bei mir ist das alles deterministischer :-D
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

dot hat geschrieben:
Krishty hat geschrieben:Dir Rückgabe ist die Pest; Visual C++ verschüttet die Rückgabewerte dauernd auf den Stapelspeicher. Zwar werden die Register drei Mal so effizient ausgenutzt (habe leider nur X, Y, & Z), aber dafür bewirkt das Shuffling dermaßen viele temporäre Werte, dass der Registerdruck dennoch steigt. Irre. Da weiß man sofort, warum andere Befehlssätze hunderte Register haben.
Auch mit __vectorcall?
Habe ich garnicht erst versucht, weil sich das vor allem auf sowieso geinlinete Funktionen bezog. Es findet kein Funktionsaufruf mehr statt, aber trotzdem sind da sechs movaps zum und vom Stapel. WTF.
DerAlbi hat geschrieben:Aber da war von vorn herein auch alles darauf ausgelegt parallelisiert zu werden. Datenlayout ist da halt wichtig. wenn man Anfängt aufnicht-ausgerichteten adressen zu arbeiten oder die floats erst zusammensucht, um sie parallel zu verarbeiten... näääh geht nich. Aber gut. Als RISC-Mensch... bei mir ist das alles deterministischer :-D
Auf das Layout habe ich quasi keinen Einfluss mehr, das ist verlorener Posten. War halt nicht mein Design :( Und ein Neu-Design lohnt sich erst, wenn Visual C++ irgendwann mal Address Of Label implementiert.

Ich habe hier eine Stelle, wo ich die Größe des Arbeitssatzes (also RAM-Durchsatz) gegen Layout abwägen muss: Ein Batzen Vertices liegt in 16-Bit-shorts vor. SSE 2 kriegt es um’s Verderben nicht auf die Kette, die effizient zu float zu konvertieren. Alles, was mit 16-Bit-Zahlen zu tun hat, läuft nur noch über die MMX-Register, die in x64 sowieso nicht mehr ansprechbar sind. Vier ints zu vier floats konvertieren? Als ob – den Befehl gibt es nur als skalar oder als 2er-Vektor (!). Ach die schönen Legacy-Befehle. Und wenn ich alles mit 32-Bit-ints aufziehe, pumpe ich in der innersten Schleife doppelt so viele Daten durch die CPU. Ganz zu schweigen davon, dass ich dann immernoch zwei Loads pro Element brauche, weil es ja keine 96-Bit-Operationen gibt. WTF. Als ich anfing, zwei 16-Bit-Zahlen im 64-Bit-Allzweckregister aufzupusten um das durch den Speicher in zwei floats der SIMD-Einheiten zu aliasen, habe ich hingeschmissen, weil der Scheiß ja Endian-abhängig ist und ich die Stelle niemals wieder finde wenn ich mal für ARM kompiliere. Bah. Und über die Umwege wär’s dann sowieso lahmer gewesen als drei skalare Konvertierungen, die zwar hintereinander laufen, aber zumindest direkt durch Register, mit Daten, die halb so viel RAM schlucken.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: Jammer-Thread

Beitrag von DerAlbi »

Tjaaah wer floaten will muss loaden ^_^
Ich weiß noch nicht ganz wieso das aufpusten auf die doppelte größe ein so großes gegenargument ist. Wichtig ist, dass man das nur während der cpu-internen arbeiten macht, das lesen und rausschreiben wird davon beeinflusst... aber wenn man eh 64bit register hat... man schleppt die bits in der Pipeline ja eh ungenutzt mit rum. der cache ist auch mindestens so breit angeschlossen. letztlich hat es doch schon fast weniger sinn, auf weniger als 64bit zu arbeiten, oder? Also aufpusten, lokal in der pipeline/cache rechnen, schrumpfen, zurückschreiben.
Sry, nicht dass ich da tieferes wissen habe. Lass mich doch naiv daherlabern :-)
btw: _mm_cvtpi32x2_ps
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

Na wegen der, wie du selber gesagt hast, Speicherbandbreite. Alles doppelt so groß machen bedeutet auch die doppelte Belastung auf dem RAM-Bus, wenn man die Dinger verarbeitet, und effektiv halb so viel Cache. Und das limitiert ja eh immer.

Bzgl _mm_cvtpi32x2_ps: Das ist nichts weiter als der doppelte Aufruf des Intrinsics. Die Parametertypen, __m64, sind auf x64 zwar deklariert, aber nicht als Registertypen verwendbar. Was auch immer ich übergebe, muss also erstmal auf den Stack geschrieben werden und von dort lädt es das Intrinsic. Ich habe also die Wahl zwischen (Pseudo-Assembler):

  MOV EAX, WORD PTR [foo.x]
  MOV EBX, WORD PTR [foo.y]
  MOV ECX, WORD PTR [foo.z]
  MOVD XMM0, EAX
  MOVD XMM1, EBX
  MOVD XMM2, ECX
  CVTSI2SS XMM0, XMM0
  CVTSI2SS XMM1, XMM1
  CVTSI2SS XMM2, XMM2


was seriell ist, aber dafür direkt über die Register rutscht, oder via _mm_cvtpi32x2_ps

  MOV EAX, WORD PTR [foo.x]
  MOV EBX, WORD PTR [foo.y]
  MOV ECX, WORD PTR [foo.z]
  SHL RAX, 32 ;
X und Y in einem Register kombinieren
  OR RAX, RBX
  MOV QWORD PTR [localInt64], RAX ;
Einen 128-Bit-Speicherbereich mit X, Y, und Z in 32-Bit-Form anlegen
  MOV QWORD PTR [localInt64+8], RCX
  CVTPI322PS XMM0, XMMWORD PTR [localInt64]
  CVTPI322PS XMM1, XMMWORD PTR [localInt64+8]
  SHUFPS XMM0, XMM1, 0beidezusammenH


was trotz Parallelisierung die Konvertierungen von drei nur auf zwei drückt und dabei einen Umweg über den Speicher macht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

Aber Danke für den Link zu ryg - ich habe da gerade eine Stunde mit eskalierender Geek-Neugier verbracht und mich durch seinen Blog geblättert.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Krishty »

Durch seine Webseite, die ich verlinkt habe, oder wirklich durch seinen Wordpress-Blog?

Er war damals einer der Programmierer hinter .kkrieger, dem 96-KiB-Ego-Shooter. Heute arbeitet er bei RAD, zusammen mit cbloom, dessen Blog mich ein halbes Jahr ausgelastet hat.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4864
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Schrompf »

Beides :-) Aber Danke nochmal für cbloom. Der ist mir vor langer Zeit schon mehrfach im Netz begegnet, und jetzt hab ich mich wieder festgelesen. Wobei ich rygs Philosphierereien zu Prozessorarchitektur spannender finde.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2380
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Jonathan »

Ach Qt und Initialisierung von Objekten. Es ist soo grausam.

Ich benutze den Designer, um das GUI zu erstellen. Der hat die praktische Funktion "promote Widget" mit dem man auch eigene Widgets im Designer benutzen kann. Soweit so toll.

Jetzt habe ich ein Widget, dass mit OpenGL ein bisschen was rendern soll. Dazu speichert es unter anderem einige Infos über die Szene, sowie OpenGL Ressourcen. Und spätestens jetzt fängt der Spaß an. Wo initialisiert man das am besten? Das Widget soll die Szene ja nur anzeigen, also wir sie von außen definiert. Jetzt kann ich aber kein RAII benutzen, d.h. die Szene als Konstruktorparameter übergeben, weil Qt ja seinen eigenen Präprozessor (MOCing) hat und den Code generiert - Konstruktorparameter sind unmöglich.
Man könnte jetzt meinen, das sei nicht so schlimm, man kann ja im Hauptfenster erst setupUi() aufrufen (das den generierten Code zur GUI-Erstellung ausführt) und dann nochmal eine Initialisierungsfunktion. Aber das geht nicht, weil sowas wie Vertex-Buffer ja ein initialisiertes OpenGL voraussetzen. Und OpenGL wird in Qt erst irgendwann nach dem Erstellen initialisiert, und zwar erst nach sämtlichen Konstruktoren, man wird es irgendwann per Event darüber informiert, dass man es ab jetzt benutzen kann. Ich darf also im Konstruktor der Hauptklasse noch nichts erstellen, ich könnte höchstens Werte durchreichen, die das OpenGL Widget zwischenspeichert und benutzt sobald der Kontext erstellt ist. Ich habe dann auch teilweise einfach ein Callback erstellt, damit das Hauptfenster Code ausführen kann, sobald OpenGL im entsprechenden Widget initialisiert ist.
Und im Moment will ich einen Vertexbuffer mit passenden Daten füllen. Diese soll man beim Erstellen setzen können, aber auch hinterher wieder ändern können. Aber beim Erstellen gibt es den Kontext vielleicht noch gar nicht, daher kann ich höchstens die Parameter zwischenspeichern. Wenn ich aber später die Werte nochmal ändern will, muss ich den Vertexbuffer ja direkt verändern (weil kein weiteres 'initialisiert'-Event kommen wird), ich brauche also entweder eine Abfrage, ob OpenGL schon initialisiert ist, oder muss zwei verschiedene Funktionen anbieten, die man dann jeweils nur beim Initialisieren oder Ändern aufrufen darf.

Letztendlich führt es also dazu, dass man die Klassen sehr viel umständlicher und unübersichtlicher programmieren muss, nur weil Qt irgendeine bescheuerte Initialisierung erzwingt. Nichts das irgendetwas davon sonderlich schwer umzusetzen wäre, aber ich hasse es, wenn ich nicht selber daran schuld bin, wenn mein Code hässlich ist...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Jonathan
Establishment
Beiträge: 2380
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Jonathan »

glm ist ein exakter Nachbau der glsl Matheklassen. Das ist super. Aber soweit ich das sehe gilt:

Der mat4 Konstruktor in glsl ist Column-Major, der mat4 Konstruktor ist Row-Major.

meh, warum??


Ist ne Lüge, siehe unten.
Zuletzt geändert von Jonathan am 11.03.2015, 15:11, insgesamt 1-mal geändert.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Jammer-Thread

Beitrag von dot »

Jonathan hat geschrieben:[...] der mat4 Konstruktor ist Row-Major.
Das wäre mir neu... ;)
Benutzeravatar
Jonathan
Establishment
Beiträge: 2380
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Jammer-Thread

Beitrag von Jonathan »

Jup, habe mir das eben nochmal genauer angesehen und es ist in der Tat Column-Major. Ich war nur verwirrt, weil ich dachte, die Matrix müsste anders aussehen und es müsste Row-Major sein, damit es so funktionieren kann. Glück gehabt :)
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Jammer-Thread

Beitrag von dot »

glm ist dennoch imo ziemlicher Mist, allein dass ich tatsächlich immer voll-qualifizierte Funktionsnamen benutzen muss weil es kein ADL supported...passt also schon in den Jammer Thread... :P
Antworten