C ++: Bekämpfung von Polymorphismus Overhead

8

Ich weiß, dass Polymorphie einen merklichen Overhead hinzufügen kann. Der Aufruf einer virtuellen Funktion ist langsamer als der Aufruf einer nicht virtuellen. (Meine ganze Erfahrung ist über GCC, aber ich denke / hörte, dass dies für jeden Realcompiler gilt.)

Oftmals wird eine gegebene virtuelle Funktion immer wieder am selben Objekt aufgerufen. Ich weiß, dass sich der Objekttyp nicht ändert, und die meisten Male konnte der Compiler das gut abziehen:

%Vor%

Um den Code zu beschleunigen, könnte ich den obigen Code wie folgt umschreiben:

%Vor%

Ich frage mich, was ist der beste Weg, um diesen Overhead aufgrund von Polymorphie in diesen Fällen zu vermeiden.

Die Idee des oberen Casting (wie im zweiten Snippet gezeigt) sieht für mich nicht so gut aus: BaseType könnte von vielen Klassen geerbt werden, und der Versuch, alle zu übertreffen, wäre ziemlich weit verbreitet .

Eine andere Idee könnte darin bestehen, obj.f in einem Funktionszeiger zu speichern (nicht getestet, nicht sicher, ob es den Laufzeit-Overhead killen würde), aber auch diese Methode sieht nicht perfekt aus: wie oben beschrieben, es würde mehr Code schreiben müssen und es wäre nicht möglich, einige Optimierungen auszunutzen (zB: wenn FinalType::f eine Inline-Funktion wäre, würde es nicht inline werden - aber ich denke, der einzige Weg, dies zu vermeiden, wäre zu topcast obj auf seinen endgültigen Typ ...)

Also, gibt es eine bessere Methode?

Bearbeiten: Nun, das wird natürlich nicht so viel bewirken. Diese Frage war hauptsächlich zu wissen, ob es etwas zu tun gab, da es aussieht, als ob dieser Overhead kostenlos gegeben würde (dieser Overhead scheint sehr leicht zu töten zu sein) Ich sehe nicht warum, warum nicht.

Ein einfaches Schlüsselwort für kleine Optimierungen, wie C99 restrict , dem Compiler zu sagen, dass ein polymorphes Objekt von einem festen Typ ist, habe ich mir erhofft.

Wie auch immer, nur um auf Kommentare zu antworten, ist ein kleiner Overhead vorhanden. Sehen Sie sich diesen Ad-hoc-Code extrem an:

%Vor%

Kompilieren und ausführen, Zeit nehmen:

%Vor%

Ich denke, nur -O2, -O3 und -Os sind Final::f inline.

Und diese Tests wurden auf meinem Rechner mit dem neuesten GCC und einem AMD Athlon (tm) 64 X2 Dual Core Prozessor 4000+ CPU ausgeführt. Ich denke, es könnte auf einer günstigeren Plattform viel langsamer sein.

    
peoro 06.11.2010, 02:24
quelle

2 Antworten

8

Wenn der dynamische Versand in Ihrem Programm ein Leistungsengpass ist, besteht die Lösung des Problems nicht darin, den dynamischen Versand zu verwenden (verwenden Sie keine virtuellen Funktionen).

Sie können einen Laufzeitpolymorphismus durch Kompilierzeit-Polymorphismus ersetzen, indem Sie Vorlagen und generische Programmierung anstelle von virtuellen Funktionen verwenden. Dies kann zu einer besseren Leistung führen oder auch nicht; nur ein Profiler kann Ihnen das sicher sagen.

Um es ganz klar zu machen, wie Wilheltell bereits in Kommentaren auf die Frage hingewiesen hat, ist es selten, dass der Overhead, der durch dynamischen Versand verursacht wird, signifikant genug ist, um sich Sorgen zu machen. Seien Sie absolut sicher, dass es sich um Ihren Leistungs-Hotspot handelt, bevor Sie den integrierten Komfort durch eine unhandliche benutzerdefinierte Implementierung ersetzen.

    
James McNellis 06.11.2010, 02:37
quelle
2

Wenn Sie Polymorphie verwenden müssen, verwenden Sie sie. Es gibt wirklich keinen schnelleren Weg, es zu tun.

Allerdings würde ich mit einer anderen Frage antworten: Ist das dein größtes Problem? Wenn ja, ist Ihr Code bereits optimal oder fast so. Wenn nicht, finden Sie heraus, was das größte Problem ist, und konzentrieren Sie sich stattdessen darauf.

    
Mike Dunlavey 06.11.2010 14:28
quelle