Forum: Compiler & IDEs C Optimierung ISR


von Thomas P. (topla)


Lesenswert?

Hallo zusammen,

ich habe hier auf einem ATMega2560 eine ISR, die serielle Daten entgegen 
nimmt und in einem Puffer ablegt. Nach dem Empfang des letzten Zeichen 
läuft eine Auswertung direkt in der ISR, die Daten in einem Array 
ablegt. Passt auch alles und funktioniert reibungslos. In der ISR werden 
8 Register gesichert und wieder hergestellt. Jetzt ist bei der 
Auswertung noch etwas hinzugekommen, was dazu führt, dass der Compiler 
der Meinung ist, 27 Register sichern (und wieder herstellen) zu müssen. 
Gut, wenn er meint...
Zeitlich passt das auch noch in den Rahmen, mich ärgert aber, dass bei 
einer durchschnittlichen Telegrammlänge von 10 Zeichen 342 Befehle für 
vollkommen sinnlose push/pop-Orgien verbraten werden, da der diese 
Ressourcen benötigende Programmteil garnicht durchlaufen wird. Im 
Assembler hätte ich die Rettung zusätzlich benötigter Register direkt in 
den entsprechenden Programmabschnitt gepackt.
Frage:
Kann ich das auch dem Compiler beibiegen und wenn ja, wie?

Thomas

von P. M. (o-o)


Lesenswert?

Grundsätzlich kann man darauf hoffen, dass der Compiler dies beim 
Optimieren auch sieht.

Aber: Kannst du nach Empfang des letzten Zeichens nicht einfach ein Flag 
setzen und die Auswertung dann in der Hauptschleife machen? Das ist IMHO 
die sauberere Lösung, wenn man die Zeit dazu hat.

von Falk B. (falk)


Lesenswert?

@ Thomas P. (topla)

>ich habe hier auf einem ATMega2560 eine ISR, die serielle Daten entgegen
>nimmt und in einem Puffer ablegt.

Das ist normal.

> Nach dem Empfang des letzten Zeichen
>läuft eine Auswertung direkt in der ISR, die Daten in einem Array
>ablegt.

Das schon weniger. Muss das sein? Kann man nicht auch ein Signal an die 
Hauptschelife  senden? Siehe Interrupt.

> Passt auch alles und funktioniert reibungslos. In der ISR werden
>8 Register gesichert und wieder hergestellt. Jetzt ist bei der
>Auswertung noch etwas hinzugekommen, was dazu führt, dass der Compiler
>der Meinung ist, 27 Register sichern (und wieder herstellen) zu müssen.
>Gut, wenn er meint...

Du hast wahrscheinlich eine Funktion aufgerufen.

>Kann ich das auch dem Compiler beibiegen und wenn ja, wie?

Poste deine ISR als Anhang. Dann reden wir weiter.
Wahrscheinlich muss man die Funktionen als Inline deklarieren. Oder 
einfach direkt als Code in die ISR packen.

von Thomas P. (topla)


Angehängte Dateien:

Lesenswert?

Falk B. schrieb:
> Das schon weniger. Muss das sein? Kann man nicht auch ein Signal an die
> Hauptschelife  senden? Siehe Interrupt.

Ist mir bekannt, wird dann u. U. aber zeitkritisch zwischen den nächsten 
eintreffenden Daten und der Umlaufzeit in der Hauptschleife. Da sich 
diese Verfahrensweise schon auf dem DS80C320 bewährt hat, wollte ich da 
jetzt nicht alles grundsätzlich neu erfinden.

> Du hast wahrscheinlich eine Funktion aufgerufen.

Nein, ist eigentlich nur Bitschubserei und Ablage in einem Array.

> Poste deine ISR als Anhang. Dann reden wir weiter.

Da ist sie.

Thomas

von Klaus (Gast)


Lesenswert?

@ Thomas P.

Könntest Du bitte den Compiler nennen (und dessen genaue Version) sowie 
die Compilerflags, die beim compilieren der ISR gesetzt sind, posten?

von Falk B. (falk)


Lesenswert?

@Thomas P. (topla)

>> Du hast wahrscheinlich eine Funktion aufgerufen.

>Nein, ist eigentlich nur Bitschubserei und Ablage in einem Array.

Hmm, was hängt aber hinter den Macros?

XBUS_SEND_EIN;

Der Rest sieht normal aus. Hmmm?

von Thomas P. (topla)


Lesenswert?

Falk B. schrieb:

> Hmm, was hängt aber hinter den Macros?
>
> XBUS_SEND_EIN;

#define XBUS_SEND_EIN PORTG |= (1<<XBUS_DIR)

> Der Rest sieht normal aus. Hmmm?

@Klaus (Gast):
avr-gcc (avr_8_bit_gnu_toolchain_3.4.1_798) 4.6.2 unter AVRStudio 4.19
-Wall -gdwarf-2 -std=gnu99 -gstrict-dwarf -DF_CPU=16000000UL -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums

Thomas

@ Sabe (Gast): freut mich, wenn es Dir gut geht.

von Lurchi (Gast)


Lesenswert?

So weit ich weiss verschiebt zumindest GCC das sichern der Register 
nicht nach hinten, sondern macht es immer in einem Rutch am Anfang.
Der nur selten benutzte Code nutzt ggf. schon relativ viele Register 
wegen der Arrayzugriffe und >> operatoren. Auf 27 Register zu kommen ist 
da aber schon viel.
Eine Optimierung wäre ggf. bei den Abfragen über die shift operatoren 
möglich. Es hängt noch von den Datentyen ab. Ggf. ließe sich der 
Konstante Vergleichswert verschieben um die Bits abzufragen, statt die 
Werte aus der Tabelle zu schieben.

von Thomas P. (topla)


Lesenswert?

Ja, sieht so aus.
Sowas:
switch (xbus_ebuf[i+2] & 0b01100000)
ist im Registerbedarf teuer.
Macht ja auch nichts, so richtig stören mich eigentlich nur die vielen 
unnötigen push/pop.
Irgendwie hätte ich bei den ganzen Arrayzugriffen auch die eine oder 
andere Multiplikation erwartet, aber der addiert sich nur zu Tode.

Thomas

von Peter D. (peda)


Lesenswert?

Man kann den SPM READY Interrupt freigeben und dann in dessen Handler 
die Auswertung machen.

von Kaj (Gast)


Lesenswert?

Thomas P. schrieb:
> Irgendwie hätte ich bei den ganzen Arrayzugriffen auch die eine oder
> andere Multiplikation erwartet, aber der addiert sich nur zu Tode.
keine cpu addiert sich zu tode, denn das ist das, was sie am besten 
kann.
Hast du mal nachgerechnet, ob eine multiplikation (in deinem Falle) 
überhaupt schneller wäre?

von Thomas P. (topla)


Lesenswert?

Kaj schrieb:
> Hast du mal nachgerechnet, ob eine multiplikation (in deinem Falle)
> überhaupt schneller wäre?

Nein, nachdem ich hier mehrfach darauf hingewiesen wurde, mich statt um 
die Arbeit des Compilers lieber um mein Programm zu kümmern. Im 
Zusammenhang mit der push/pop-Orgie fiel mir nur auf, das der 8051-Code 
in diesem Umfeld mehrere MUL aufweist.


Peter D. schrieb:
> Man kann den SPM READY Interrupt freigeben und dann in dessen Handler
> die Auswertung machen.


Hallo Peter,

tut mir leid, ich bekomme keinen Zusammenhang zwischen Datenempfang auf 
einer seriellen Schnittstelle und Interrupt beim Schreiben in den 
Programmspeicher hin.

Thomas

von chris (Gast)


Lesenswert?

Thomas P. schrieb:
> Hallo Peter,
>
> tut mir leid, ich bekomme keinen Zusammenhang zwischen Datenempfang auf
> einer seriellen Schnittstelle und Interrupt beim Schreiben in den
> Programmspeicher hin.

Wenn ich das richtig verstehe, meint Peter, die Auswertung in den 
SPM-Interrupt auszulagern. Diesen gibst du dann frei, wenn dein String 
komplett empfangen ist. Dadurch wird dieser sofort ausgeführt, weil der 
Programmspeicher bereit zum Schreiben ist (vermute ich nur, habs nicht 
nachgelesen!).
--> Deine Auswertung erfolgt auch 'sofort' und nicht erst in der main 
loop, aber du hast nicht bei jeder UART RX ISR die ganzen push/pop drin 
sondern nur im (selten ausgeführten) SPM Ready Interrupt.
Mit Schreiben auf den Programmspeicher hat das nix zu tun, aber der 
Interrupt kann gut für andere Zwecke missbraucht werden.

von Oliver S. (oliverso)


Lesenswert?

Thomas P. schrieb:
> Jetzt ist bei der
> Auswertung noch etwas hinzugekommen, was dazu führt, dass der Compiler
> der Meinung ist, 27 Register sichern (und wieder herstellen) zu müssen.
> Gut, wenn er meint...

Meistens meint er das zu meinen müssen, wenn aus der ISR eine andere 
Funktion aufgerufen wird, die er nicht sieht. Dann kann er nur alle 
Register sichern. Wenn du also eine selbstgeschriebene Funktion aus der 
ISR heraus aufrufst, pack die mal zu der ISR in die .c-Datei. Dann wird 
es besser.

Oliver

von Thomas P. (topla)


Lesenswert?

@ chris (Gast):
Danke für den Hinweis, hätte mir ja denken können, dass von Peter solche 
genialen Gedanken kommen. Wäre echt eine Möglichkeit.

@ Oliver S.:
Den Gedanken hatte Falk ja oben auch schon, ist aber bis auf ein Makro 
nicht so (siehe Dateianhang).

Sieht schon spannend aus:
ISR(USART0_RX_vect)
{
    167a:  1f 92         push  r1
    167c:  0f 92         push  r0
    167e:  0f b6         in  r0, 0x3f  ; 63
    1680:  0f 92         push  r0
    1682:  0b b6         in  r0, 0x3b  ; 59
    1684:  0f 92         push  r0
    1686:  11 24         eor  r1, r1
    1688:  5f 92         push  r5
    168a:  6f 92         push  r6
    168c:  7f 92         push  r7
    168e:  8f 92         push  r8
    1690:  9f 92         push  r9
    1692:  af 92         push  r10
    1694:  bf 92         push  r11
    1696:  cf 92         push  r12
    1698:  df 92         push  r13
    169a:  ef 92         push  r14
    169c:  ff 92         push  r15
    169e:  0f 93         push  r16
    16a0:  1f 93         push  r17
    16a2:  2f 93         push  r18
    16a4:  3f 93         push  r19
    16a6:  4f 93         push  r20
    16a8:  5f 93         push  r21
    16aa:  6f 93         push  r22
    16ac:  7f 93         push  r23
    16ae:  8f 93         push  r24
    16b0:  9f 93         push  r25
    16b2:  af 93         push  r26
    16b4:  bf 93         push  r27
    16b6:  cf 93         push  r28
    16b8:  df 93         push  r29
    16ba:  ef 93         push  r30
    16bc:  ff 93         push  r31

Thomas

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Thomas P. schrieb:
> Sieht schon spannend aus:
> ISR(USART0_RX_vect)
> {
>     167a:  1f 92         push  r1
>     [...]
>     16bc:  ff 93         push  r31

Und? Benutzt er die auch alle in der ISR? Wenn ja, wo? Zeig doch bitte 
mal die komplette ISR in der ASM-Version.

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn man wenigstens eine Idee hätte, welche der vielen undeclared
identifieres nun Variablen, Konstanten etc. sind (sodass man
compilierbaren Code bekommt), dann wäre es wohl leichter, dir da
Ratschläge zu geben.

Ich hab's erstmal aufgegeben, das Ding zum Compilieren zu bekommen.

von Thomas P. (topla)


Lesenswert?

Jörg W. schrieb:

> Ich hab's erstmal aufgegeben, das Ding zum Compilieren zu bekommen.

Hallo Jörg,
danke für Deine Bemühungen. Wenn es zum Erkenntnisgewinn beiträgt, setze 
ich mich hin und suche die verschiedenen Definitionen zusammen.
Allerdings habe ich für mich jetzt erstmal mitgenommen, dass es ohnehin 
nicht ohne Tricks möglich ist, die Registerrettung an die Stelle im 
Programmablauf zu schieben, die diese auch benötigt.

@ Frank M. (ukw):
Nein, es werden wohl nicht alle Register auch wirklich benutzt, keine 
Ahnung was den Compiler zu der Annahme treibt.


Thomas

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas P. schrieb:
> Allerdings habe ich für mich jetzt erstmal mitgenommen, dass es ohnehin
> nicht ohne Tricks möglich ist, die Registerrettung an die Stelle im
> Programmablauf zu schieben, die diese auch benötigt.

Da bin ich mir eben noch nicht ganz so sicher.

von Thomas P. (topla)


Angehängte Dateien:

Lesenswert?

Ich habe das mal alles zusammengefegt; sieht nicht schön aus, sollte 
aber compilierbar sein - hoffe ich.

thomas

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Thomas P. schrieb:
> sollte aber compilierbar sein

Ist es offenbar nicht.

Bereits die erste Zeile führt zu einem Fehler.

von Ralf G. (ralg)


Lesenswert?

Johann L. schrieb:
> Ist es offenbar nicht.
'main()' fehlt auch.

Ich könnte mir vorstellen, dass der Compiler versucht, die Bitfelder 
durch exzessive Registernutzung einigermaßen optimal einzubinden.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ralf G. schrieb:
> 'main()' fehlt auch.

Es geht ja nur um ein Modul, und um ein solchen zu compilieren braucht's 
keine main:

Es recht azs, wenn ein modul.c zu einem modul.o übersetzbar ist, d.h.:
1
avr-gcc -c modul.c ...
ohne Fehler zu produzieren ausgeführt werden kann.  Der einfachste Weg, 
um an für andere reproduzierbaren Code zu gelangen, ist den Optionen -v 
-save-temps zuzufügen, und das i-File samt Optionen zu posten.

Wirklich toll ist diese Methode aber nicht, da im i-File alle Makros und 
Includes aufgelöst sind, so dass das .i schwer zu lesen ist.

Für einen richtigen COMPILIERBAREN Testfall, der nicht gleich alle 
potentiellen Helfer in die Flucht schlägt wegen

o nicht ohne Fehler übersetzbar (fehlende Deklarationen, Macros, etc.)

o Optionen oder Tool-Version werden verheimlicht

o Code-Formatierung wie Kraut & Rüben

o Code-Verschleierung per "...", // hier stand ein Code
  etc.

o beliebig verhachstückte Code-Schnippel, die per Copy & Paste
  aus der Quelle herausgebrochen wurden

o Absolutes Unverständnis, was ANDERE benötigen, um das
  Problem nachzuvollziehen

von Peter D. (peda)


Lesenswert?

Thomas P. schrieb:
> tut mir leid, ich bekomme keinen Zusammenhang zwischen Datenempfang auf
> einer seriellen Schnittstelle und Interrupt beim Schreiben in den
> Programmspeicher hin.

Der UART-Interrupt schreibt in eine FIFO und macht die 
Paket-Ende-Erkennung.
Bei Paket-Ende enabled er den SPM-Interrupt. Dieser wiederum disabled 
sich, erlaubt andere Interrupts und wertet dann in aller Ruhe das Paket 
aus.
Der SPM-Interrupt wird damit als SW-Interrupt verwendet.

Auch Interrupts, deren Pending Bit nach Reset gesetzt ist, können als 
SW-Interrupt verwendet werden, z.B. ein nicht benutztes USARTx-UDRE.

von Peter D. (peda)


Lesenswert?

Thomas P. schrieb:
> sieht nicht schön aus, sollte
> aber compilierbar sein - hoffe ich.

Warum so ängstlich?
Ein simpler Klick auf "Build" hätte sofort aus der Hoffnung Gewißheit 
machen können.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Bereits die erste Zeile führt zu einem Fehler.

Kannst du aber auskommentieren, dann compiliert es.  So flexibel
bin ich dann noch. ;-)

GCC 4.7.2 rettet R15 … R31 (und natürlich R0/R1).
GCC 4.9.3 rettet R14 … R31 und R0/R1, generiert aber insgesamt 10
Byte kleineren Code.

Scheint beides schon mal besser zu sein als bei Thomas.

Einen 5er GCC habe ich jetzt nicht noch gebaut.  Sinnvoller wäre es
schätzungsweise zu sehen, ob man mit irgendwelchen -f-Optionen noch
bisschen Finetuning erreicht, aber Johann, da kennst du dich sicher
besser aus.

von Thomas P. (topla)


Lesenswert?

Hallo Johann,
ja, ich weiß, dass ich hier der Depp bin, und zu dem habe ich mich auch 
noch selber gemacht, indem ich in einem Anfall von Wahnsinn beschlossen 
habe, das Projekt statt in Assembler in C zu realisieren.

Ich habe extra den ganzen Definitionsteil in die angehangene Datei 
eingefügt, damit nicht so viele includes mitgeliefert werden müssen. 
Dabei habe ich das Entfernen der ersten Zeile verbrummt, blöd, weil der 
Fehler hier wegen der vorhandenen Datei (auch wenn nix mehr drin steht) 
eben nicht auftaucht.
Tool-Version und Optionen stehen etwas weiter oben.
Die Formatierung passt im AVR-Studio einwandfrei, da bleibt wohl was 
unterwegs auf der Strecke.
Verschleiert ist hier garnichts, der Code kommt 1:1 aus dem Projekt.
Es sind auch keine kopierten Codeschnipsel, sondern die ISR ist komplett 
im derzeitigen Zustand, wenn auch noch nicht vollständig. Hat aber mit 
meiner ursprünglichen Anfrage ("Warum sichert der Compiler alle Register 
am ISR-Anfang und nicht erst dann, wenn er die Register wirklich braucht 
und kann man das beeinflussen?") überhaupt nichts zu tun.

@Peter Dannegger
Ich bin da nicht ängstlich, aber die Antwort von Johann hat doch gleich 
gezeigt, dass das, was bei mir einwandfrei funktioniert, bei anderen 
nicht auch so sein muss - deshalb der Hinweis.
Danke für Erklärung mit dem SPM-Int, mit Hilfe von chris war ich dann 
gestern schon selber auf die richtige Spur gekommen.

Thomas

von Ralf G. (ralg)


Lesenswert?

Jörg W. schrieb:
> GCC 4.7.2 rettet R15 … R31 (und natürlich R0/R1).
> GCC 4.9.3 rettet R14 … R31 und R0/R1, generiert aber insgesamt 10

... und die Register werden auch alle verwendet. (Wenn mir nicht eins 
durch die Lappen gegengen ist.)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas P. schrieb:
> Die Formatierung passt im AVR-Studio einwandfrei, da bleibt wohl was
> unterwegs auf der Strecke.

Das ist das übliche Dilemma: die Unix-Welt rückt bei einem TAB-Zeichen
gern auf eine durch 8 teilbare Position vor (das entspricht dem, wie
es eben seit DECs VT100 in der Hardware voreingestellt ist), die
Windows-Welt in aller Regel auf eine durch 4 teilbare.

Da das bisschen Speicherplatz heutzutage nichts mehr kostet, kommt
man im Sinne der Les- und Austauschbarkeit besser, die Einrückungen
nur durch Leerzeichen vornehmen zu lassen.

von Thomas P. (topla)


Lesenswert?

Jörg W. schrieb:
> Da das bisschen Speicherplatz heutzutage nichts mehr kostet, kommt
> man im Sinne der Les- und Austauschbarkeit besser, die Einrückungen
> nur durch Leerzeichen vornehmen zu lassen.

Ja, ich habe den Haken in den options vom Editor gefunden und gesetzt. 
Man muss aber erstmal drauf kommen, dass man ein Problem hat.

Thomas

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

...ohne den Code übersetzt zu haben: Folgendes scheint nicht ganz 
unproblematisch.

#1

> int verr:1;

1-Bit signed Variablen können nur die Werte -1 oder 0 annehmen.  Im Code 
wird aber z.B. gegen 1 getestet.  Solche Vergleiche sind immer false!

#2

Code wie
1
if ((wdat[((xbus_ebuf[i+1])<<2) | (xbus_ebuf[i+2]>>6)].lage) != ((xbus_ebuf[i+2]) & 3))
ist zum einen schlecht lesbar und taucht zig-mal auf, insbesondere der 
Ausdruck für den Array-Index in wdat[].  Weil Daten geschreiben werden, 
darf der so berechnete Index nicht wiederverwendet werden, sondern 
muss wegen den Strict-Aliasing Regeln von C immer wieder neu gelesen und 
berechnet werden.

#3

Wenn du schon Bitfelder verwendest, dann leg die "ganzen" Komponenten 
wie 8-Bit breite Felder an den Anfang oder lass sie wenigstens an 
geraden (durch 8 teilbaren) Bit-Offsets starten.

#4

Beim besten Willen... der Quellcode ist eine Zumutung, ich hab's 
aufgegeben das zu lesen.  Dementsprechend ist auch eine Bewertung des 
vom GCC erzeugten Codes nicht möglich.

o Vermeide TABs.  Jeder halbwegs ordentliche Editor erlaubt es, 
(automatisch) SPACEs anstatt TABs zu verwenden, und zwar OHNE dass man 
beim Editieren was davon merkt.  Das TABs nicht protabel sind und die 
Lesbarkeit massic einschränken, wirst du kaum von der Hand weisen 
können.

o Versuche, immer wieder auftretende Sequenzen als (inline) Funktionen 
auszulagern.

o Code wie
1
rmdat[(xbus_ebuf[i+1])>>2] |= (xbus_ebuf[i+2] & 0x0f);
ist inhärent schlecht wartbar: Währewnd der Verarbeitung werden ständig 
die Indices der zu verarbeitenden Daten (xbus_ebuf[]) gepatcht.  Das 
Index-Array scheint ein wilder Zoo unterschiedlichster Daten zu sein.

von Thomas P. (topla)


Angehängte Dateien:

Lesenswert?

So, auf Grund Deiner Hinweise habe ich angefangen, den Code zu 
überarbeiten

> #1
gegen uint8_t ausgetauscht, längerfristig wird das noch umgestellt

> #2
neue Variablen eingeführt, die die erneuten Zugriffe auf den 
Empfangspuffer unnötig machen sollten

> #3
liegen sie doch?

> #4
Editor angepasst, im Quellcode Tabs ersetzt

> o Versuche, immer wieder auftretende Sequenzen als (inline) Funktionen
> auszulagern.

Schon wieder eine neue Baustelle, muss ich mir mal anlesen.

> o Code wie
1
rmdat[(xbus_ebuf[i+1])>>2] |= (xbus_ebuf[i+2] & 
2
> 0x0f);
ist inhärent schlecht wartbar: Währewnd der Verarbeitung
> werden ständig die Indices der zu verarbeitenden Daten (xbus_ebuf[])
> gepatcht.  Das Index-Array scheint ein wilder Zoo unterschiedlichster
> Daten zu sein.

Siehe #2, für die Aufteilung der angelieferten Daten kann ich aber 
wirklich nichts.

Thomas

von Thomas P. (topla)


Lesenswert?

Wird die Auswertung nach dem letzten Zeichen der seriellen Übertragung 
über den SPM-Interrupt ausgelagert, will der Compiler noch 9 Register 
sichern. Ist schon deutlich besser, es bleibt aber die etwas 
enttäuschende Erkenntnis, dass der Compiler nicht in der Lage ist, 
benötigte Ressourcen erst im Bedarfsfall zu frei zu räumen, speziell bei 
ISR, wo Laufzeit doch eine Rolle spielt.

Thomas

von Ralf G. (ralg)


Lesenswert?

Thomas P. schrieb:
> Ist schon deutlich besser, es bleibt aber die etwas
> enttäuschende Erkenntnis, dass der Compiler nicht in der Lage ist,
> benötigte Ressourcen erst im Bedarfsfall zu frei zu räumen, speziell bei
> ISR, wo Laufzeit doch eine Rolle spielt.

Die gesicherten Register werden alle in der ISR auch verwendet! Nichts 
mit prophylaktisch.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas P. schrieb:
> es bleibt aber die etwas enttäuschende Erkenntnis, dass der Compiler
> nicht in der Lage ist, benötigte Ressourcen erst im Bedarfsfall zu frei
> zu räumen

Hajo, so isch des.  Die Sicherung der benötigten Ressourcen auf dem
Stack erfolgt immer bereits beim Eintritt in eine Funktion (Johann
kann mich gern widerlegen).

Alternative wäre in deinem Falle natürlich wirklich, die ISR mal in
Assembler zu zimmern.  Dann kannst du initial nur das Notwendigste
sichern und für den Rest dann eine C-Funktion aufrufen, bei der du
zuvor das „Komplettprogramm“ abarbeitest (also alle gemäß ABI zu
sichernden Register retten).

von Ralf G. (ralg)


Lesenswert?

Jörg W. schrieb:
> Die Sicherung der benötigten Ressourcen auf dem
> Stack erfolgt immer bereits beim Eintritt in eine Funktion

Sogar der Compiler will die Übersicht behalten ;-)

von Thomas P. (topla)


Lesenswert?

Ralf G. schrieb:

> Die gesicherten Register werden alle in der ISR auch verwendet! Nichts
> mit prophylaktisch.

Jein, im kritischen Pfad, also beim Durchlaufen des Auswertungsteils 
schon, aber der wird eben im Durchschnitt nur bei jedem 10. Aufruf 
angesprochen. Nett wäre es eben, wenn die für diesen Pfad benötigten 
Register erst dann gesichert würden, wenn dieser auch wirklich 
durchlaufen wird, also nach der Verzweigung eben.

Thomas

von Ralf G. (ralg)


Lesenswert?

Thomas P. schrieb:
> Sieht schon spannend aus:
> ISR(USART0_RX_vect)
> {
>     167a:  1f 92         push  r1
>     167c:  0f 92         push  r0
>     167e:  0f b6         in  r0, 0x3f  ; 63
>     1680:  0f 92         push  r0
>     1682:  0b b6         in  r0, 0x3b  ; 59
>     1684:  0f 92         push  r0
>     1686:  11 24         eor  r1, r1
/*
 wird bei mir nicht gesichert (gcc 4.7.2):
>     1688:  5f 92         push  r5
>     168a:  6f 92         push  r6
>     168c:  7f 92         push  r7
>     168e:  8f 92         push  r8
>     1690:  9f 92         push  r9
>     1692:  af 92         push  r10
>     1694:  bf 92         push  r11
>     1696:  cf 92         push  r12
>     1698:  df 92         push  r13
*/

Thomas P. schrieb:
> Jein, im kritischen Pfad, also beim Durchlaufen des Auswertungsteils
> schon, aber der wird eben im Durchschnitt nur bei jedem 10. Aufruf
> angesprochen. Nett wäre es eben, wenn die für diesen Pfad benötigten
> Register erst dann gesichert würden, wenn dieser auch wirklich
> durchlaufen wird, also nach der Verzweigung eben.

Aah, verstehe.

Jörg W. schrieb:
> Alternative wäre in deinem Falle natürlich wirklich, die ISR mal in
> Assembler zu zimmern.

Ich bin hier nicht der Experte, aber da hätte man sich die der 
Sicherheit dienenden Zugriffe auf die Bitfelder ja sparen können. Nur 
zum 'Umlagern' von 'push/ pop' würde ich mir das nicht antuen. Die 
Register wird man trotzdem für die Indizes und das Vorhalten der 
Zwischenergebnisse in den Abfragen brauchen.

Bitfelder rausschmeißen ergibt zwar weniger Code, aber die 
Registersicherung wird nicht kürzer. Der LTO hilft dem Compiler bei der 
Codgröße enorm, spart jedoch nur noch r14 ein.

von Falk B. (falk)


Lesenswert?

Bei allem Engagement sollte man doch aber bitte das Wesentlich nicht aus 
den Augen verlieren.

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung

von Peter D. (peda)


Lesenswert?

Man sollte aber nicht zu tode optimieren.
Der kleinst mögliche UART-Teiler ist 8, d.h. der Interrupt hat 
mindestens 80 Zyklen zur Verfügung.

Da die UART bis zu 3 Byte puffern kann, kann man auch eine Loop 
schreiben, die am Ende nochmal das Empfangsflag testet, d.h. den 
Interrupt bei Bedarf nochmal ausführt ohne weiteres POP/PUSH.

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.