Forum: Compiler & IDEs AVR-GCC generiert unnötigen(?) ISR overhead


von Andre R. (ryan87)


Lesenswert?

Hallo Leute,

ich bin grad dabei eine möglichst schnelle SPI interrupt routine zu 
schreiben und hab mir zu dem Zweck mal das listing (lss) vom avr-gcc 
angeguckt. Ich verwende einen ATmega168P. Optimierung -Os

Hier der C-Code:
1
uint8_t rxd;
2
uint8_t txd;
3
4
ISR(SPI_STC_vect)
5
{
6
  rxd = SPDR;
7
  SPDR = txd;
8
}

und hier das Resultat (ASM + C mix):
1
uint8_t rxd;
2
uint8_t txd;
3
4
ISR(SPI_STC_vect)
5
{
6
  90:  1f 92         push  r1
7
  92:  0f 92         push  r0
8
  94:  0f b6         in  r0, 0x3f  ; 63
9
  96:  0f 92         push  r0
10
  98:  11 24         eor  r1, r1
11
  9a:  8f 93         push  r24
12
  rxd = SPDR;
13
  9c:  8e b5         in  r24, 0x2e  ; 46
14
  9e:  80 93 01 01   sts  0x0101, r24
15
  SPDR = txd;
16
  a2:  80 91 00 01   lds  r24, 0x0100
17
  a6:  8e bd         out  0x2e, r24  ; 46
18
}
19
  a8:  8f 91         pop  r24
20
  aa:  0f 90         pop  r0
21
  ac:  0f be         out  0x3f, r0  ; 63
22
  ae:  0f 90         pop  r0
23
  b0:  1f 90         pop  r1
24
  b2:  18 95         reti

So, Quizfragen:
1. Was wird da  mit r1 gemacht? Das ergibt keinen Sinn für mich.
2. Könnte man nicht anstelle von r24 auch r0 verwenden oder umgekehrt. 
Das würde dann ein Register weniger machen.
3. Wozu push und pop von r0 bei Adresse 96 und aa?

Mag mich vielleicht jemand erleuchten?

von Serieller (Gast)


Lesenswert?

Zu 3. An den Stellen wird SREG gerettet und restauriert.

Grundsätzlich würde ein Register ausreichen. Erzeugen andere 
Optimierungsstufen besseren oder schlechteren Code?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Der ISR-Prolog wird auch bei anderen Optimierungen gleich bleiben.

Er ist i.W. statisch, zumindest was zero_reg (R1) und tmp_reg (R0) und 
das Sichern von SREG angeht.

Wenn's wirklich auf das letzte Tick ankommt --> (Inline) Assembler

von Andre R. (ryan87)


Lesenswert?

Serieller schrieb:
> Zu 3. An den Stellen wird SREG gerettet und restauriert.
>
> Grundsätzlich würde ein Register ausreichen. Erzeugen andere
> Optimierungsstufen besseren oder schlechteren Code?

Bei 94 wird doch SREG in r0 geladen. Bei AC wiederhergestellt. 
Dazwischen liegt ein push r0 und pop r0. Ohne das in dem Bereich r0 
geändert wird. Das verwundert mich.

Andere Optimierungsstufen bringen wie bereits vermutet keine Änderungen.

von Peter D. (peda)


Lesenswert?

Bei Entwicklung des AVR-GCC wurden irrtümlich R0, R1 als Null und 
SREG-Sicherung festgelegt.
Sie sind aber verbrannte Register, da einige Befehle sie zerstören (LPM, 
SPM, MUL).
Es traut sich aber keiner, das zu korrigieren (z.B. auf R2, R3), daher 
ist dieser Overhead bis in alle Ewigkeit drin.
Und auch nach jedem MUL-Befehl muß das Nullregister schnell wieder 
gelöscht werden.


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Bei Entwicklung des AVR-GCC wurden irrtümlich R0, R1 als Null und
> SREG-Sicherung festgelegt.

Das ist kein Irrtum.

> Sie sind aber verbrannte Register, da einige Befehle sie zerstören (LPM,
> SPM, MUL).

Wenn tmp_reg anders läge und ein MUL ausgeführt würde, müssten noch mehr 
GPRs gesichert werden (R0, R1, R2, R3). Dann wär das Geschrei noch 
größer.

> Es traut sich aber keiner, das zu korrigieren (z.B. auf R2, R3), daher
> ist dieser Overhead bis in alle Ewigkeit drin.

Wegen 2 push/pop das ABI ändern???

Andre R. schrieb:

> Andere Optimierungsstufen bringen wie bereits vermutet keine Änderungen

Das ist keine Vermutung, es steht in den GCC-Quellen.

Johann

von Oliver (Gast)


Lesenswert?

Es wurde ja weiter oben schon geschrieben, wenn es tatsächlich auf diese 
2 Zyklen weniger ankommt, muß man die ISR halt in Assembler schreiben.

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oder avr-gcc v8 + Binutils 2.29 verwenden:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
uint8_t rxd;
5
uint8_t txd;
6
7
ISR (SPI_STC_vect)
8
{
9
  rxd = SPDR;
10
  SPDR = txd;
11
}
12
13
int main;
1
$ avr-gcc -mmcu=atmega8 isr.c -Os && avr-objdump -d a.out
1
00000048 <__vector_10>:
2
  48:   8f 93           push    r24
3
  4a:   8f b1           in      r24, 0x0f       ; 15
4
  4c:   80 93 63 00     sts     0x0063, r24     ; 0x800063 <rxd>
5
  50:   80 91 62 00     lds     r24, 0x0062     ; 0x800062 <txd>
6
  54:   8f b9           out     0x0f, r24       ; 15
7
  56:   8f 91           pop     r24
8
  58:   18 95           reti

Je nach Dauer von push / pop sind das dann 9 bis 15 Zyklen.

von Bernd (Gast)


Lesenswert?

Leichenfledderer. ;))

Hast du einen Link zu einem Windows-Binary deines gcc v8?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bernd schrieb:
> Leichenfledderer. ;))

Isch weiß.

> Hast du einen Link zu einem Windows-Binary deines gcc v8?

Nö.

von Eric B. (beric)


Lesenswert?

Johann L. schrieb:
> uint8_t rxd;
> uint8_t txd;

<korinthen>Fehlt da nicht ein volatile? </korinthen>

von Bernd (Gast)


Lesenswert?

Schade. Dann war die Störung der Totenruhe ja völlig umsonst. Dabei war 
die Lieferzeit schon fast um!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Eric B. schrieb:
> Johann L. schrieb:
>> uint8_t rxd;
>> uint8_t txd;
>
> <korinthen>Fehlt da nicht ein volatile? </korinthen>

Musst du den Autor (TO) fragen. Ansonsten ist es gültiger C-Code, der 
die Sachlage ebenso gut demonstriert wie mit volatile.

von Bernd (Gast)


Lesenswert?

Äh, Liegezeit. Blöde Autokorrektur.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bernd schrieb:
> Schade. Dann war die Störung der Totenruhe ja völlig umsonst.

Wieso?

Es ist ein Beitrag zum Thema, und wenn ein Suchender die Web-Suche 
bemüht, ist es nicht unwahrscheinlich, dass er hier langet.

: Bearbeitet durch User
von Bernd (Gast)


Lesenswert?

Ja. Und wenn er nicht zu den 1% Linux-Kellerkindern gehört, ist er 
enttäuscht, weil er die neue Version gar nicht nutzen kann.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Bernd schrieb:
> Ja. Und wenn er nicht zu den 1% Linux-Kellerkindern gehört, ist er
> enttäuscht, weil er die neue Version gar nicht nutzen kann.

Er weiß aber, dass das neue Feature in Arbeit und sogar schon recht weit
fortgeschritten ist, und dass deswegen in absehbarer Zeit ganz sicher
auch ein Binary-Release für Leute ohne Keller verfügbar sein wird.

Auch ich werde jetzt nicht sofort in den Keller gehen und die neue
Version bauen, da ich zur Zeit nichts mit AVRs mache. Trotzdem ist die
Information für mich wertvoll. Denn wenn der Zeitpunkt gekommen ist, wo
ich wieder etwas mit AVRs anfange, weiß ich, dass ich mich erst einmal
nach einem neuen GCC-Release umsehen sollte, das es bis dahin vielleicht
auch als Ready-To-Use-Paket gibt.

Insofern finde ich es super von Johann, dass er uns bzgl. interessanter
Weiterentwicklungen des AVR-GCC auf dem Laufenden hält.

von Raoul D. (raoul_d219)


Lesenswert?

Yalu X. schrieb:
> Bernd schrieb:
>> Ja. Und wenn er nicht zu den 1% Linux-Kellerkindern gehört, ist er
>> enttäuscht, weil er die neue Version gar nicht nutzen kann.

Nach 2 x git pull und jeweils 2 x make install hatte ich unter 
/usr/local/avr-git nach ca. 60 min. alles zur Verfügung (die 
Arch-Linux-User sollten allerdings in den binutils guile deaktivieren).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Er weiß aber, dass das neue Feature in Arbeit und sogar schon recht weit
> fortgeschritten ist,

Was die Quellen angeht, ist das Feature fertig, d.h. upstream in GCC und 
Binutils.  Extra Patches braucht man also keine.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bernd schrieb:
> Hast du einen Link zu einem Windows-Binary deines gcc v8?

Eins hochgeladen als "avr-gcc-8.0_2017-07-17_mingw32.zip" in

https://sourceforge.net/projects/mobilechessboar/files/avr-gcc%20snapshots%20%28Win32%29/

Einfach das ZIP an einen gewünschten Ort auspacken.

Verwenden durch absoluten Pfad nach ..../bin/avr-gcc bzw. 
..../bin/avr-gcc-8.0.0 oder Eintragen in Umgebungsvariable PATH.

Enthält GCC trunk, Binutils master and AVR-LibC trunk + 
https://savannah.nongnu.org/patch/?9400

Passendes Manual dazu: http://gcc.gnu.org/onlinedocs/gcc/

: Bearbeitet durch User
von Bernd (Gast)


Lesenswert?

Die Windows-Kellerkinder bedanken sich! :D

Leider hängt sich der gcc in einem ersten Test beim Kompilieren komplett 
auf (100% CPU-Last, bis man abbricht). Ich muss in den nächsten Tagen 
mal schauen, ob ich ein Testbeispiel hinkriege. Kann aber etwas dauern.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bernd schrieb:
> Die Windows-Kellerkinder bedanken sich! :D
>
> Leider hängt sich der gcc in einem ersten Test beim Kompilieren komplett
> auf (100% CPU-Last, bis man abbricht). Ich muss in den nächsten Tagen
> mal schauen, ob ich ein Testbeispiel hinkriege. Kann aber etwas dauern.

Hängt auch bei mir. :-/ Ich werd die Version wieder offline nehmen.

Ne Windows version zu erstellen ist etwas aufwändig, und richtig testen 
kann ich das auch nicht außer auf ner alten Win2000-Nudel.  Und den 
Compiler Debuggen kann ich auch nicht...

von Nico W. (nico_w)


Lesenswert?

Wegen dem Thread hatte ich gestern auch einmal das Bedürfnis die ganze 
Geschichte selbst zu basteln. Bin dann um 2 Uhr auch fast fertig 
geworden. Kompillieren konnte ich, allerdings habe ich ein paar Probleme 
mit der aktuellen avr-libc.

In meinem Arduino-Ordner (Windows) oder unter /usr/avr...(Ubuntu) 
befinden sich in den Ordnern z.B. crtatemga2560.o und libatmega2560.a

Wenn ich jetzt die avr-libc-bin-1.8.1.zip oder die 2.0.0 angucke [*1],
dann befindet sich dort nur eine crtm2560.o

Was mach ich da falsch?

[*1] 
https://download.savannah.gnu.org/releases/avr-libc/binary-releases/

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


Lesenswert?

Die Namen in der avr-libc sind abhängig von der Compilerversion.
Sie passen sich an das an, was der Compiler dann sehen will.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Nico W. schrieb:
> In meinem Arduino-Ordner (Windows) oder unter /usr/avr...(Ubuntu)
> befinden sich in den Ordnern z.B. crtatemga2560.o und libatmega2560.a
>
> Wenn ich jetzt die avr-libc-bin-1.8.1.zip oder die 2.0.0 angucke [*1],
> dann befindet sich dort nur eine crtm2560.o
>
> Was mach ich da falsch?

Du musst den Compiler zum generieren der AVR-LibC verwenden, der auch in 
der zu erstellenden Toolchain verwendet wird.

Also den bereits installierten avr-gcc in den Pfad aufnehmen oder
1
../../sources/avr-libc/trunk/configur --host=avr --prefix=$INSTALL_PATH CC=$INSTALL_PATH/bin/avr-gcc
Bei einem Canadian-Cross Build muss CC= natürlich zum build->target 
compiler zeigen, nicht zum host->target compiler.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Bernd schrieb:
>> Hast du einen Link zu einem Windows-Binary deines gcc v8?

Versuch #2 hochgeladen als "avr-gcc-8.0_2017-07-18_mingw32.zip" in
https://sourceforge.net/projects/mobilechessboar/files/avr-gcc%20snapshots%20%28Win32%29/

Zur Verwendung gilt das gleiche wie oben:

> Einfach das ZIP an einen gewünschten Ort auspacken.
>
> Verwenden durch absoluten Pfad nach ..../bin/avr-gcc bzw.
> ..../bin/avr-gcc-8.0.0 oder Eintragen in Umgebungsvariable PATH.
>
> Enthält GCC trunk, Binutils master and AVR-LibC trunk +
> https://savannah.nongnu.org/patch/?9400
>
> Passendes Manual dazu: http://gcc.gnu.org/onlinedocs/gcc/

Ich hab versucht einen anderen x86_64-linux-gnu -> mingw32 
Cross-Toolchain zu verwenden.  Angetestet unter wine schein das Ergebnis 
zu funktionieren, mit einem älteren Windos bekomme ich allerdings
1
e:/winavr/8.0_2017-07-18/bin/../lib/gcc/avr/8.0.0/../../../../avr/bin/ld.exe: error: asprintf failed

Mit -fno-use-linker-plugin oder explizit -fno-lto lässt es sich umgehen.

Warum dieser Fehler auftritt weiß ich nicht, vielleicht ein Problem mit 
der asprintf Implementierung von M$; im Endeffekt das gleiche Problem, 
das ich schon hier hatte:

Beitrag "Re: AVR-GCC selbst bauen - Unter Linux für Windows?"

von Nico W. (nico_w)


Lesenswert?

Johann L. schrieb:
> Also den bereits installierten avr-gcc in den Pfad aufnehmen oder
> ../../sources/avr-libc/trunk/configur --host=avr --prefix=$INSTALL_PATH
> CC=$INSTALL_PATH/bin/avr-gcc

Perfekt! Danke. Jetzt läuft alles rund.

Vielleicht hab ich gestern Nacht mal zwischendurch das Terminal-Fenster 
gewechselt. Eigentlich hatte ich den avr/bin im PATH.

Wie auch immer. Mit CC geht's dann nimmer schief.

von Bernd (Gast)


Lesenswert?

Läuft hier jetzt auch, danke. Das Kompilat ist leider gegenüber dem 
6.3.1 nochmal um 2% gewachsen. :/
Weil wir beim Thema "overhead" sind: Besteht da eigentlich Interesse, 
mal genauer zu erforschen, woran dieses "aus dem Leim" gehen mit jeder 
neuen Version genau liegt? Man könnte ja mal ein paar kleine Programme 
kompilieren und dann vergleichen.

von Nico W. (nico_w)


Lesenswert?

Mein Programm ist 2% kleiner geworden. Etwas ähnliches konnte ich aber 
auch bei dem ersten Einsatz von LTO sehen. Dabei waren die Programme 
alle miteinander Verwandt. Dennoch wurde das eine deutlich kleiner 
während ein anderes größer wurde.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Johann L. schrieb:
1
> e:/winavr/8.0_2017-07-18/bin/../lib/gcc/avr/8.0.0/../../../../avr/bin/ld.exe: 
2
> error: asprintf failed

Für diejenigen, die diesen Fehler auch sehen, hab ich eine neue Version 
"avr-gcc-8.0_2017-07-19_mingw32" hochgeladen, die asprintf durch xmalloc 
+ sprintf ersetzt.

Bernd schrieb:
> Das Kompilat ist leider gegenüber dem 6.3.1 nochmal um 2% gewachsen. :/
> Weil wir beim Thema "overhead" sind: Besteht da eigentlich Interesse,
> mal genauer zu erforschen, woran dieses "aus dem Leim" gehen mit jeder
> neuen Version genau liegt?

Wenn du jemand findest, der sich dafür interessiert...

Das Motto ist ja "wenn man es nicht selbst macht, macht's keiner".  So 
hab ich z.B. wegen des ISR-Overheads und des GAS-Teils in den avr-gcc 
Mailing Listen angefragt, ob jemand den GAS-Teil übernehmen würde. 
Natürlich kamen keine Beiträge zum Thema — schon garnicht fand sich ein 
jemand oder eine jemandin zum Klöppeln des GAS-Teils — sondern nur Tipps 
wie "schreib die ISR in Inline Asm" oder "Instruktionen scannen ist doch 
easy".

Im Endeffekt hab ich mich dann dazu entschieden, selbst dieser jemand zu 
sein.  Und mich in GAS zurechtzufinden und das Zeug runterzuschreiben 
war wahrscheinlich weniger Mühl und schneller getan als einem zu 
erklären, was man da genau braucht und wie das exakt arbeiten soll und 
was nicht funktioniern muss und wo die Haken und Ösen sind usw. 
trallala.

Nicht wenige die hier schreiben, haben wahrscheinlich irgendwo ihre 
eigene Nerd-Ecke, in der sie gerne basteln:  Die einen sind angetreten, 
die Physik aus den Angeln zu heben, andere wollen die Welt und den 
ganzen Rest auf Hex umstellen, und meine Nerd-Spielwiese ist eben 
avr-gcc. Von Assembler bis C++ ist da alles dabei und adäquat, man 
kann sich in Testing oder Profiling vertiefen. Wenn ich was im Simulator 
praktisch finde, bastel ich daran weiter, und neue 
(Optimierungs)-Algorithmen entwerfen und schreiben macht man sonst auch 
eher selten.

Dass Leute avr-gcc beruflich einsetzen und mein Gebastel praktisch 
finden, oder fluchen wenn ich nen Bug eingebaut hab — ist eben so :-)

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.