Forum: Compiler & IDEs ISR effizient verteilen


von S. R. (svenska)


Lesenswert?

Hi,

ich spiele derzeit mit einem USB-fähigen AVR (Atmega32U4) herum und 
möchte daraus ein Composite Device (cdc-acm und msc) bauen. Die 
Verwaltung des Gesamtdevices (Endpoint 0, Descriptoren) muss zentral 
geschehen, alles weitere soll aber jeder Treiber (nach Möglichkeit) für 
sich behandeln.

Alle Endpoints teilen sich einen Interruptvektor, also hatte ich da eine 
Tabelle im Kopf, wo die Endpoint-spezifischen Handler vermerkt sind und 
verzweige dann nach Bedarf. Ich arbeite mit C (avr-gcc).

Kann ich diese spezifischen Handler in die ISR inlinen, auch über 
Dateigrenzen hinweg? Was muss ich dem gcc dafür mitteilen?

Oder muss ich den Preis eines indirekten Funktionsaufrufs in der ISR 
bezahlen, wenn ich getrennte Treiber möchte?

Eine fertige Bibliothek möchte ich (vorerst) nicht nutzen. Im Augenblick 
orientiere ich mich an einem kleinen Teensy-Beispiel für cdc und den 
originalen Datenblättern, Lufa ist mir ein bisschen zu wirr.

Gruß,
svenska

von Oliver S. (oliverso)


Lesenswert?

Du kannst keine ISR mehrfach definieren. Der eigentliche Funktionsaufruf 
aus der ISR heraus ist ja noch nicht mal das Problem, der kostet selbst 
mit Parameterübergabe nur ein paar Zyklen. Unschöner ist, daß der gcc 
zum ISR-Begin alle Register retten, und am Ende wieder herstellen muß, 
sobald er da einen Funtionsaufruf findet, bei dem er die Sourcecode 
nicht kennt.

Da die ISR aber auch nur eine C-Funktion ist, kannst du da Funktionen so 
inlinen, wie sich in C Funktionen halt so inlinen lassen.
Also entweder alle Funktionen in einem Sourcefile, oder zumindest per 
include darin eingebunden. Die dann noch static und inline, dann machts 
der gcc vielleicht sogar.

Oliver

von S. R. (svenska)


Lesenswert?

Oliver S. schrieb:
> Da die ISR aber auch nur eine C-Funktion ist, kannst du da Funktionen so
> inlinen, wie sich in C Funktionen halt so inlinen lassen.

Die Frage ist, ob das über Dateigrenzen hinweg machbar ist. Wenn nicht, 
muss ich die Kröte halt schlucken; wirklich schlimm wäre das nicht.

von Nico W. (nico_w)


Lesenswert?

S. R. schrieb:
> Die Frage ist, ob das über Dateigrenzen hinweg machbar ist.

Stichwort: "LTO".

von MaWin (Gast)


Lesenswert?

S. R. schrieb:
> Die Frage ist, ob das über Dateigrenzen hinweg machbar ist.

Ja. Mit Link Time Optimization (LTO) geht das ganz automatisch. Wenn es 
nur einen Aufrufer einer Funktion gibt, wird diese automatisch 
ge-inlined. Ganz ohne inline und/oder static keywords.

von Markus F. (mfro)


Lesenswert?

wenn man eine C-Funktion möglichst immer und ausschließlich auch über 
Übersetzungseinheiten hinweg ge-inlined haben möchte, schreibt man sie 
nicht in eine .c-Datei, sondern in die entsprechende Header-Datei und 
definiert sie
1
static inline f(...) { ... };

Allerdings muß der Compiler sie selbst dann nicht unbedingt inlinen, 
wenn er nicht will (weil man z.B. nicht optimiert compiliert). Bei gcc 
kann man in dem Fall noch extra nachhelfen:
1
__attribute__((always_inline))

Dann geht das auch ohne -flto

von S. R. (svenska)


Lesenswert?

MaWin schrieb:
> Ja. Mit Link Time Optimization (LTO) geht das ganz automatisch.

Auch, wenn man das indirekt über einen Funktionspointer in einer (lokal 
const static deklarierten) Tabelle macht?

Also von:
1
    switch(whatever) {
2
    case 0: tab[0](); break;
3
    case 1: tab[1](); break;
4
    default: break;
5
    }

zu:
1
    if(whatever == 0) {
2
        /* die funktion, auf die tab[0] zeigt */
3
    } elsif(whatever == 1) {
4
        /* die funktion, auf die tab[1] zeigt */
5
    }

automatisch? Denn das kann ich mir nicht vorstellen.

von Carl D. (jcw2)


Lesenswert?

S. R. schrieb:
> MaWin schrieb:
>> Ja. Mit Link Time Optimization (LTO) geht das ganz automatisch.
.
> Auch, wenn man das indirekt über einen Funktionspointer in einer (lokal
> const static deklarierten) Tabelle macht?
>
> Also von:
>
1
>     switch(whatever) {
2
>     case 0: tab[0](); break;
3
>     case 1: tab[1](); break;
4
>     default: break;
5
>     }
6
>
.
> zu:
>
1
>     if(whatever == 0) {
2
>         /* die funktion, auf die tab[0] zeigt */
3
>     } elsif(whatever == 1) {
4
>         /* die funktion, auf die tab[1] zeigt */
5
>     }
6
>
>
> automatisch? Denn das kann ich mir nicht vorstellen.

Bei LTO wird die komplette interne Darstellung einer "C-Datei" oder 
korrekt Übersetzungseinheit an den Linker übergeben, d.h. die 
Optimierung kann dort mit der gesammelten Info über alle Code-Schnipsel 
stattfinden.

von Oliver S. (oliverso)


Lesenswert?

Hinterher mal im Assembler-Listing nachschauen, was der Compiler jetzt 
tatsächlich draus gemacht hat, schadet aber trotzdem nicht.

Oliver

von MaWin (Gast)


Lesenswert?

S. R. schrieb:
> automatisch? Denn das kann ich mir nicht vorstellen.

Ich weiß nicht, ob der gcc das tut. Aber ich halte es nicht für 
unmöglich. Es müss(t)en halt mehrere Optimierungen zusammenarbeiten.

Ich denke aber, dass eher das switch rausfliegen wird und Arithmetik auf 
die Tabelle angewendet wird.

Am Ende ist das aber auch ein Spezialfall. Nimm halt keine Tabelle.

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.