Speicheroptimierung: was ist sinnvoll, was nicht?


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



  • 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) == 1 strikt 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.



  • @otze
    Danke.

    Eben weil es nen potentiell grossen Nutzen gibt es nicht zu garantieren, aber keinen es doch zu garantieren, hab ich angenommen dass es nicht garantiert wird.

    Dann ist die Überlegung sowieso hinfällig.

    Geht also maximal wenn es eigene "Handles" sind, wo man selbst garantiert dass sie nie grösser als X werden. Oder Lust hat sich auf undokumentiertes Verhalten zu verlassen.



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

    Könntest du mir das ein wenig ausführlicher erklären?

    Meinst du dass prinzipiell ein Handle die Wertebereiche von -2^32 bis 2^32 durchlaufen kann? 😕



  • hustbaer schrieb:

    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.

    OpenGL garantiert nur, dass names unsigned int sind und die 0 ist reserviert. Das ist alles. In der Praxis sind es allerdings in der Tat oft aufsteigende Integer beginnend bei 1; mit Löchern ist zu rechnen...


Anmelden zum Antworten