Forum: Compiler & IDEs Virtual Function Elimination ARM GCC


von Leopold N. (leo_n)


Lesenswert?

Hallo zusammen,

ich versuche, die Code Size meines Binaries möglichst klein zu halten 
und würde deshalb gerne auch virtuelle Funktionen (C++), die nicht 
benutzt werden, aus dem Binary schmeißen. Für normale Funktionen gibt es 
ja Dead Code Elimination des Linkers, aber die greift aufgrund der 
VTables bei virtuellen Funktionen nicht. Stattdessen gibt es anscheinend 
VFE 
(https://developer.arm.com/documentation/dui0474/m/linker-command-line-options/--vfemode-mode), 
was laut Link wohl auch standardmäßig schon aktiviert ist. Jedoch finden 
alle virtuellen Funktionen obwohl ganz klar nicht genutzt, ihren Weg ins 
fertig Binary und verdoppeln dort die Codesize. Compiler: ARM GCC 9.3.1, 
STM32CubeIDE V1.8.0
kompiliert wird mit: -Os -ffunction-sections -fdata-sections 
-Wl,--gc-sections -nostartfiles -nodefaultlibs -nostdlib

Ich habe auch bereits folgende Optionen ohne Erfolg probiert:
-fwhole-program
-flto
-fdevirtualize-at-ltrans

Hat jemand eine Idee, was ich tun muss, um die virtuellen Funktionen 
rauszubekommen (außer, keine zu benutzen...)

Grüße

von Oliver S. (oliverso)


Lesenswert?

Hast du mal -O3 mit -flto probiert? Wenn damit Compiler und Linker das 
auch nicht machen, dann gehts vermutlich nicht besser.

Oliver

von c-hater (Gast)


Lesenswert?

Leopold N. schrieb:

> Hat jemand eine Idee, was ich tun muss, um die virtuellen Funktionen
> rauszubekommen (außer, keine zu benutzen...)

Keine zu benutzen, ist natürlich Quatsch.

Die bestmögliche Lösung ist, nur die Funktionen virtuell zu machen, die 
man auch zu nutzen gedenkt und zwar tatsächlich als virtuelle 
Funktionen. Denn logischerweise bringt es nix, eine virtuelle Funktion 
zu deklarieren, die entweder garnicht genutzt wird oder auch nur 
nirgendwo überschrieben wird.

von Devirtualization (Gast)


Lesenswert?

Zeig mal Beispielcode, prinzipiell kann GCC Optimizer Devirtualization 
(das brauchst du hier efefktiv), aber manchmal weigert er sich. 
Vielleicht ist Amalgation notwendig, obwohl -fwhole-program das gleiche 
bringen sollte.

von Leopold N. (leo_n)


Angehängte Dateien:

Lesenswert?

Hier als Beispiel mal der LTDC.
Der LTDC wird nur in der Klasse STM32H753BIT6 verwendet, und zwar ist er 
ein Member. Es werden nur die Funktionen LTDC::startup und LTDC::LTDC 
aufgerufen, die restlichen Funktionen landen aber trotzdem aufgrund der 
VTables im Binary.

von Leopold N. (leo_n)


Angehängte Dateien:

Lesenswert?

Oliver S. schrieb:
> Hast du mal -O3 mit -flto probiert? Wenn damit Compiler und Linker das
> auch nicht machen, dann gehts vermutlich nicht besser.
>
> Oliver

Probiert, aber ohne Erfolg

von Oliver S. (oliverso)


Lesenswert?

Leopold N. schrieb:
> Oliver S. schrieb:
>> Hast du mal -O3 mit -flto probiert? Wenn damit Compiler und Linker das
>> auch nicht machen, dann gehts vermutlich nicht besser.
>>
>> Oliver
>
> Probiert, aber ohne Erfolg

Dann wirst du wohl damit leben müssen, wie es ist, oder du wirfst die 
nicht benötigten Funktionen halt aus dem Sourcecode raus.

Oliver

von Leopold N. (leo_n)


Angehängte Dateien:

Lesenswert?

Hier mal ein STM32CubeIDE Project, mit dem ich das ganze mal ausprobiert 
hab.
Wenn ich bei DerivedClass die Vererbung wegnehme (: public BaseClass 
auskommentieren und override löschen) verschwindet die Funktion 
DerivedClass::foo aus dem Binary, da sie ja auch nicht aufgerufen wird.
Die Funktion DerivedClass::bar bleibt natürlich.
Sobald DerivedClass aber von BaseClass erbt, wird DerivedClass::foo 
immer mit in die Binaries geschleppt, obwohl main() sie nicht aufruft.

Jemand eine Idee?

von Oliver S. (oliverso)


Lesenswert?

Leopold N. schrieb:
> Jemand eine Idee?

Haste mal gegoogelt? Wenn dir das keine neuen Ansätze liefert (was es 
nicht tun wird, obwohl die Frage durchaus häufig gestellt wird), gehts 
halt nicht.

Einzige Lösung, die sich dort abzeichnet: Geh zurück auf gcc 3.x. Da 
gabs eine Compileroption für das Problem. Der Erfolg ist nicht 
garantiert, da gcc die ab Version 4 wegen "Nicht-Wartbarkeit" 
(Euphemismus für "funzt nicht wirklich") aufgegeben hat.

Oliver

von Leopold N. (leo_n)


Lesenswert?

Habe gerade gefühlt zwei Tage mit googlen verbracht...
auf GCC 3.x zurückzugehen ist keine Option. Ich kann bloß nicht glauben, 
dass es 2021 (fast 22) keine Möglichkeit geben soll, Dead Code zu 
eliminieren, nur weil ein paar VTables sich darauf referenzieren, welche 
selbst aber nicht gebraucht werden. Und ich versteh nicht, warum VFE als 
Compileroption zwar im Handbuch steht, aber nix tut, bzw. vom Compiler 
sogar explizit nicht erkannt wird.

von Devirtualization (Gast)


Lesenswert?

Leopold N. schrieb:
> Hier als Beispiel mal der LTDC.

Wir brauchen ein MWE, damit können wir nichts anfangen, weil zu komplex 
und kompiliert nicht.


Leopold N. schrieb:
> Hier mal ein STM32CubeIDE Project, mit dem ich das ganze mal ausprobiert
> hab.
> [...]
> Jemand eine Idee?

Ja, -flto (GCC9) optimiert das sauber wie erhofft:
Es verbleibt nur DerivedClass::foo(). Konstruktor, Destruktor und vtable 
werden komplett eliminiert.

von Devirtualization (Gast)


Lesenswert?

Ups, ich hatte die Namen vertauscht.
Die vtable wird eliminiert, aber DerivedClass::foo() ist weiterhin 
vorhanden, obwohl ungenutzt.

von Leopold N. (leo_n)


Lesenswert?

Ja, -flto hatte ich auch schon probiert...habe allerdings Sorgen bei 
dieser Option, da sie wohl Bugs haben soll (oder mal gehabt hatte in 
früheren Versionen von GCC).

von Oliver S. (oliverso)


Lesenswert?

Leopold N. schrieb:
> Ja, -flto hatte ich auch schon probiert...habe allerdings Sorgen
> bei
> dieser Option, da sie wohl Bugs haben soll (oder mal gehabt hatte in
> früheren Versionen von GCC).

Der Schwippschwager des Onkel meines Bruders Hundesitter kennt jemanden, 
der hat mal gehört, daß…

Debuggen wird damit natürlich nicht einfacher, aber sonstige Sorgen 
braucht man da schon lange nicht mehr zu haben.

Oliver

von Devirtualization (Gast)


Lesenswert?

Leopold N. schrieb:
> Ja, -flto hatte ich auch schon probiert...habe allerdings Sorgen bei
> dieser Option, da sie wohl Bugs haben soll (oder mal gehabt hatte in
> früheren Versionen von GCC).

Wenn ich den Inhalt von derivedClass.cpp in main.cpp kopiere, klappt es. 
Dann gibt es derivedClass gar nicht mehr im Binary.
Vollte Optimierung bekommt man leider erst mit Amalgation. Soll der TE 
das mal probieren.

LTO bringt grundsätzlich nicht mehr Bugs als GCC sowieso hat, bis auf 
die bekannte Geschichte mit weak linking von interrupts.

von Oliver S. (oliverso)


Lesenswert?

Devirtualization schrieb:
> Amalgation

Devirtualization schrieb:
> Amalgation

Was du für Wörter kennst…
Ähnlichkeiten mit Amalgamation sind vermutlich beabsichtigt.

Oliver

von Leopold N. (leo_n)


Lesenswert?

Devirtualization schrieb:
> Wenn ich den Inhalt von derivedClass.cpp in main.cpp kopiere, klappt es.
> Dann gibt es derivedClass gar nicht mehr im Binary.
> Vollte Optimierung bekommt man leider erst mit Amalgation. Soll der TE
> das mal probieren.

Das Problem ist leider, dass ich die virtuellen Klassen und deren 
Ableitungen in verschiedenen Bibliotheken habe und main() davon erst mal 
nichts sieht... Drum geht das mit dem amalgamamatieren leider nicht :)

von Oliver S. (oliverso)


Lesenswert?

Ich hasb mal probiert: In meinem Testprogramm fliegt die unbenutze 
virtuelle Funktion func1 auch mit Almagamation nicht raus. Es hätte mich 
auch gewundert, wenns da zwischen lto und und "alles in einer Datei" 
wesentliche Unterschiede gegeben hätte.

https://godbolt.org/z/v6WvbaooY

Oliver

von Leopold N. (leo_n)


Lesenswert?

Also Fazit: Keiner hier hat ne Ahnung wie man diesen Overhead 
wegbekommt...
Schade, hatte gehofft, dass ich zu blöd zum googlen bin :/

Falls noch jemand ne Idee hat, immer gern, ansonsten könnte man den 
Thread schließen.

von Oliver S. (oliverso)


Lesenswert?

Leopold N. schrieb:
> Schade, hatte gehofft, dass ich zu blöd zum googlen bin :/

Biste halt.

Sonst hättest du den passenden Kommentar zu der Frage auf gcc.org 
gefunden.

Ich zitier mal für dich:
>> So what can I do?
> Nothing (well, improve GCC!).

In diesem Sinne…

Oliver

: Bearbeitet durch User
von Leopold N. (leo_n)


Lesenswert?

Oliver S. schrieb:
> Biste halt.
>
> Sonst hättest du den passenden Kommentar zu der Frage auf gcc.org
> gefunden.

:) Den Thread hatte ich auch schon durch, mehrmals sogar in der Hoffnung 
was übersehen zu haben xD

Schönen Abend noch ;)

von Gcc (Gast)


Lesenswert?

> Das Problem ist leider, dass ich die virtuellen Klassen
> und deren Ableitungen in verschiedenen Bibliotheken habe

Falls das der Wahrheit entspricht und es sich um Objektcode-Bibliotheken 
handelt, wirst du doch nicht ernsthaft erwarten daß der Compiler da was 
optimieren kann. Der bekommt den Maschinencode ja nichtmal in die 
Finger.

von HörNichtAufMich (Gast)


Lesenswert?

Du kannst in Godbolt nicht erkennen, ob der Compiler/Linker Funktionen 
raushaut, oder nicht. Überlege doch mal:
Das Standard-Template ist int square(int num) { return num*num;} was von 
exakt niemanden aufgerufen wird! Und trotzdem ist es im Disassembly - 
egal bei welcher Optimierung usw. Merkste selbst? ;-)

Der Thread stürzt sich hier auf das falsche tool: der Compiler ist 
überhaupt nicht dafür zuständig, Sachen aus dem Programm zu schmeißen! 
Das macht der Linker.

von mh (Gast)


Lesenswert?

HörNichtAufMich schrieb:
> Der Thread stürzt sich hier auf das falsche tool: der Compiler ist
> überhaupt nicht dafür zuständig, Sachen aus dem Programm zu schmeißen!
> Das macht der Linker.

Dann muss der arm-clang den Linker integriert haben?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.