Inline-Optimierung durch Klassenunbekanntheit bei Deklaration unterbunden?



  • LTO sollte man während der Entwicklung von großen Programmen aber vermeiden, siehe auch http://www.c-plusplus.net/forum/viewtopic-var-p-is-1952161.html



  • krümelkacker schrieb:

    Wie es bei Microsoft aussieht, weiß ich nicht.

    MSVC++ 2008 Professional unterstützt Linkzeit-Codegenerierung.



  • Hallo,

    Danke erstmal.
    Okay, LTO klingt doch schon Mal cool.

    SeppJ:
    Ja, das ist ein absoluter Standardfall, aber ich kenn mich leider nicht so mit den Optimierungsmöglichkeiten des Compilers aus. Steht das bei VC irgendwo in der Doc oder wo finde ich solche Infos? 🙂

    Ich habe zur Zeit halt die Wahl, entweder B nur vorwärts-zu-deklarieren oder komplett einzubinden. Angenommen, die gängigen Compiler sind nicht dazu in der Lage LTO zu nutzen, dann würde ich den B-Header in A halt lieber inkludieren.

    Danke. Wenn es dazu sonst nichts Interessantes mehr gibt, geht es wohl in dem LTO-Thread weiter, lol 🙂



  • Eisflamme schrieb:

    Hallo,

    Danke erstmal.
    Okay, LTO klingt doch schon Mal cool.

    SeppJ:
    Ja, das ist ein absoluter Standardfall, aber ich kenn mich leider nicht so mit den Optimierungsmöglichkeiten des Compilers aus. Steht das bei VC irgendwo in der Doc oder wo finde ich solche Infos? 🙂

    Ich habe zur Zeit halt die Wahl, entweder B nur vorwärts-zu-deklarieren oder komplett einzubinden. Angenommen, die gängigen Compiler sind nicht dazu in der Lage LTO zu nutzen, dann würde ich den B-Header in A halt lieber inkludieren.

    Danke. Wenn es dazu sonst nichts Interessantes mehr gibt, geht es wohl in dem LTO-Thread weiter, lol 🙂

    Includes in Headern schrauben nur die Compilezeit nach oben, wenn das Projekt mal groß wird und jedesmal bei kleinen Änderungen alles gebaut wird, weil du zuviele unnötige Includes hast. Und ob dieses inline was bringt hast du sicher noch nicht mal gemessen. Du produzierst nur schlechten Code.



  • Ja, tu das nicht. Extreme Kompilierzeiten bei jeder Anwendung sind absolut benutzerunfreundlich.

    Ich habe beispielsweise vor Kurzem die Ogre-Grafikbibliothek angeschaut, und bereits für das Hello-World-Beispiel musste ich fast eine Minute kompilieren. Ein einziges Modell mit 0815-Einstellungen gezeichnet... Das kanns ja echt nicht sein! Und ich habe nachgeschaut, die Entwickler haben sinnlos viele Header eingebunden, wo eine Vorwärtsdeklaration gereicht hätte. Von Pimpl und so keine Spur... 🙄

    Umso grösser war meine Freude, als ich zu Irrlicht umstieg und da für die ganze Bibliothek 3 Sekunden kompilieren musste! Da wurde echt was überlegt. 🙂



  • Für myGame?



  • Nexus schrieb:

    ...die Entwickler haben sinnlos viele Header eingebunden, wo eine Vorwärtsdeklaration gereicht hätte. Von Pimpl und so keine Spur... 🙄

    Kann der Compiler Pimpl wegoptimieren und alles inlinen? Sonst geht das mal garnicht!!!!!1efl



  • Eine Vorwärtsdeklaration ist nur dann ausreichend, wenn es unerheblich ist, ob der Compiler Informationen über den Typ hat oder nicht. Und wenn der Compiler diese Informationen benötigt, ist LTO aus dem Rennen. LTO ist dazu da Optimierungen vorzunehmen, die der Compiler nicht vornehmen kann. Zum Beispiel:

    In classA.h wird eine Klasse mit der als inline deklarierten Funktion funcFromA() deklariert.
    In classA.cpp steht die Definition der Klasse aus classA.h, inklusive besagter funcFromA()
    In classB.h wird classA.h inkludiert. Bei jeder Verwendung von funcFromA() in dieser Datei wird das inline geflissentlich ignoriert. Warum? Weil der Compiler an dieser Stelle die Definition nicht kennt.
    LTO soll nun diese Definitionen über die Objektdateigrenzen hinaus transportieren, um doch noch ein Inlining zu ermöglichen.

    Zweites Beispiel:
    Die Klasse A enthält als Member einen Zeiger auf eine Instanz von Klasse B. Muss die Headerdatei mit der Deklaration von Klasse B inkludiert werden? Nein. Eine Vorwärtsdeklaration reicht. Handelt es sich aber nicht um einen Zeiger, sondern eine Instanz, reicht eine Vorwärtsdeklaration nicht.

    Zum zweiten Beispiel sei zu sagen, dass es als "schick" gilt, Zeiger auf komplexe Datenstrukturen zu verwenden, die dann nur eine Vorwärtsdeklaration benötigen, und so, vermeintlich, die Kompilierungszeit verringern. Das ist dann Teil des pImpl -Idioms (Pointer to Implementation) und ist ganz supi l33t. Und erzeugt eine Flut von zusätzlicher Tipparbeit, die eine Flut von zusätzlichen potentiellen Fehlern mit sich führt. Ein geschickter Modularer Aufbau der Quelldateien ist meist effizienter um Kompilierungszyklen zu verkürzen. Aber wie bei Allem ist das immer in Relation zum Projekt zu sehen. Eine allgemeingültige Aussage wird es da wohl niemals geben.



  • Yamakuzure schrieb:

    In classA.h wird eine Klasse mit der als inline deklarierten Funktion funcFromA() deklariert.
    In classA.cpp steht die Definition der Klasse aus classA.h, inklusive besagter funcFromA()
    In classB.h wird classA.h inkludiert. Bei jeder Verwendung von funcFromA() in dieser Datei wird das inline geflissentlich ignoriert. Warum? Weil der Compiler an dieser Stelle die Definition nicht kennt.

    Warum soll er die Definition nicht kennen, wenn "classB.h" den Header "classA.h" mit der Inline-Funktion inkludiert?



  • Na ja, er kennt die Funktionsdeklaration aber die Funktionsdefinition ist ja in der .cpp-Datei, oder?



  • Eisflamme schrieb:

    Na ja, er kennt die Funktionsdeklaration aber die Funktionsdefinition ist ja in der .cpp-Datei, oder?

    Nein, Yamakuzure sprach von einer Inline-Funktion.



  • Ja, aber er hat trotzdem diese im Header deklariert und in der Quellcodedatei definiert, falls so was geht:

    In classA.h wird eine Klasse mit der als inline deklarierten Funktion funcFromA() deklariert. 
    In classA.cpp steht die Definition der Klasse aus classA.h, inklusive besagter funcFromA()
    

    Ich benutze inline eh nie, daher hab ich keine Ahnung.



  • Der Witz von inline ist ja gerade, dass du Funktionen im Header definieren kannst. inline -Deklarationen sind zwar erlaubt, aber dann muss die Funktionsdefinition in der selben Übersetzungseinheit wie der Aufruf vorhanden sein. Das läuft also darauf hinaus, die Definition im Header anzugeben, wenn man Linkerfehler vermeiden möchte.

    Yamakuzure hat sich auch sonst etwas unklar ausgedrückt. Wenn im Header nur die Klassendeklaration steht, kann er dort auch keine Methode deklarieren. Falls er hingegen wirklich die ganze Klasse erst in der .cpp-Datei definiert, kann er deren Methoden nicht in anderen Headern – hier "classB.h" – benutzen.



  • Yamakuzure schrieb:

    [...] Zum Beispiel:

    In classA.h wird eine Klasse mit der als inline deklarierten Funktion funcFromA() deklariert.
    In classA.cpp steht die Definition der Klasse aus classA.h, inklusive besagter funcFromA()
    In classB.h wird classA.h inkludiert. Bei jeder Verwendung von funcFromA() in dieser Datei wird das inline geflissentlich ignoriert.

    Stopp mal. Das ist gar nicht erlaubt. Du darfst in einer Übersetzungeinheit keine Inline-Funktion benutzen, die nur deklariert wurde. Also
    ÜE1:

    inline int foo(int);
    
    int bar(int x)
    {
      return foo(x*2);
    }
    

    ÜE2:

    inline int foo(int x) {return x;}
    
    int bar(int);
    
    int main()
    {
      return bar(0);
    }
    

    ist kein gültiges Programm. Der Compiler wird sich vielleicht nicht beschweren, aber der Linker wird wahrscheinlich meckern; denn in ÜE1 wird die inline-Funktion benutzt aber nur deklariert. In ÜE2 wird sie definiert, aber nie benutzt. Weil die Funktion in ÜE2 nicht benutzt wird und die ODR fordert, dass jede Benutzung eine Definition in derselben ÜE erfordert, darf ein Compiler beim Übersetzen von ÜE2 die Definition der inline-Funktion aussparen. ==> Der Linker wird dann wegen eines unaufgelösten Symbols meckern.

    Siehe 3.2/3 [one definition rule]:

    ... An inline function shall be defined in every translation unit in which it is used.

    Das Schlüsselwort "inline" wird scheinbar öfters missverstanden. Es ist primär dazu da, einem Compiler, das tatsächliche "Inlining" leichter zu machen, indem in jeder ÜE, in der die Inline-Funktion benutzt wird, auch die entsprechende Definition vorhanden ist (so will es die ODR).

    Nexus schrieb:

    Der Witz von inline ist ja gerade, dass du Funktionen im Header definieren kannst.

    ...sogar definieren musst. Denn ohne Definition in der aktuellen ÜE darf die Funktion nicht benutzt werden.

    Edit: Sorry Nexus. Hatte ich komplett übersehen, dass Du auch darauf aufmerksam gemacht hattest.

    Gruß,
    kk



  • krümelkacker schrieb:

    Nexus schrieb:

    Der Witz von inline ist ja gerade, dass du Funktionen im Header definieren kannst.

    ...sogar definieren musst. Denn ohne Definition in der aktuellen ÜE darf die Funktion nicht benutzt werden.

    Man muss nicht, aber es macht keinen Spaß, in jeder cpp, in der man die Funktion braucht, die Definition zu wiederholen 😉



  • Michael E. schrieb:

    krümelkacker schrieb:

    Nexus schrieb:

    Der Witz von inline ist ja gerade, dass du Funktionen im Header definieren kannst.

    ...sogar definieren musst. Denn ohne Definition in der aktuellen ÜE darf die Funktion nicht benutzt werden.

    Man muss nicht, aber es macht keinen Spaß, in jeder cpp, in der man die Funktion braucht, die Definition zu wiederholen 😉

    ...oder einen zweiten Header einzufügen, der dann schließlich die Definition enthält. Das ist natürlich beides eher sinnfrei. Ich hätte für alle anderen Korintenkacker die Aussage noch eingrenzen müssen. 🙂


Anmelden zum Antworten