Speicheroptimierung: was ist sinnvoll, was nicht?



  • Arcoth schrieb:

    Bei char ist es nichtmal erlaubt.

    Das ist auch bei einer Variable mit zwei Bytes oder drei nicht erlaubt, da das Alignment nie größer als der Typ selbst sein darf.

    Bitte richtig formulieren, so ist das nämlich falsch.


  • Mod

    schluderer schrieb:

    Bitte richtig formulieren, so ist das nämlich falsch.

    Was ist denn da schluderig formuliert?



  • Arcoth schrieb:

    schluderer schrieb:

    Bitte richtig formulieren, so ist das nämlich falsch.

    Was ist denn da schluderig formuliert?

    Gut, ich präzisiere: Es ist falsch.


  • Mod

    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.



  • Arcoth schrieb:

    Bei char ist es nichtmal erlaubt.

    Das ist auch bei einer Variable mit zwei Bytes oder drei nicht erlaubt, da das Alignment nie größer als der Typ selbst sein darf.

    Tip: schluderer meint vermutlich Alignment-Requirement (ich hoffe das ist jetzt der richtige Fachbegriff) <-> Alignment. Das Alignment darf natürlich immer grösser sein. (Und ein Typ hat auch kein Alignment, ein Objekt bzw. eine Adresse hat Alignment).

    Was ich meinte: C++ garantiert dir für char dass es keine Bits gibt die man mit char nicht "sehen" kann. Für UDTs gilt das nicht. Ob es für die numerischen Typen gilt weiss ich nicht.

    Also nochmal anders formuliert: ne struct kann 8 Byte gross sein, wovon aber nur die ersten 6 verwendet werden. sizeof(T) ist dann natürlich 8, sogesehen hast du schon Recht. Trotzdem existieren hier zwei Padding-Bytes.

    Das einzige was erlaubt ist, ist dass man char von Haus aus grösser macht.

    Was meinst du damit? char ist immer ein Byte groß.

    Stell dich nicht so an. Ich hab' oben extra "8-bittig" geschrieben. Der Zusatz gilt natürlich hier auch.

    Dass der C++ Standard das Wort "byte" für "das was so gross ist wie ein char, auch wenn ein char viel mehr als 8 Bit hat" verwendet weiss ich auch. Und dass daher ein char immer ein "C++ byte" gross ist. Ob diese Verwendung des Wortes "byte" sinnvoll ist ist aber ne andere Frage.
    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.


  • Mod

    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).


  • Mod

    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 weniger alignof(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*


  • Mod

    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 feine Option -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?


  • Mod

    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.


Anmelden zum Antworten