Speicheroptimierung: was ist sinnvoll, was nicht?
-
Arcoth schrieb:
schluderer schrieb:
Gut, ich präzisiere: Es ist falsch.
Das Alignment kann nie größer als der Typ selbst sein, weil sonst Array-Elemente nicht direkt hintereinander liegen könnten, was aber immer der Fall ist. Ich sehe den Fehler nicht.
Alignment ist eine Eigenschaft von Objekten, nicht Typen. Der Typ erzwingt lediglich ein Mindestalignment für alle Objekte dieses Typs. Und dieses Mindestalignment ist immer ein Teiler der Größe des Typs (hier greift das Array-Argument).
-
Tip: schluderer meint vermutlich Alignment-Requirement (ich hoffe das ist jetzt der richtige Fachbegriff) <-> Alignment. Das Alignment darf natürlich immer grösser sein.

Ich meinte mehr oder wenigeralignof(foo) <= sizeof(foo), und ja, das ist dann wohl ein 'Alignment-Requirement' (oder wie auch immer es genannt wird).Ja, das Missverständnis lag wohl darin, dass ich dachte, Alignment ist eine dem Typ innewohnende Sache.
Man hätte es genau so gut "word" oder "smallest adressable memory unit" nennen können. Dann wären Generationen von C++ Programmierern weniger verwirrt, und es gäbe eine Sache weniger mit der Generationen von Schlaumeiern rumnerven könnten.
Bezeichnet nicht alle Welt mit Byte die kleinste adressierbare Einheit? So habe ich den Begriff aufgefasst, und demnach ist ein char auch immer ein "Byte" groß. Ich verstand nur nicht, was du "größer machen willst". Die Bitzahl?
-
Also für mich ist ein Byte eigentlich immer ein Oktett, nur hier im Forum und um C++-Standard muss man sich da anstrengen, ansonsten gibt's schnell Haue...
-
hustbaer schrieb:
Ich glaube du solltest selbst noch ein wenig zum Thema Structure Packing lesen, denn das meiste von dem was du schreibst stimmt nicht.
Du hast Recht. Die Werte werden natürlich anhand ihrer Größe aligned und nicht allgemein auf Wortgröße. Das würde keinen Sinn ergeben.
-
Pria == blurry ?
-
Arcoth schrieb:
Man hätte es genau so gut "word" oder "smallest adressable memory unit" nennen können. Dann wären Generationen von C++ Programmierern weniger verwirrt, und es gäbe eine Sache weniger mit der Generationen von Schlaumeiern rumnerven könnten.
Bezeichnet nicht alle Welt mit Byte die kleinste adressierbare Einheit? So habe ich den Begriff aufgefasst, und demnach ist ein char auch immer ein "Byte" groß. Ich verstand nur nicht, was du "größer machen willst". Die Bitzahl?
Boah, stell dich bitte nicht dümmer als du bist.
Ja, klar die Bitzahl. Bzw. anders gesagt wie viele "Byte" (nicht im C++ Sinn, sondern so wie der Rest der Welt den Begriff versteht) ein char gross ist.
Ein Byte hat 8 Bit. Das ist ein De Facto Standard.
Und Systeme wo die kleinste adressierbare Einheit grösser als 8 Bit ist nennen diese normalerweise Word und nicht Byte.
Nur der C++ Standard muss verwirrenderweise trotzdem den Begriff Byte verwenden.
-
hustbaer schrieb:
Wie gross ein Handle ist kann man sich normalerweise nicht aussuchen, das bestimmt das OS/die API des Geräts mit dem man arbeitet.
Sicher, das trift aber z.b. nicht auf OGL zu (deswegen das Beispiel), da ist das Handle ein uint32 Wert mit vortlaufender Nummer, von daher kann man da z.b. mit einem ushort optimieren.
Für das enum habe ich mal spasseshalber ein Template-Container angelegt der den Wert als 16 bit wert ablegt und konnte hier keine Unterschiede zu Performance feststellen.
template<typename T> struct cenum { unsigned short value; public: cenum() : value(T()) {} T get() {return (T)value;} operator T () { return (T)value; } T* operator-> () {return (T*)&value;} void operator =(T val) {value = (unsigned short)val;} void set(T val) {value = (unsigned short)val;} };Ich weiß jetzt natürlich nicht wie das ist bei Playstation und Co. da die ja normalerweise nicht mit OGL arbeiten
-
Pria schrieb:
hustbaer schrieb:
Wie gross ein Handle ist kann man sich normalerweise nicht aussuchen, das bestimmt das OS/die API des Geräts mit dem man arbeitet.
Sicher, das trift aber z.b. nicht auf OGL zu (deswegen das Beispiel), da ist das Handle ein uint32 Wert mit vortlaufender Nummer, von daher kann man da z.b. mit einem ushort optimieren.
Für das enum habe ich mal spasseshalber ein Template-Container angelegt der den Wert als 16 bit wert ablegt und konnte hier keine Unterschiede zu Performance feststellen.
template<typename T> struct cenum { unsigned short value; public: cenum() : value(T()) {} T get() {return (T)value;} operator T () { return (T)value; } T* operator-> () {return (T*)&value;} void operator =(T val) {value = (unsigned short)val;} void set(T val) {value = (unsigned short)val;} };Ich weiß jetzt natürlich nicht wie das ist bei Playstation und Co. da die ja normalerweise nicht mit OGL arbeiten
*lach*
-
Und Systeme wo die kleinste adressierbare Einheit grösser als 8 Bit ist nennen diese normalerweise Word und nicht Byte.
Nur der C++ Standard muss verwirrenderweise trotzdem den Begriff Byte verwenden.Alles klar, merke ich mir.
Für das enum habe ich mal spasseshalber ein Template-Container angelegt der den Wert als 16 bit wert ablegt und konnte hier keine Unterschiede zu Performance feststellen.
Natürlich nicht, weil alles geinlined wird (was ist das überhaupt für ein "Performance-Test"?). Du kannst auch gleich den unterliegenden Typ ändern, wie cooky schon viel weiter vorne demonstriert hat, dann wirst du auch rein theoretisch keine Unterschiede feststellen können.
Übrigens, es gibt noch die
ganz feineOption -fshort-enums vom GCC.
-
Koennen enums nicht auch als Bitset realisiert sein? Gibt es da eine konkrete Mindestgroesse des Typs?
-
Auch ein bitset hat natürlich eine Mindestgröße von 1.
-
Nun, bei 4 Enums reichen 2 Bit. Andere Systeme konnen auf Bitebene lesen/schreiben. Deswegen frage ich. Und bei Groessenangaben macht eine Zahl ohne Einheit keinen Sinn. Ist es standardisiert, dass Bitsets bzw. alle Dinge mindestens 1 Byte/Char/whatever gross sind?
-
knivil schrieb:
Koennen enums nicht auch als Bitset realisiert sein?
Meinst du Bitfield?
Und ja, das darf man
A bit-field shall have integral or enumeration type (3.9.1).
[...]
If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (7.2), the original enumerator value and the value of the bit-field shall compare equal.cooky451 schrieb:
Auch ein bitset hat natürlich eine Mindestgröße von 1.
Falls du ein Bitfield meinst: Nein, das kann auch 0 Bits belegen. Es trennt dann bspw. zwei Bitfields zu zwei memory locations.
Edit: Sprechen wir über zwei verschiedene Sachen?
-
knivil schrieb:
Nun, bei 4 Enums reichen 2 Bit. Andere Systeme konnen auf Bitebene lesen/schreiben. Deswegen frage ich. Und bei Groessenangaben macht eine Zahl ohne Einheit keinen Sinn. Ist es standardisiert, dass Bitsets bzw. alle Dinge mindestens 1 Byte/Char/whatever gross sind?
Soweit ich weiss ja.
Bei Arrays bzw. einzelnen Objekten ist es sowieso klar.sizeof()ist in Bytes (chars), also kann nichts kleiner sein als ein Byte (char).Bei mehreren Membervariablen wäre es vielleicht denkbar dass man die irgendwie in ein einziges Byte zusammenpacken könnte, aber ich schätze dass auch da der Standard nen Riegel vorschiebt.
Wenn man sowas wirklich machen will kann man ja immer noch Bitfields verwenden.Ausserdem würde es vermutlich ein Problem mit dem Speichermodell von C++ geben, was Threads angeht.
Zwei enum Variablen sind zwei unterschiedliche Objekte, und dürfen daher auch von verschiedenen Threads gleichzeitig verwendet werden.
Wenn die zwei Variablen jetzt im selben Byte liegen bedeutet das, dass die Zugriffe auf dieses Byte entweder irgendwie über CAS o.ä. gemacht werden müssen (langsam), oder die CPU ein Cache-Coherency-Protokoll mit Sub-Byte Genauigkeit haben muss (hat soweit ich weiss keine CPU).
-
Arcoth schrieb:
knivil schrieb:
Koennen enums nicht auch als Bitset realisiert sein?
Meinst du Bitfield?
Und ja, das darf man
A bit-field shall have integral or enumeration type (3.9.1).
[...]
If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (7.2), the original enumerator value and the value of the bit-field shall compare equal.Das heisst dass du nen Enum-Typ als Basistyp für ein Bitfield angeben darfst:
enum foo { ... }; struct bar { foo f : 3; };So wie ich knivil verstehe ist das aber überhaupt nicht was er meint.
-
Zum Hintergrund meiner Frage: Bitbanding bei ARM, wobei dort ein adressierbare Einheit auf ein Bit(s) gemappt wird. Auch erlaubt es mehrere Adressen fruer eine Speicherstelle (meist wird es fuer IO benutzt). D.h. ein bitset koennte prinzipiell echt kleiner sein als 1 Byte. Andererseits ist es erlaubt (bitte korrigiert mich, wenn ich falsch liege), ein enum als integralen Typ oder als bitset zu realisieren.
-
Wobei handle ein integer und info jeweils ein enum mit zuständen darstellt, insgesammt also (4 + 4 + 4
12 byte. Man könnte hier die größe um die hälfte reduzieren, etwa indem man statt dem int und den enum werten ein short type nimmt. Klar, das handle wäre dann halb so groß und könnte nur noch rund 66k werte aufnehmen, ist aber aktuell nicht von belang, immerhin hätten wir die größe der Klasse um die hälfte reduziert.Könnte man tun.
Riesige Enums habe ich noch nicht gesehen. Aber Handles sind solche Elemente, welche man gerade in der Praxis nicht genug haben kann.
Je mehr VertexBuffer du instanziierst, desto effizienter wird das Ganze, aber desto größer ist die Wahrscheinlichkeit das du auch mehr als 2^16 Elemente addresieren willst.
-
@knivil
Dabei ist dann wieder das Problem, dass in ein C++ char min. 8 Bit braucht um den verlangten Wertebereich abdecken zu können. Und C++sizeof(char) == 1strikt vorschreibt.
D.h. die CPU könnte es adressieren, aber C++ kann es nicht adressieren.Und das 2. Problem wird vermutlich die Threading-Sache sein. Ich bin mir nämlich ziemlich sicher dass es auf ARM nicht definiert ist was passiert wenn zwei Cores gleichzeitig schreibend auf (unterschiedliche) Bits im selben Byte zugreifen.
Und laut C++ Standard muss das möglich sein, und sich immer so verhalten wie man es erwartet -- nämlich dass der Zugriff auf Variable 1 den Wert von Variable 2 nicht ändern darf, auch wenn ein anderer Thread gleichzeitig auf Variable 2 zugreift.
Und zwar egal was diese Variablen für nen Type haben, und wo sie liegen. Ausgenommen sind da nur Bitfields, aber Bitfields sind halt auch Bitfields und keine eigenen "Objekte".Kurz: ich sehe keine Möglichkeit in C++ enums automatisch auf weniger als 1 Byte (==
char) abzubilden.Manuell, also indem man selbst explizit Bitfields verwendet, geht es natürlich. Dabei entfallen dann beide genannten Hindernisse, da Bitfields selbst nicht adressierbar sind und für Bitfields auch andere Regeln für Multithreading gelten.
-
Bitte ein Bit schrieb:
Je mehr VertexBuffer du instanziierst, desto effizienter wird das Ganze, aber desto größer ist die Wahrscheinlichkeit das du auch mehr als 2^16 Elemente addresieren willst.
Garantiert OpenGL denn überhaupt dass "Names" (Handles) immer mit 1 beginnend, ansteigend vergeben werden und auch freigewordene "Löcher" wiederverwendet werden, bevor weiter raufgezählt wird?
Sonst wäre das nämlich ziemlich gepokert.Und da ich keinen effektiven Nutzen so einer Garantie wüsste, gehe ich eher davon aus, dass es nicht garantiert ist.
-
hustbaer schrieb:
Und da ich keinen effektiven Nutzen so einer Garantie wüsste, gehe ich eher davon aus, dass es nicht garantiert ist.
Die handles können ja auch prozessübergreifend vergeben werden. Und der Treiber könnte ja auch intern alle Handles gleich verwalten und dann so Dinge machen wie: handle 0-1000 sind Texturen 1000-2000 sind... usw. Es gibt da also gar keine Garantien.