Forum: Compiler & IDEs GCC 4.1.1. schlechte Optimierung


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Anbei ein Beispiel (ist ne Funktion aus meinem Jumbo-LED Beispiel), wo
der GCC 4.1.1. schlecht optimiert.


Zuerst wird eine 16Bit-Variable komplett gelesen, obwohl nur das
High-Byte gebraucht wird (die Version 3.4.6. konnte das aber schon
optimieren).

Dann wird eine Funktion ge-inlined, obwohl sie nicht static ist und mit
-Os auf size optimiert werden soll.

Dann wird ein großes Codestück dupliziert (im test411.lst hinter der
RET-Zeile) nur um ein "ldi r28, 0x00" einzusparen.


Hier mal die Statistik:

4.1.1
   text    data     bss     dec     hex filename
    296      10       8     314     13a test.out

3.4.6
   text    data     bss     dec     hex filename
    236      10       8     254      fe test.out

Sind also beeindruckende 25% mehr mit dem 4.1.1.


Peter

von Peter D. (peda)


Lesenswert?

Noch was vergessen, die Kommandozeile:


avr-gcc.exe -xc -Os -mmcu=attiny26 -Wall -g disptime.c


Peter

von Benedikt (Gast)


Lesenswert?

Wobei man aber dazu sagen sollte, dass der neue GCC meistens besser
optimiert als der alte.
Zumindest von der Geschwindigkeit her ist der vom 4.1.1 erzeugte Code
fast immer etwas besser.
Anscheinend inlined der 4.1.1 alle Funktionen die eine bestimmte Größe
unterschreiten. Hier ist die Funktion halt so klein, dass eine Funktion
eigentlich keinen Sinn macht.

von Peter D. (peda)


Lesenswert?

@Benedikt,

was soll denn inlinen für einen Sinn machen, wenn die Funktion nicht
static ist ?

Er muß sie ja trotzdem stehen lassen, da sie von woanders aufgerufen
werden könnte. Wenigstens tut er das auch.

Das Inlinen an der Größe festzumachen ist der falsche Ansatz, auch die
Anzahl der Aufrufe ist entscheidend.

Der Geschwindigkeitsvorteil hier ist unbedeutend, da ja noch
haufenweise Divisionen drumrum sind. Da verschwindet die Zeit für ein
gespartes Call+RET einfach im Nirwana.

Ich hätte natürlich überhaupt nichts dagegen, wenn der Compiler ein
Division+Modulo optimiert.


Auch sollte bitteschön der -Os Schalter nicht ignoriert werden, d.h.
Größe vor Geschwindigkeit. Also Inlinen nur, wenn ich auch den Schalter
dafür setze.

Ich hab auch die anderen Level ausprobiert -O0...-O3, immer war der
3.4.6.-Code kürzer.


Peter

von Karl H. (kbuchegg)


Lesenswert?

> was soll denn inlinen für einen Sinn machen, wenn die Funktion
> nicht static ist ?

C fordert nicht das eine Funktion die geinlined wird static sein
muss.
Ganz im Gegenteil: Auf Nicht-µC ist es eher die Regel, dass sie
es nicht sind. Die übliche Vorgehensweise ist es, diese Funktionen
in Header Files auszulagern und natürlich die Funktion als inline
zu markieren. static macht man die dann aber nicht, da man ansonsten
in jeder Compilation Unit eine neue Kopie der Funktion erzeugt.

> Er muß sie ja trotzdem stehen lassen, da sie von woanders aufgerufen
> werden könnte. Wenigstens tut er das auch.

Yep. Und ein guter Linker schmeist sie dann wieder raus, wenn kein
einziger Aufruf übrig bleibt.

> Das Inlinen an der Größe festzumachen ist der falsche Ansatz, auch
> die Anzahl der Aufrufe ist entscheidend.

Die kann aber der Compiler nicht alle überblicken, da er sich ja
immer nur auf eine Compilation-Unit konzentriert.
Also inlined der was das Zeug hält. Sobald die Funktion klein genug
ist wird sie aufgelöst.

> Der Geschwindigkeitsvorteil hier ist unbedeutend, da ja noch
> haufenweise Divisionen drumrum sind. Da verschwindet die Zeit
> für ein gespartes Call+RET einfach im Nirwana.

Bei allem nötigen Respekt: Aber das kümmert den Compiler einen
feuchten Kehrricht.

> Auch sollte bitteschön der -Os Schalter nicht ignoriert werden,
> d.h. Größe vor Geschwindigkeit. Also Inlinen nur, wenn ich auch den
> Schalter dafür setze.

100% ACK
Das ist mir auch schon mal aufgefallen. Das kann ich mir
eigentlich nur so erklären:
Durch das inlinen eröffnen sich oft neue Optimierungsmöglichkeiten
über die Funktionsgrenzen hinweg. Möglicherweise hat jemand
statistisch herausgefunden, dass sich das im Mittel lohnt und
die zusätzlichen Optimierungen den zunächst größeren Code im
Mittel kleiner kriegen.

Glücklich bin ich auch nicht damit. Ich hätte auch erwartet, dass
bei -Os keine inlines stattfinden.

von A.K. (Gast)


Lesenswert?

Was das inlinen mit -Os angeht: Das dürfte mit C++ zusammenhängen. Da
sind inlines sehr verbreitet, oft nicht mehr als Zugriffsfunktionen auf
class members. Konsequenter Verzicht auf inlining macht den Code dann
nicht kleiner sondern deutlich grösser.

Im Compiler immer genau die richtige Grenze zu finden, ist allerdings
eine Wissenschaft für sich. Komplexität der Funktion allein ist ein
schwaches Mass, da wie du schon andeutest, Synergien auftreten, die
erst erkannt werden, wenn man die Codegenerierung schon halb durch hat.
Man es aber lieber vorher wüsste ob oder ob nicht.

von A.K. (Gast)


Lesenswert?

Apropos: -fno-inlines oder so. Das funktioniert m.W. immer. Nützlich
insbesondere beim Durchsteppen, weil man sonst allzu leicht die
Übersicht verliert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Die kann aber der Compiler nicht alle überblicken, da er sich ja
> immer nur auf eine Compilation-Unit konzentriert.

Bei GCC 4 nicht mehr notwendigerweise, man kann ihm auch mehrere
compilation units gemeinsam vorwerfen.

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.