-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: Optimierungsfrage

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.07.2004
    Ort
    Südhessen
    Beiträge
    1.312

    Optimierungsfrage

    Anzeige

    Hallo,

    ich sehe mir in letzter Zeit gern mal die assemblierten Varianten des C-Codes an und da ist mir eines aufgefallen. Vielleicht weiß jemand, wie man das umgehen kann?

    Ich habe folgendes: Einen globlen (also statischen) Zähler in uint8_t, der mir die Anzahl der bisherigen Interrupts zählt. Ab einer bestimmten Interruptzahl möchte ich Code ausführen. Also kommt logischerweise sowas hier zum Einsatz:
    Code:
    if (++interrrupt_num_10ms == IRQS_PER_10MS) {...}
    Wenn ich das simuliere und analysiere (also den ASM-Code anschaue), kommt dabei viel Code zum Vorschein. Nun habe ich die erste Optimierung über google gefunden: Ich mache diesen globalen Interrupt-Zähler zu einem Register mittels
    Code:
    register uint8_t interrupt_num_10ms asm("r5");
    Wenn ich das jetzt wieder vergleiche, macht er folgendes:
    Code:
    72:           if (++interrupt_num_1ms == IRQS_PER_10MS)
    +0000005C:   2D85        MOV     R24,R5           Copy register
    +0000005D:   3081        CPI     R24,0x01         Compare with immediate
    +0000005E:   F4C9        BRNE    PC+0x1A          Branch if not equal
    D.h. er kopiert erst R5 in sein temporäres Register und vergleicht es dann. Kann man ihm irgendwie sagen, dass er gleich R5 vergleichen soll/kann?

    Grüße,
    Wulfi

  2. #2
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Ich mache diesen globalen Interrupt-Zähler zu einem Register
    Ich würde davon generell abraten. Der Compiler weiß im Allgemeinen schon ganz gut, was er macht. Du bekommst in 99% der Fälle einen insgesamt besseren Code, wenn du dem Compiler völlig freie Hand bei der Registerwahl lässt.

    Kann man ihm irgendwie sagen, dass er gleich R5 vergleichen soll/kann?
    Geht nicht, weil der Befehl CPI nur mit den Registern 16 bis 31 funktioniert. Wie gesagt, der Compiler weiß in der Regel, was er tut.

    Wenn ich das simuliere und analysiere (also den ASM-Code anschaue), kommt dabei viel Code zum Vorschein
    Es wäre interessant, diesen ASM-Code mal zu sehen, dann könnte dir sicher besser geholfen werden.
    MfG
    Stefan

  3. #3
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Nachtrag:
    Bei mir sieht der generierte Code so aus:
    Code:
    if (++count == 10)
      da:	80 91 00 01 	lds	 r24, 0x0100
      de:	8f 5f       	subi	r24, 0xFF	; 255
      e0:	80 93 00 01 	sts	 0x0100, r24
      e4:	8a 30       	cpi	 r24, 0x0A	; 10
      e6:	09 f4       	brne	.+2
    Also optimal. Wenn er bei dir deutlich anders aussieht, dann hast du wahrscheinlich die Compiler-Optimierung nicht aktiviert.
    MfG
    Stefan

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.07.2004
    Ort
    Südhessen
    Beiträge
    1.312
    Nein, Du hast schon recht, es ist nicht ratsam, aber mit ein paar Optimierungen war der Hex-Code nur noch halb so groß... (Das mache ich nur jetzt mal zum Kennenlernen)

    Bei größeren Programmen muss man das mit Vorsicht genießen.
    Aber angenommen, ich finde ein Register zwischen 16 und 31, das der Compiler nicht nutzt, und ich weise es der Variable zu, dann würde er den Vergleich in einem Zuge machen?

  5. #5
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    aber mit ein paar Optimierungen war der Hex-Code nur noch halb so groß
    Dann hast du mit ziemlicher Sicherheit die compilerinterne Optimierung nicht aktiviert. Nicht mal mit handgeschriebenem Assembler könnte man bei dem Code, den der Compiler dann generiert, 50% rausholen.
    MfG
    Stefan

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.07.2004
    Ort
    Südhessen
    Beiträge
    1.312
    Doch, das hatte ich.
    Es war nur ein kleiner Code von ca. 700 Bytes.
    Nachdem ich die globalen Variablen zu Registern verändert hatte und hier und da noch ein paar Optimierungen vornahm, waren es noch 320 Byte.

    Die Optimierung war in beiden Fällen -Os. Ich habe auch die anderen Optimierungen ausprobiert, -Os gab in diesem Fall das beste Ergebnis.

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    20.08.2008
    Ort
    Kandel
    Alter
    29
    Beiträge
    1.220
    Zitat Zitat von thewulf00
    Nein, Du hast schon recht, es ist nicht ratsam, aber mit ein paar Optimierungen war der Hex-Code nur noch halb so groß... (Das mache ich nur jetzt mal zum Kennenlernen)

    Bei größeren Programmen muss man das mit Vorsicht genießen.
    Aber angenommen, ich finde ein Register zwischen 16 und 31, das der Compiler nicht nutzt, und ich weise es der Variable zu, dann würde er den Vergleich in einem Zuge machen?
    Du bekommst noch andere Schwierigkeiten. Afaik "rettet" der Compiler beim Eintritt in eine ISR immer ALLE (auch die in der ISR ungenutzten) Register und stellt sie beim verlassen wieder her.
    Dementsprechend macht es meiner Meinung nach nicht viel Sinn, eine globale Variable in einem Register abzulegen, außer du schreibst Pro- und Epilog für jede zugreifende ISR selbst.

    mfG
    Markus

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    08.07.2004
    Ort
    Südhessen
    Beiträge
    1.312
    Nein, er speichert nur die genutzten und die temporären (R0, R1).
    Siehe hier:
    Code:
    @00000054: __vector_7
    76:       {
    +00000054:   921F        PUSH    R1               Push register on stack
    +00000055:   920F        PUSH    R0               Push register on stack
    +00000056:   B60F        IN      R0,0x3F          In from I/O location
    +00000057:   920F        PUSH    R0               Push register on stack
    +00000058:   2411        CLR     R1               Clear Register
    +00000059:   938F        PUSH    R24              Push register on stack
    81:           if (++interrupt_num_10ms == IRQS_PER_10MS)
    +0000005A:   91800063    LDS     R24,0x0063       Load direct from data space
    +0000005C:   5F8F        SUBI    R24,0xFF         Subtract immediate
    +0000005D:   93800063    STS     0x0063,R24       Store direct to data space
    +0000005F:   3184        CPI     R24,0x14         Compare with immediate
    +00000060:   F559        BRNE    PC+0x2C          Branch if not equal

  9. #9
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Afaik "rettet" der Compiler beim Eintritt in eine ISR immer ALLE (auch die in der ISR ungenutzten) Register und stellt sie beim verlassen wieder her.
    Nein, nur die, die er benutzt. Etwas anders sieht es aus, wenn du in der ISR andere Funktionen aufrufst, dann muss er auch die Call-Clobbered-Register sichern.
    MfG
    Stefan

  10. #10
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    @thewulf00:

    Ist das obige etwa das, was du mit "kommt dabei viel Code zum Vorschein" meintest?
    Also wenn dein Timing so knapp ist, dass es auf 4 Takte mehr oder weniger ankommt, dann schreibe besser die ganze ISR selber in Assembler. Das bringt dir mehr, als mit "register" rumzuspielen.
    MfG
    Stefan

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •