Inline Funktion in Interrupt Routine

Gast #3616127
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
Gast #3616151
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
Gast #3616212
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.
Gast #3616219
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.
#3617588
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
#3617614
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
#3617727
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.
(Firma: Brainit GmbH) #3617748
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.
(Firma: Brainit GmbH) #3617772
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" )
#3617834
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
Gast #3617884
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.
Gast #3617890
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.
#3617987
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
#3618027
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.
Gast #3618048
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?
(Firma: Brainit GmbH) #3618060
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...
Gast #3618079
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.
(Firma: Brainit GmbH) #3618108
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.
#3618147
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
Gast #3618165
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.
#3618226
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
}
Gast #3618521
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."

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