AVR Inline-Optimierung

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

AVR Inline-Optimierung

Beitragvon Mathias » 28. Okt 2017, 16:49 AVR Inline-Optimierung

Wen ich folgenden Test mache, verbraucht ein Aufruf einer Inline-Procedure mehr Speicher als wen man dies selbst direkt reinschreibt.
Code: Alles auswählen
  procedure sei; assembler; inline;
  asm
           Sei
  end;


Code: Alles auswählen
begin
  Sei;  // Braucht 8 Byte
  asm cli end; // Braucht 2 Byte;
end.

Ich dachte immer, wen man eine Procedure, vor allem eine mit assembler, werde direkt in den Haupt-Code kompiliert.

Somit empfiehlt es sich, es selbst direkt in den Code zu schreiben, vor allem bei so was einfachen wie cli und sei.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 18:45 Re: AVR Inline-Optimierung

Auch hier wieder der Verweis auf die *.s-Dateien.

Code: Alles auswählen
.section .text.n_gh_init_ss_cli
.globl   GH_INIT_ss_CLI
GH_INIT_ss_CLI:
   cli
   ret
.Le0:
   .size   GH_INIT_ss_CLI, .Le0 - GH_INIT_ss_CLI
 
.section .text.n_gh_init_ss_sei
.globl   GH_INIT_ss_SEI
GH_INIT_ss_SEI:
   sei
   ret
.Le1:
   .size   GH_INIT_ss_SEI, .Le1 - GH_INIT_ss_SEI


Ja, die Prozeduren werden als solche abgelegt und mit call und return abgerufen. Was auch noch den Nachteil hat, dass sie 7 zusätzliche Takte für Einsprung und Rückkehr benötigen.

Direktes Schreiben des Inline-Assemblers in andere Prozeduren kann aber auch den Nachteil haben, dass der Compiler einen Haufen Register- und Stackpointersicherung extra betreibt und die Prozedur aufbläht. Trifft bei Dir nicht zu, weil da nichts drumrum ist, was er sichern müsste.

Ich bin da noch nicht ganz dahintergestiegen, wann was günstiger ist.
Timm Thaler
 
Beiträge: 733
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 28. Okt 2017, 18:51 Re: AVR Inline-Optimierung

Auch hier wieder der Verweis auf die *.s-Dateien.
Woher nehmen und nicht stehlen.
Hier ./lib/avr-embedded kann ich keine finden, dort hat es nur 2 Dateien.

./lib/avr-embedded/Project1.compiled
./lib/avr-embedded/Project1.o

Ich bin da noch nicht ganz dahintergestiegen, wann was günstiger ist.
Könnte sein, das der AVR-Compiler noch stark in der Beta ist ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 22:12 Re: AVR Inline-Optimierung

Bei den benutzerdefinierten Compilereinstellungen
-Cpavr5
-Wpatmega328p
-al
stehen?
Timm Thaler
 
Beiträge: 733
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon kupferstecher » 29. Okt 2017, 10:37 Re: AVR Inline-Optimierung

Nach meiner Beobachtung funktioniert "inline" nur bei normalen Routinen und nicht bei Assembler-Routinen. Ist vermutlich einfach nicht implementiert.

Cli und Sei sind zwar wichtig, aber die paar Takte extra dürften kaum kritisch sein.
kupferstecher
 
Beiträge: 169
Registriert: 17. Nov 2016, 11:52

Beitragvon Mathias » 29. Okt 2017, 16:44 Re: AVR Inline-Optimierung

Timm Thaler hat geschrieben:Bei den benutzerdefinierten Compilereinstellungen
-Cpavr5
-Wpatmega328p
-al
stehen?

Dank dem -al gibt es eine *.s .

Für was hast du noch den Parameter -Cpavr5 eingetragen ?
Ich habe/hatte bei mir nur -Wpatmega328p.

Das mit dem -al werde ich noch im Tutorial erste Schritte ergänzen, ich denke dies ist recht nützlich.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 29. Okt 2017, 17:32 Re: AVR Inline-Optimierung

Wenn Du rechts daneben auf "Alle Einstellungen" klickst, bekommst Du ein Fenster, was da alles einstellbar ist.

a heisst, dass Assembler-File (die *.s) wird nicht gelöscht. al heisst, die Zeilenzahlen aus dem Sourcecode stehen im Assemblerfile, das hilf die Stelle schneller zu finden.
Timm Thaler
 
Beiträge: 733
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 29. Okt 2017, 17:41 Re: AVR Inline-Optimierung

Ich habe mal versucht, für ATtiny dem Parameter -Cpavr25 und -WpATTINY2313A einzutragen.
Dies bringt nicht, wen der Cross-Compiler mit 5 kompiliert wurde.
Ich dachte schon, man könnte sich die Umkomplierung mit fpcupdelux sparen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 17. Feb 2018, 06:45 Re: AVR Inline-Optimierung

Mathias hat geschrieben:Somit empfiehlt es sich, es selbst direkt in den Code zu schreiben, vor allem bei so was einfachen wie cli und sei.


Lösung ohne Prozeduraufruf oder Inline-Assembler:

Code: Alles auswählen
avr_cli;
avr_sei;


Die Unit intrinsics muss eingebunden werden. cli und sei werden dann direkt eingefügt.
Timm Thaler
 
Beiträge: 733
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon FPK » 17. Feb 2018, 11:07 Re: AVR Inline-Optimierung

kupferstecher hat geschrieben:Nach meiner Beobachtung funktioniert "inline" nur bei normalen Routinen und nicht bei Assembler-Routinen. Ist vermutlich einfach nicht implementiert.


Ist auch extrem schwierig bis gar nicht zu implementieren, denn das würde heissen, dass der Compiler "verstehen" muss, was in der Assembler-Routine passiert.
FPK
 
Beiträge: 50
Registriert: 21. Mai 2008, 18:38
Wohnort: Erlangen

Beitragvon Mathias » 17. Feb 2018, 17:41 Re: AVR Inline-Optimierung

Die Unit intrinsics muss eingebunden werden. cli und sei werden dann direkt eingefügt.

Da hast du etwas sehr interessantes entdeckt, das macht die AVR-Programmierung wider etwas einfacher. :wink:

Bitte teile solche Sachen im Forum mit, dann hat man die Möglichkeit das Wiki auch zu ergänzen. :wink:
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon kupferstecher » 18. Feb 2018, 11:09 Re: AVR Inline-Optimierung

FPK hat geschrieben:Ist auch extrem schwierig bis gar nicht zu implementieren, denn das würde heissen, dass der Compiler "verstehen" muss, was in der Assembler-Routine passiert.

Kannst du genauer was dazu schreiben, warum muss der Compiler die Assembler-Routine verstehen? Ich würde ja keine Optimierungen vom Compiler auf Assemblerebene erwarten, er soll nur den gesamten Assemblerblock in den aufrufenden Code packen, einfach, um sich den Call zu sparen. Dem Compiler sind sogar die verwendeten Register bekannt, es könnten je nach Anwendung auch noch Stackoperationen eingespart werden. Selbst Variablenaufrufe sollten dem Compiler bekannt sein, damit könnten Werte in Registern gehalten werden (vermutlich aufwendiger).

An anderer Stelle habe ich gelesen, dass man Inlineassembler in Asm-Funktionen packen sollte, da Funktionen mit versprengten Assemblerblöcken nicht oder schlecht optimiert werden würden. Vermutlich hängen beide Themen zusammen?
kupferstecher
 
Beiträge: 169
Registriert: 17. Nov 2016, 11:52

Beitragvon FPK » 18. Feb 2018, 13:42 Re: AVR Inline-Optimierung

kupferstecher hat geschrieben:
FPK hat geschrieben:Ist auch extrem schwierig bis gar nicht zu implementieren, denn das würde heissen, dass der Compiler "verstehen" muss, was in der Assembler-Routine passiert.

Kannst du genauer was dazu schreiben, warum muss der Compiler die Assembler-Routine verstehen? Ich würde ja keine Optimierungen vom Compiler auf Assemblerebene erwarten, er soll nur den gesamten Assemblerblock in den aufrufenden Code packen, einfach, um sich den Call zu sparen. Dem Compiler sind sogar die verwendeten Register bekannt, es könnten je nach Anwendung auch noch Stackoperationen eingespart werden. Selbst Variablenaufrufe sollten dem Compiler bekannt sein, damit könnten Werte in Registern gehalten werden (vermutlich aufwendiger).


Registernutzung ist eine Sache, die man vielleicht in den Griff kriegt. Aber man kann eben in Assembler unendlich Gemeinheiten schreiben, die den Compiler bzw. den Optimierer aus dem Tritt bringen, angefangen bei Aliasing oder unerwarteten Stackmanipulationen. Klar kann man zig Regeln aufstellen, wie eine inlinebare Assemblerfunktion auszusehen hat, aber da öffnet man eine Büchse der Pandora. Ich bin deswegen auch der Meinung: der Nutzer einer Entwicklungssystem darf kein Assembler benötigen, falls doch, ist was am Compiler/der Sprache falsch (natürlich sollte auch die Laufzeitbibliothek so wenig wie möglich Assembler enthalten, leider kommt man da manchmal nicht drumherum).

An anderer Stelle habe ich gelesen, dass man Inlineassembler in Asm-Funktionen packen sollte, da Funktionen mit versprengten Assemblerblöcken nicht oder schlecht optimiert werden würden. Vermutlich hängen beide Themen zusammen?


Ja.
FPK
 
Beiträge: 50
Registriert: 21. Mai 2008, 18:38
Wohnort: Erlangen

Beitragvon Timm Thaler » 18. Feb 2018, 20:28 Re: AVR Inline-Optimierung

FPK hat geschrieben:Ich bin deswegen auch der Meinung: der Nutzer einer Entwicklungssystem darf kein Assembler benötigen, falls doch, ist was am Compiler/der Sprache falsch.


Am PC möchte ich auch nicht (mehr) mit Assembler rumfummeln. Allerdings konnte man nur so in Turbo-Pascal einen Grafikbildschirm mehr als 16 Farben bekommen. ;-)

Allerdings geht es hier um Mikrocontroller, und da musst Du mitunter selbst am gut abgehangenen GCC mit Asm arbeiten.

Und der Pascal-Compiler macht mitunter absolut komische Sachen. Einmal den Datentyp von Unsigned auf Signed gewechselt, und Du bekommst statt einer wenige µsec dauernden Hardware-Multiplikation (in 16bit) eine Software-Multiplikation mit 100-facher Dauer hingeklatscht.

Code: Alles auswählen
# [39] c_u32 := a_u16 * b_u16;
   lds   r18,(U_sMT_MATH_ss_A_U16)
   lds   r19,(U_sMT_MATH_ss_A_U16+1)
   lds   r22,(U_sMT_MATH_ss_B_U16)
   lds   r23,(U_sMT_MATH_ss_B_U16+1)
   mul   r18,r22
   movw   r20,r0
   mul   r19,r22
   add   r21,r0
   mul   r18,r23
   add   r21,r0
   clr   r1
   mov   r18,r1
   mov   r19,r1
   sts   (U_sMT_MATH_ss_C_U32),r20
   sts   (U_sMT_MATH_ss_C_U32+1),r21
   sts   (U_sMT_MATH_ss_C_U32+2),r18
   sts   (U_sMT_MATH_ss_C_U32+3),r19
# [40] c_i32 := a_u16 * b_i16;
   lds   r18,(U_sMT_MATH_ss_B_I16)
   lds   r19,(U_sMT_MATH_ss_B_I16+1)
   mov   r20,r1
   sbrc   r19,7
   com   r20
   mov   r21,r20
   lds   r22,(U_sMT_MATH_ss_A_U16)
   lds   r23,(U_sMT_MATH_ss_A_U16+1)
   mov   r24,r1
   mov   r25,r1
   call   fpc_mul_longint
   sts   (U_sMT_MATH_ss_C_I32),r22
   sts   (U_sMT_MATH_ss_C_I32+1),r23
   sts   (U_sMT_MATH_ss_C_I32+2),r24
   sts   (U_sMT_MATH_ss_C_I32+3),r25


Es ist ja richtig, dass die obere Mul nur 16 Bit liefert, Überlauf wird einfach abgeschnitten, während die untere echte 32 Bit hat. Aber es ist für den Programmierer nicht ersichtlich, warum der Compiler mal so und mal so entscheidet.

Oder Divison / 256. Immerhin erkennt der Compiler, dass er keine Software-Division aufrufen muss. Allerdings macht er dann ein Shift über 8 Bits draus. Dabei muss er nur ein paar Bytes umsortieren.

Auch sehr beliebt, Werte erstmal in ein Register laden, um sie dann in ein anderes Register umzuladen, mit dem gerechnet wird.

Wenn es dann schnell gehen soll, muss man einfach von Hand ran.
Timm Thaler
 
Beiträge: 733
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon FPK » 18. Feb 2018, 21:14 Re: AVR Inline-Optimierung

Timm Thaler hat geschrieben:
FPK hat geschrieben:Ich bin deswegen auch der Meinung: der Nutzer einer Entwicklungssystem darf kein Assembler benötigen, falls doch, ist was am Compiler/der Sprache falsch.


Und der Pascal-Compiler macht mitunter absolut komische Sachen. Einmal den Datentyp von Unsigned auf Signed gewechselt, und Du bekommst statt einer wenige µsec dauernden Hardware-Multiplikation (in 16bit) eine Software-Multiplikation mit 100-facher Dauer hingeklatscht.

Es ist ja richtig, dass die obere Mul nur 16 Bit liefert, Überlauf wird einfach abgeschnitten, während die untere echte 32 Bit hat. Aber es ist für den Programmierer nicht ersichtlich, warum der Compiler mal so und mal so entscheidet.


Dann solltest Du Dich mal mit den Typkonvertierungsregeln in (Free) Pascal beschäftigen, das ist relativ fundamental und sollte jedem Programmierer bewusst sein. Kurzform: Der Typ des Ergebnisses einer Operation hängt immer von den Typen der Operanden ab, bei arithmetischen Operationen gilt eigentlich immer, dass der Typ gewählt wird, in den beiden Operanden passen, bei word*word ist das eben word, bei word*integer ist das longint. Damit ist klar, dass word*integer eine 32 Bit Operation verursacht. An was Du das Ergebnis zuweisst, spielt semantisch keine Rolle, der Compiler kann natürlich versuchen, bei entsprechenden Randbedingungen eine aufwendige Operation zu vermeiden und integer*word doch nur mit 16 Bit rechnen lassen.

Oder Divison / 256. Immerhin erkennt der Compiler, dass er keine Software-Division aufrufen muss. Allerdings macht er dann ein Shift über 8 Bits draus. Dabei muss er nur ein paar Bytes umsortieren.


Stimmt für trunk jedenfalls nicht mehr:

Code: Alles auswählen
 
PsPROGRAM_ss_DIVIDE256sWORDssWORD:
# Var $result located in register r18
# [tdiv.pp]
# [6] begin
   mov   r24,r25
# Var w located in register r24
# [7] result:=w div 256;
   mov   r25,r1
# Var $result located in register r24
# [8] end;
   ret
 


Auch sehr beliebt, Werte erstmal in ein Register laden, um sie dann in ein anderes Register umzuladen, mit dem gerechnet wird.


Sowas lässt sich oft im Compiler beheben, wenn konkreter Code vorliegt.

Wenn es dann schnell gehen soll, muss man einfach von Hand ran.


Gibt wenige Beispiele wo das gilt, die oben jedenfalls nicht :) Wenn irgendwo komischer Code erzeugt wird, Bugreport erstellen, lässt sich dann meist lösen, da profitieren dann alle Programme davon.
FPK
 
Beiträge: 50
Registriert: 21. Mai 2008, 18:38
Wohnort: Erlangen

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste

porpoises-institution
accuracy-worried