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
Noch was vergessen, die Kommandozeile: avr-gcc.exe -xc -Os -mmcu=attiny26 -Wall -g disptime.c Peter
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.
@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
> 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.
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.
Apropos: -fno-inlines oder so. Das funktioniert m.W. immer. Nützlich insbesondere beim Durchsteppen, weil man sonst allzu leicht die Übersicht verliert.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.