thread local: Zu erwartende performance?



  • Hintergrunt:
    Momentan entwickel ich einen OpenGL Wrapper. Ein GL Kontext ist immer an genau einen Thread gekoppelt und hat in meinem Wrapper ein eigenes State Objekt.
    Man muss immer zwei pointer benutzen um eine Methode der Wrapper Objekte aufzurufen. Einmal das Objekt und zweitens das GL Kontext Objekt.

    Methoden kann man also folgendermaßen designen:

    Buffer::macheX(GlContext &gc, ...)
    

    oder

    GlContext::bufferMacheX(Buffer &buffer, ...)
    

    Nun ist es sehr verlockend thread_local für das GL Kontext Objekt zu verwenden.

    Jedoch bin ich mir nicht sicher was ich von der performance erwaten darf, da es wohl sehr unterschiedliche Implementierungen gibt.
    Wenn ich es benutze würde ich es auch für sehr oft aufgerufene Methoden verwenden. (Tausende mal pro Frame)

    Also grob sind es zwei Fragen:
    -Gibt es einen Schnitt bei OS/Compiler wo die Implementierung einen deutlichen Verbesserung erfährt. Z.B. in XP/msvs08 sehr schlecht ab Win7/msvc10/gcc gut.

    -Wie groß sind die Kosten auf einer guten implementierung?



  • ~~Mh für mich hört sich das nach einer schlecht gestellten Frage an. Denn wenn du zwischen mehreren Threads keine Kommunikation hast und auch alle Threads etwa gleich ausgelastet sind, dann sehe ich keinen Grund warum eins schneller als das andere sein sollte.

    Ich muss allerdings auch dazu sagen, dass ich quasi keine Ahnung von OpenGL(-Contexten) habe.~~

    Edit: komplett falscher Context



  • Beim GCC kostet das quasi nichts, sofern alles in der gleichen ÜE passiert.

    Besser als globaler State ist aber immer, ihn zu vermeiden. Warum nicht

    struct BufferContextPair {
      GlContext *gc;
      Buffer *buffer;
    };
    

    oder so ähnlich?



  • Osbios schrieb:

    Ein GL Kontext ist immer an genau einen Thread gekoppelt und hat in meinem Wrapper ein eigenes State Objekt.

    Warum? Der Kontext beschreibt doch den Zustand des Objekts, auf dem du pinselst, nicht den Zustand eines Threads.



  • Skym0sh0 schrieb:

    Ich muss allerdings auch dazu sagen, dass ich quasi keine Ahnung von OpenGL(-Contexten) habe.

    Oder von thread_local! 😉

    goforit schrieb:

    Beim GCC kostet das quasi nichts, sofern alles in der gleichen ÜE passiert.

    Besser als globaler State ist aber immer, ihn zu vermeiden. Warum nicht

    struct BufferContextPair {
      GlContext *gc;
      Buffer *buffer;
    };
    

    oder so ähnlich?

    Was ist mit ÜE gemeint?
    Soweit ich verstehe benutzt gcc ein register als Offset zum TLS und/oder pthread mapt einen Speicherbereich per thread. Also entsprechend schnell.
    Wie macht das msvc/windows?

    Warum sollte ich thread-globale Variablen vermeiden wenn sie genau dass sind was ich haben möchte?

    manni66 schrieb:

    Warum? Der Kontext beschreibt doch den Zustand des Objekts, auf dem du pinselst, nicht den Zustand eines Threads.

    Nein. GL hat sehr viele globale States. Unter anderem z.B. das Objekt was gerade aktiv ist welches man verändern möchte. Erst ab GL 4.5 hat man für fast alles Direct State Access Funktionen. Ich benutze jedoch als minimum GL 3.3.

    Und daher muss ich für den GL context des jeweiligen Threads die States speichern.



  • Was ist mit ÜE gemeint?

    Geraten: Übersetzungs-Einheit



  • Habe mit VirtualBox auf XP getestet und konnte keinen Performance Unterschied zu Win7 feststellen.

    Was man bei thread_local bzw. __thread oder __declspec(thread) beachten muss, ist das es für jeden Thread Speicher verbraucht. Ich habe auf Win7/Ubuntu vielfachen Speicherverbrauch gehabt als ob es min. 2-3 unsichtbare Threads gab.
    In Windows Programmen hatte ich manchmal sehr lange Ladezeiten und extremen Speicherverbrauch wenn thread_local mehrere MB groß war.

    Daher benutze ich in meinem Fall nun Pointer.

    Die Klasse mit all den States wird dann im scope eines Threads (welcher einen GL Context hat) erstellt und setzt den Pointer auf sich selber.
    Nun kann ich mein Interface etwas hübscher gestallten:

    thread_local ContextState threadContextState;
    Buffer::macheX(...)
    {
      threadContextState->benutzeIrgendwasWovonDerUserNixMitbekommenMuss();
    }
    void thread1()
    {
      ContextState meinContextState; //Constructor setzt threadContextState auf sich selber
      Buffer b;
      b.macheX();
    }
    

Anmelden zum Antworten