Hallo zusammen,
in meinem Programm benutze ich eine Funktion an verschiedener Stelle,
auch in der Interrupt-Routine.
Diese Funktion ist im header utils.h deklariert, die Interrupt-Routine
befindet sich in main.c.
Da die Funktion an verschiedenen Stellen im Programm aus
unterschiedlichen Dateien benutzt wird, soll sie an diesen Stellen
aufgerufen werden (Optimierung Code Size). In der Interrupt-Routine soll
aber dieser Aufruf vermieden werden, um sie möglichst kurz zu halten
(Optimierung Execution Time).
Wie kann ich das nun realisieren, dass diese Funktion in der
Interrupt-Routine inline ist, sonst aber aufgerufen wird?
Vielen Dank!
Sören
gcc-Option
-lto
beim Compilieren und Linken angeben.
Wichtig: Beim Linken auch noch die Optimierung einschalten, z.B. -Os.
Dann hast Du zumindest eine Chance, dass die Funktion "geinlined" wird -
sogar bei Aufruf von verschiedenen Funktionen aus verschiedenen Modulen
("Übersetzungseinheiten").
Frank M. schrieb:> Dann hast Du zumindest eine Chance, dass die Funktion "geinlined" wird -> sogar bei Aufruf von verschiedenen Funktionen aus verschiedenen Modulen> ("Übersetzungseinheiten").
Er will sie ja nicht generell inline haben, nur in der ISR...
Frank M. schrieb:> gcc-Option>> -lto>> beim Compilieren und Linken angeben.>> Wichtig: Beim Linken auch noch die Optimierung einschalten, z.B. -Os.>> Dann hast Du zumindest eine Chance, dass die Funktion "geinlined" wird -> sogar bei Aufruf von verschiedenen Funktionen aus verschiedenen Modulen> ("Übersetzungeseinheiten").
Ich glaube der TO will die Funktion mal inlinen und mal nicht!
Ingo
Definier die Funktion mit __attribute__((always_inline)), sodass sie
immer geinlined wird. Dann definiere eine Wrapper-Funktion, die einfach
nur diese Funktion aufruft, aber mit __attribute__((noinline)) definiert
ist - also nicht geinlined wird. Je nachdem welche der beiden Funktionen
du aufrufst wird also geinlined oder nicht.
Wenn es dir wirklich wichtig ist, dass die Funktion nur in der ISR
inline ist und sonst auf keinen Fall musst du wohl mit den noinline und
always_inline Attributen arbeiten. Über Defines könntest du pro Datei
festlegen ob die Funktion inlined wird oder nicht. Eventuell musst du
dann die ISR in eine extra C-Datei auslagern. Eigentlich sollte man sich
da aber nicht so viele Gedanken machen. Der Compiler sollte eigentlich
ganz gut selbst entscheiden können ob sich inlinen lohnt oder nicht.
sebi707 schrieb:> Der Compiler sollte eigentlich> ganz gut selbst entscheiden können ob sich inlinen lohnt oder nicht.
Kann er und macht er. Da ihm (vermutlich) per Option gesagt wurde, auf
Codegröße zu optimieren, wird er genau das tun. Da lohnt dann für ihn
inlining selten bis nie.
Da braucht es schon explizite Nachhilfe,wie o.a.
Oliver
Markus F. schrieb:> __attribute__((always_inline)) macht nicht unbedingt das, was man> sich bei dem Namen so denkt. mit -Os beispielsweise bekommt> man (meist) lediglich die zusätzliche Warnung, daß sich inlinen nicht> lohne.
Na ja, das wäre allerdings blöd.
always_inline bedeutet schon always_inline, und gcc wird dann auch
inlinen, wenn die Funktion ans ich auch mit inline dekoriert ist.
Oliver
Oliver S. schrieb:> always_inline bedeutet schon always_inline, und gcc wird dann auch> inlinen, wenn die Funktion ans ich auch mit inline dekoriert ist.>> Oliver
Probier' mal
1
-Winline
(Warnung, falls inline-Funktionen nicht inlined wurden) in Kombination
mit
1
-Os
. Mein Compiler jedenfalls erklärt mir dann für viele Funktionen, daß er
eben nicht inlinen würde, weil er sich ausgerechnet hätte, daß sich
das nicht lohnen und die Codegröße zunehmen würde.
Das läßt sich mit 'flatten' zuverlässig übersteuern.
Hmmm... so wie ich das verstehe, machen always_inline und flatten schon
zwei verschiedene Sachen:
Eine Funktion mit attribute((always_inline)) wird selbst zu einer
inline-Funktion.
Eine Funktion mit attribute((flatten)) wird nciht selbst zu einer
inline-Funktion, aber der Compiler versucht alles was aus dieser
Funktion heraus aufgerufen wird zu inlinen.
Michael Reinelt schrieb:> Eine Funktion mit attribute((flatten)) wird nicht selbst zu einer> inline-Funktion, aber der Compiler versucht alles was aus dieser> Funktion heraus aufgerufen wird zu inlinen.
... richtig. Und deshalb für eine ISR (die so schnell wie möglich
abgearbeitet werden soll) m.E. genau das richtige.
Markus F. schrieb:> Michael Reinelt schrieb:>> Eine Funktion mit attribute((flatten)) wird nicht selbst zu einer>> inline-Funktion, aber der Compiler versucht alles was aus dieser>> Funktion heraus aufgerufen wird zu inlinen.>> ... richtig. Und deshalb für eine ISR (die so schnell wie möglich> abgearbeitet werden soll) m.E. genau das richtige.
Korrekt.
ist auch aus einem zweiten Grund sehr sehr sinnvoll: generell sichert
der GCC beim Eintritt in eine ISR nur die Register welche in der ISR
verändert werden (und restauriert diese beim Verlassen). Sobald man aber
eine Funktion aufruft, werden sehr viele Register gesichert, der Prolog
und Epilog werden damit (unnötig) lang. Hintergrund ist das ABI (Details
gibts in diesem Thread: Beitrag "AVR: Prolog/Epilog in Funktion statt ISR" )
Mit einem nicht mehr ganz aktuellen avr-gcc 4.3.3 mit -Os und -Winline
compiliert, ergibt das 512 Byte Code, wenn die Zeile mit always_inline
auskommentiert ist, und über 1500, wenn nicht auskommentiert. Keine
Warnung, und eindeutig geinlined.
So sollte das m.E. auch sein, das Attribut sagt dem Compiler ja
schließlich, daß er er seine eigene Meinung vergessen soll.
Oliver
Markus F. schrieb:> Probier' mal-Winline (Warnung, falls inline-Funktionen nicht inlined> wurden) in Kombination mit-Os. Mein Compiler jedenfalls erklärt mir dann> für viele Funktionen, daß er eben nicht inlinen würde, weil er sich> ausgerechnet hätte, daß sich das nicht lohnen und die Codegröße zunehmen> würde.
Bei mir verhält er sich etwas anders:
always_inline.c:1:6: warning: always_inline function might not be inlinable [-Wattributes]
3
void func() __attribute__((always_inline));
4
^
5
always_inline.c: In function ‘main’:
6
always_inline.c:1:6: error: inlining failed in call to always_inline ‘func’: function body not available
7
always_inline.c:5:9: error: called from here
8
func();
9
^
Er bringt also die von dir angegebene Warnung, bricht aber zusätzlich
auch mit Fehler ab. Wenn ich dagegen weder -Os, noch -Winline angebe,
passiert folgendes:
1
gcc -c always_inline.c -o always_inline.o
2
always_inline.c:1:6: warning: always_inline function might not be inlinable [-Wattributes]
3
void func() __attribute__((always_inline));
4
^
Hier kommt dann tatsächlich nur die Warnung. Bei always_inline erwarte
ich eigentlich, daß der Compiler zuverlässig mit Fehler abbricht, wenn
ein Inlining nicht durchgeführt werden kann. Offenbar ignoriert er aber
das erzwungene Inlining, wenn Optimierungen ausgeschaltet sind.
Mist. Gerade nach dem Posten fällt mir auf, daß du's wohl anderes
gemeint hast. Du beschreibst ja den Fall, daß inlining möglich ist und
der Compiler sich aber dagegen entscheidet und nicht den Fall, daß es
nicht geht und der Compiler dann einfach ohne inlining weitermacht.
Rolf Magnus schrieb:> Bei mir verhält er sich etwas anders:>> [C]> void func() __attribute__((always_inline));> gcc -c always_inline.c -o always_inline.o -Os -Winline> always_inline.c:1:6: warning: always_inline function might not be> inlinable [-Wattributes]
Je nun, deine Funktion ist ja auch nicht inline. Da hat der gcc recht.
Durch das Attribut "__attribute__((always_inline))" wird die Funktion
nicht als inline definiert, dafür braucht es ein "inline" vorne dran.
Oliver
Oliver S. schrieb:>> So sollte das m.E. auch sein, das Attribut sagt dem Compiler ja> schließlich, daß er er seine eigene Meinung vergessen soll.>> Oliver
Funktioniert in den meisten Fällen, aber eben nicht immer (habe leider
gerade kein Beispiel parat, an dem ich das beweisen könnte, ist aber
auch nicht so wichtig).
Was anderes (zu deinem Code): die inline-Funktion sollte zusätzlich
"static" deklariert werden.
Sonst ist sie "extern" und der Compiler bindet beide Versionen ein: eine
inlined-Version da, wo man sie haben will und zusätzlich eine
"eigenständige" Funktion, die (zumindest, wenn wir bei unserem Beispiel
des Interrupt-Handlers bleiben) wahrscheinlich nicht gewollt ist.
Schließlich kann der Compiler ja (noch) nicht wissen, ob die Funktion
noch von woanders gerufen wird.
Oliver S. schrieb:> Durch das Attribut "__attribute__((always_inline))" wird die Funktion> nicht als inline definiert, dafür braucht es ein "inline" vorne dran.
Ok, mit zusätzlichem inline verschwindet die Warnung auch noch, und der
Compiler übersetzt es, wenn keine Optimierung an ist, einfach komplett
kommentarlos, und das sogar, wenn ich -Winline angebe. Das würde ich mal
als Bug im Compiler bezeichnen.
Und warum bei always_inline nicht automatisch das inline mit drin ist,
verstehe ich auch nicht. Wozu soll das denn gut sein?
Rolf Magnus schrieb:> Ok, mit zusätzlichem inline verschwindet die Warnung auch noch, und der> Compiler übersetzt es, wenn keine Optimierung an ist, einfach komplett> kommentarlos, und das sogar, wenn ich -Winline angebe. Das würde ich mal> als Bug im Compiler bezeichnen.
Naja, kann man auch so sehen: Wenn ohne Optimierung, ist das der
"Debug-Modus", und da kann es schon sinnvoll sein, nicht zu inlinen, um
dem Debugger (und vor allem demjenigen der vor dem Debugger sitzt) das
leben nicht unnötig schwer zu machen...
Michael Reinelt schrieb:> Naja, kann man auch so sehen: Wenn ohne Optimierung, ist das der> "Debug-Modus", und da kann es schon sinnvoll sein, nicht zu inlinen, um> dem Debugger (und vor allem demjenigen der vor dem Debugger sitzt) das> leben nicht unnötig schwer zu machen...
Wenn ich das brauche, dann definiere ich mir selber ein Makro, das im
Debug-Modus nichts macht und sonst zu __atrribute__((always_inline))
expandiert.
Für mich ist das Attribut always_inline dazu da, sicherzustellen, daß
ein Inlining auch wirklich immer stattfindet, und wenn das aus
irgendeinem Grund nicht geht, mit Fehlermeldung abgebrochen wird. Wenn
ich mich trotz diesem Attribut nicht darauf verlassen kann, ist es
eigentlich relativ wertlos. Daß der Compiler dann in der Situation nicht
mal eine Warnung - auch nicht wenn man sie explizt anfordert - ausgibt,
finde ich dann schon sehr merkwürdig.
Michael Reinelt schrieb:> GCC does not inline any functions when not optimizing unless you specify> the ‘always_inline’ attribute for the function [...]
Mit Optimierung sieht gcc ein inline ohne "always_inline" allerdings
auch nur als unverbindliche Empfehlung an. Der inlined alles, was er für
richtig hält, egal, ob inline drannsteht oder nicht, und umgekehrt
genauso.
Oliver
Die Erfahrung musste ich auch schonmal machen und bin zu dem Ergebnis
gekommen:
das inline - Attribut ist komplett wertlos.
Ohne Optimierung wird nie geinlined.
Mit Optimierung inlined der Compiler nach gutdünken, egal ob mit oder
ohne Attribut.
Naja, die pragmatische Lösung wäre doch einfach, ZWEI Funktionen zu
benutzen, eine in der iSR und ein für den Rest. Ist nicht optimal aber
immer noch besser als ewig mit Compilerschaltern rumzujonglieren.
Oliver S. schrieb:> Mit Optimierung sieht gcc ein inline ohne "always_inline" allerdings> auch nur als unverbindliche Empfehlung an.
So war das ja auch ursprünglich gedacht.
Das Problem war nämlich ein ganz anderes und kommt so zustande.
Auf der einen Seite möchte man in Header Files Funktionen definieren
können, um dem Compiler Möglichkeiten zur Optimierung zu geben. Ganz
speziell in C++ möchte man das unbedingt (und von da stammt ja auch das
inline keyword ursprünglich her), damit man Getter und Setter schreiben
kann.
d.h. es ist wünschenswert in C++, in einem Header File schreiben zu
können
1
classA
2
{
3
public:
4
intget();
5
voidset(intm);
6
7
private:
8
intmember_;
9
};
10
11
intA::get()
12
{
13
returnmember_;
14
}
15
16
voidA::set(intm)
17
{
18
member_=m;
19
}
aber da läuft man jetzt in ein multiple Defintion Dilemma, wenn dieses
Header File in mehreren Source Code Files eingebunden werden soll.
Da jetzt dem Keyword 'static' noch eine weitere Bedeutung aufs Auge zu
drücken, das dürfte sogar dem Stroustrup zu viel gewesen sein. Das Chaos
war auch so schon groß genug.
Genau an dieser Stelle kommt das inline keyword ins Spiel. Es ist die
Empfehlung an den Compiler eine Funktion zu inlinen, was er auch
ignorieren kann. Was er aber nicht ignorieren darf: er muss für den
Linker Information hinterlassen, bzw. die Sache so hindrehen, dass es ok
ist, mehrere Member Funktionen mit demselben Namen in unterschiedlichen
Object Files zu haben, ohne das dadurch die One Definition Rule verletzt
ist.
So ist das korrekt, egal ob der Compiler die Funktionen dann auch
tatsächlich inlined oder nicht. Zumindest der ODR ist damit auf jeden
Fall Genüge getan.
Das steht letztendlich auch in ISO C drin. Ich hab jetzt nur C99 da, und
das sagt:
"Making a function an inline function suggests that calls to the
function be as fast as possible. The extent to which such suggestions
are effective is implementation-defined."
und
"An inline definition does not provide an external definition for the
function, and does not forbid an external definition in another
translation unit."