Forum: Compiler & IDEs Inline Funktion in Interrupt Routine


von Sören (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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").

: Bearbeitet durch Moderator
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...

von Ingo (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ingo schrieb:
> Ich glaube der TO will die Funktion mal inlinen und mal nicht!

Ja, sorry, das habe ich zu spät gelesen.

von Dr. Sommer (Gast)


Lesenswert?

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.

von sebi707 (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Sören (Gast)


Lesenswert?

Vielen Dank für die Hinweise, ich werde das mit den Attributen und der 
Wrapper Funktion mal ausprobieren.

Sören

von Markus F. (mfro)


Lesenswert?

m.E. die beste Lösung ist, die ISR mit
1
__attribute__((flatten))
 auszustaffieren.
Das sorgt dafür, daß der Compiler versucht, sich alles zu greifen, was 
er in diese Funktion inlinen kann.
1
__attribute__((always_inline))
 macht nicht unbedingt das, was man sich bei dem Namen so denkt. mit
1
-Os
 beispielsweise bekommt man (meist) lediglich die zusätzliche Warnung, 
daß sich inlinen nicht lohne.

Gruß,
Markus

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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" )

von Oliver S. (oliverso)


Lesenswert?

Markus F. schrieb:
> Probier' mal -Winline (Warnung, falls inline-Funktionen
> nicht inlined wurden) in Kombination mit -Os.

Bite sehr:
1
#include <avr/io.h>
2
3
//inline int foo (int i, volatile int j) __attribute__((always_inline));
4
int foo (volatile int i, volatile int j)
5
{
6
  volatile int res = i;
7
  res = res + i+i*j;
8
  res = res * i * j;
9
  res = res / (i / j);
10
  return res;
11
}
12
13
14
int main(void)
15
{
16
  volatile int k;
17
  volatile int l,m;
18
19
  l = 7;
20
  m = 8;
21
22
  k = foo(foo(foo(l,m), foo(l,m)), foo(foo(l,m), foo(l,m)));
23
}

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

von Rolf Magnus (Gast)


Lesenswert?

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:
1
void func() __attribute__((always_inline));
2
3
int main()
4
{
5
    func();
6
}
1
gcc -c always_inline.c -o always_inline.o -Os -Winline
2
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.

von Rolf Magnus (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Markus F. (mfro)


Lesenswert?

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.

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

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?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...

von Rolf Magnus (Gast)


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Du dürftest sogar recht haben:

http://gcc.gnu.org/onlinedocs/gcc/Inline.html

GCC does not inline any functions when not optimizing unless you specify 
the ‘always_inline’ attribute for the function [...]

und hier http://gcc.gnu.org/ml/gcc-help/2007-01/msg00051.html liest man:

If you use the always_inline attribute, then, yes, you do not need to
also use the inline keyword.

von Oliver S. (oliverso)


Lesenswert?

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

von ben (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
class A
2
{
3
  public:
4
    int get();
5
    void set( int m );
6
7
  private:
8
   int member_;
9
};
10
11
int A::get()
12
{
13
  return member_;
14
}
15
16
void A::set( int m )
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.
1
class A
2
{
3
  public:
4
    int get();
5
    void set( int m );
6
7
  private:
8
   int member_;
9
};
10
11
inline int A::get()
12
{
13
  return member_;
14
}
15
16
inline void A::set( int m )
17
{
18
  member_ = m;
19
}

: Bearbeitet durch User
von Der Anzeiger (Gast)


Lesenswert?

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."

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.