Ich habe folgende Aufgabe, bei der Ihr mir vielleicht helfen könnt, sie zu lösen: Ich habe ein umfangreiches embedded-C++ Projekt, welches mit dem GCC für einen ATmega128 gebaut wird. Nahezu alle CPP-Files sollen mit der Optimierungsstufe "s" gebaut werden, um das Paket in die 128kByte zu bekommen. Nun gibt es aber einige Klassen (also einige CPP-Files) die in Optimierungsstufe "2" oder "3" gebaut werden müssen, weil sie sehr performant sein müssen. Nun ist es kein Problem diese Files im makefile in eine eigene Liste zu bringen. Allerdings ist mir noch nicht klar, wie ich make beibringen kann, beim Build (also beim compilieren von .cpp in .o) diese Liste mit anderen Compiler-Flags zu bauen. Kann mir hier jemand weiter helfen? Danke!
gcc ab Version 4.4 kennt pragmas, mit denen sich der Optimierungslevel im Source code definieren lässt. http://gcc.gnu.org/onlinedocs/gcc/Function-Specific-Option-Pragmas.html#Function-Specific-Option-Pragmas Allerdings würde mich mal interessieren, wie groß nachweislich der Geschwindigkeitsunterschied zwischen -Os und -O2 bzw. -O3 wirklich ist. Denn einer der Eigenschaften der Riskprozessoren ist, daß kürzer in den allermeisten Fällen auch schneller ist. Das weiß der gcc aber nicht immer. Oliver
>Denn einer der Eigenschaften der Riskprozessoren ist, daß kürzer in den >allermeisten Fällen auch schneller ist. Nö. Weniger Programmcode heisst noch lange nicht das das Programm schneller ist.
Wie gesagt, erst ein Profiling kann zeigen, ob O2 oder O3 sinnvoll sind. Neben den Futschle-an-100-Schalter-gleichzeitig-rum-Optionen wie Os, O2, O3 gibt's ja noch zig Schräubchen zum Feinjustieren. Wie auch immer; im Makefile geht auch
1 | foo.o bar.o: CFLAGS += -O2 |
Das -O bzw -f[no-]eine-option, die am weitesten rechts steht, überschreibt die weiter links — zumindest für die meisten Optionen. Es stört also nicht, wenn CFLAGS im Ende aussieht wie
1 | ... -mcall-prologues -Os -mno-call-prologues -O2 ... |
Den Code mit optimize pragmas/attribute verunstalten ist Geschmackssache.
Wenn das Object-File x.o mit zusätzlichen Flags für C++ kompiliert werden soll, dann schreibst du in dein Makefile sowas rein: x.o : CXXFLAGS += -O3 CXXFLAGS wirkt nur auf C++-Kompilierung.
>Nun gibt es aber einige Klassen (also einige CPP-Files) die in >Optimierungsstufe "2" oder "3" gebaut werden müssen, weil sie sehr >performant sein müssen. Wenn man an den Optimierungsstufen rumfummeln muss um sie performant zu machen, dann ist da schon der Hund begraben. 99% eines Codes muss gar nicht performant sein. Such dein 1% wo der meiste Umsatz gemacht wird und optimiere da. Zur Not auch mit Assembler. Wenn es um Hardwaremodule geht kann man sich oft deren Eigenschaften zu Nutze machen. Ohne Quellcode Beispiele für die besonders performanten Stellen kann man da aber auch nicht helfen.
Oliver schrieb: > Denn einer der Eigenschaften der Riskprozessoren ist, daß kürzer in den > allermeisten Fällen auch schneller ist. Auf Highend-Prozessoren lässt sich diese Regel nicht anwenden. Im Gegenteil, etliche lohnende Laufzeitoptimierungen sind recht platzraubend. Bei Lowend-RISCs wie AVRs ist aggressiv laufzeitoptimierter Code zwar oft nicht viel schneller, aber wenn beispielsweise Laufzeitfunktionen für Mul/Div ins Spiel kommen, dann kann der Compiler sie für kürzer halten als simple Shifts. Für die Laufzeit ist das indes eine Katastrophe.
A. K. schrieb: > ...wenn beispielsweise Laufzeitfunktionen für Mul/Div ins Spiel kommen, > dann kann der Compiler sie für kürzer halten als simple Shifts. > Für die Laufzeit ist das indes eine Katastrophe. So wir's zB in avr-gcc gemacht: Wenn auf Größe optimiert wird, werden zB mitunter Shift-Loops genommen wo für Speed der Shift offen codiert wird; ähnlich für Multiplikation vs. Libcall oder Division durch Konstante vs. Multiplikation. An einigen Stellen hab ich die Kosten billiger gemacht als sie wirklich sind, um nicht einen ewig-langsamen Libcall zu erzeugen wo eine Version, die eine Instruktion länger ist, mit einem Arithmetik-Taschenspielertrick aufwarten kann und wesentlich schneller ist. Problem dabei ist, daß Os/O2 eigentlich kompromisslos sind und daß es keine Möglichkeit gibt, zwischen diesen Polen abzuwägen — weder für den Anwender noch innerhalb von GCC. Weiteres Problem bei AVR ist, daß es extrem kleine Hardware gibt mit nur ein paar k Programmspeicher wo jedes Byte zählt. Bei der 64-Bit Arithmetik hab ich versuch abzuwägen, d.h. je nachdem für welches Derivat man übersetzt, bekommt man unterschiedliche schnelle/große Implemenmtierung der Division. Dies ist jedoch unabhängig vom Optimierungsgrad.
Johann L. schrieb: > Weiteres Problem bei AVR ist, daß es extrem kleine Hardware gibt mit nur > ein paar k Programmspeicher wo jedes Byte zählt. Und gerade bei den Mini-Progrämmchen ist die Wahrscheinlichkeit gegeben, daß ein libcall anstelle von ausformuliertem Code zwar beim Aufruf kürzer ist, dafür aber die lib-Funktionen reinzieht, die sonst nicht erforderlich gewesen wäre. Oliver
Oliver schrieb: > Johann L. schrieb: >> Weiteres Problem bei AVR ist, daß es extrem kleine Hardware gibt mit nur >> ein paar k Programmspeicher wo jedes Byte zählt. > > Und gerade bei den Mini-Progrämmchen ist die Wahrscheinlichkeit gegeben, > daß ein libcall anstelle von ausformuliertem Code zwar beim Aufruf > kürzer ist, dafür aber die lib-Funktionen reinzieht, die sonst nicht > erforderlich gewesen wäre. Ja, das ist ein Problem im GCC und vielleicht auch in anderen Compilern, wenn globales Wissen nicht vorhanden ist oder nicht verwendet wird. C-Paradigma war und ist ja modulweise zu übersetzen und alles erst zur Linkzeit zusammenzuführen. Momentan werden die Kosten auf Instruktionsebene bestimmt unter der Annahme, daß sich die Vorteile aufsummieren nach dem Motto "alles wird gut". Eine andere, globale Kostenberechnung setzt zum einen voraus, daß die Kosten überhaupt erst bestimmbar sind (was im Rahmen von LTO prinzipiell der Fall ist) und daß diese Kosten im Rahmen eines exakteren Kostenmodells Anwendung finden. In GCC ist letzteres ist auf Instruktionsebene nicht der Fall, d.h. Grundvoraussetzung wäre ein neues Kostenmodell.
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.