make - Build mit unterschiedlichen Compiler-Flags

#2562005
Lesenswert?

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!
Gast #2562069
Lesenswert?

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
Gast #2562171
Lesenswert?

>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.
Persönliche Seite #2562192
Lesenswert?

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.
Gast #2562243
Lesenswert?

>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.
#2562264
Lesenswert?

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.
Persönliche Seite #2562352
Lesenswert?

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.
Gast #2562651
Lesenswert?

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
Persönliche Seite #2562681
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren