www.mikrocontroller.net

Forum: Compiler & IDEs Optimizer Bug mit (-O3) bei WinAVR-20090313


Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vermutlich handelt es sich nicht wirklich um einen Bug, aber dennoch um 
einen sehr sonderbaren Effekt: Mit Optimierung -O3 kann der erzeugte 
Code riesengross werden, bzw. wesentlich grösser als ohne Optimierung!

Bei einem kleinem Testprogramm:

-O0  574 Bytes
-O1  392 Bytes
-O2  390 Bytes
-O3 4850 Bytes!
-Os  386 Bytes

Woran kann das liegen?

Test-Programm
#include <stdlib.h>
#include <avr/io.h>

unsigned int root(unsigned long a)  //Calculate Square-root
{
  unsigned long rem = 0;
  unsigned long root = 0;
  for (int i=0; i<16; i++)
  {
    root <<= 1;
    rem = ((rem << 2) + (a >> 30));
    a <<= 2;
    root++;
    if (root <= rem)
    {
      rem -= root;
      root++;
    }
    else
    {
      root--;
    }
  }
  return (unsigned int)(root >> 1);
}

int main(void)
{
  volatile unsigned int result;
  for(unsigned int i=0; i<(0xffff); i=i+1)
  {
    result = root(i);
  }
}

Compiler-Output
**** Build of configuration Release for project Test ****

make all 
Building file: ../main.c
Invoking: AVR Compiler
avr-gcc -Wall -O3 -fpack-struct -fshort-enums -std=gnu99 -funsigned-char -funsigned-bitfields 
        -mmcu=atmega16 -DF_CPU=1000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c"
Finished building: ../main.c
 
Building target: Test.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,Test.map -mmcu=atmega16 -o"Test.elf"  ./main.o   
Finished building target: Test.elf
 
Invoking: AVR Create Extended Listing
avr-objdump -h -S Test.elf  >"Test.lss"
Finished building: Test.lss
 
Create Flash image (ihex format)
avr-objcopy -R .eeprom -O ihex Test.elf  "Test.hex"
Finished building: Test.hex
 
Create eeprom image (ihex format)
avr-objcopy -j .eeprom --no-change-warnings --change-section-lma .eeprom=0 -O ihex Test.elf  "Test.eep"
Finished building: Test.eep
 
Invoking: Print Size
avr-size --format=avr --mcu=atmega16 Test.elf
AVR Memory Usage
----------------
Device: atmega16

Program:    4850 bytes (29.6% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

Finished building: sizedummy

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
> Vermutlich handelt es sich nicht wirklich um einen Bug, aber dennoch um
> einen sehr sonderbaren Effekt: Mit Optimierung -O3 kann der erzeugte
> Code riesengross werden, bzw. wesentlich grösser als ohne Optimierung!

Ja, -O3 ist letztlich sowas wie ``optimize for speed''.  Da werden
Schleifen entrollt, Funktionen inline expandiert etc. pp. was das
Zeug hält.

Autor: Kai G. (runtimeterror)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was sagt denn das Assembler-Listing?

Wenn O3 eine Geschwindigkeitsoptimierung ist (kenne die 
Compiler-Optionen nicht gut), tippe ich auf ein partielles 
loop-unrolling im main-Programm

http://de.wikipedia.org/wiki/Hotspot-Optimierung#L...

Einfach ein Schuss ins Blaue.

Schöne Grüße,
Kai

Autor: Peter S. (psavr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okey, das wirds wohl sein. Somit macht -O3 bi kleinen uC wie den AVR 
kaum Sinn....

Autor: Fabian B. (fabs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das würde ich gernerell so nicht unterschreiben. Wenn dein Prog extrem 
zeitkritisch ist, könnten dir genau das den erhofften Erfolg bringen, 
dein Controller hätte ja genug Flash. ;-)

Aber im Allgemeinen funktioniert O2 eigentlich am besten (meine 
Erfahrung)

Gruß
Fabian

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jo, -O123 sind normalerweise für Geschwindigkeit, -Os für Programmgröße.

Wenn noch Programmspeicher übrig ist, ruhig mal die höchste 
Optimierungsstufe ausprobieren (trotzdem sauber programmieren!) -- 
ungenutzten Flash-Speicher kann man nämlich in der Regel nicht mehr im 
Geschäft zurückgeben oder umtauschen...

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jede Optimierung kann nach hinten los gehen.

Ob eine Optimierung wirklich diesen Namen verdient, ist immer auch 
abhängig von der Zielarchitektur.

Einfach mal bedenken, daß die Voreinstellungen der aktivierten 
Optimierungsstrategien in avr-gcc die gleichen sind wie für 32- und 
64-Bit Systeme auch!

Und da AVR nun mal weder Date- noch Codecache hat, keine Pipeline 
(zumindest ist die Dauer von Befehlsausführungen unabhängig von deren 
Anordnung), Sprünge recht billig sind, manche Arithmetik jedoch 
vergleichsweise teuer (zB a << n, a/b, a%b) passt das eben bei weitem 
nicht immer. Nur daß der Code reisengroß wird, heisst nicht, daß er 
schneller wird ;-)

Es vergrößern sich zum Beispiel Sprungweiten. Während in kompaktem Code 
oft ein relativer, Sprung genommen werden kann, muss bei ausladendem 
Code die Bedingung umgedreht werden (kostet nix), und über einen 
absoluten Sprung gesprungen werden, welcher das eigentliche Sprungziel 
adressiert. Das ist langsamer und breiter. Wenn eine aufgerolle Schleife 
dann zig solcher Konstrukte enthält (Schleifenbedingung, break, ...), 
schiesst sich die Optimierung selbst ins Knie...

Unangenehm ist auch, daß viele Optimierungen die Lebensdauer von 
Registern erhöhen (zB loop invariant motion etc). Das macht den Code 
theoretisch schneller, aber wenn die Register ausgehen und stattdessen 
die Werte zum RAM hin- und hergeschaufelt werden müssen, ist der Code 
deutlich größer und merklich langsamer. Der Effekt lässt sich hin und 
wieder auch bei Inlining beobachten.

Um Gefühl defür zu bekommen, welche Optimierung geeignet ist, hilft nur 
eins: Hin und wieder muss man sich die Compilerausgabe anschauen.

Irgendwann hat man dann raus, was in 90% der Fälle gut taugt. -O3 gehört 
für avr-gcc aber sehr wahrscheinlich nicht dazu.

Die einzigen Änderungen, die avr-gcc an den Optionen vornimmt, sind
flag_delete_null_pointer_checks = 0;

if (!PARAM_SET_P (PARAM_INLINE_CALL_COST))
  set_param_value ("inline-call-cost", 5);
was dem Effekt entspricht von
-fno-delete-null-pointer-checks  --param inline-call-cost=5 ; anstatt 12

Johann

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:
> Jo, -O123 sind normalerweise für Geschwindigkeit, -Os für Programmgröße.

Wobei das mit der Geschwindigkeit beim AVR schnell nach hinten losgehen 
kann, -Os ist oft auch am schnellsten.

Außerdem arbeiten die Optimierungen mit der Brechstange, d.h. es wird 
alles gleich optimiert, egal, ob alle 10 Tage aufgerufen oder alle 10µs.
Man kann also leicht Verzehnfachung des Codes erreichen bei 0% 
Geschwindigkeitszuwachs.

Andere Optimierungen neben -Os würden nur Sinn machen, wenn man sie 
selektiv anwenden könnte (im Sourcecode auf einzelnen Funktionen).


Peter

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Wobei das mit der Geschwindigkeit beim AVR schnell nach hinten losgehen
> kann, -Os ist oft auch am schnellsten.

Würd ich auch empfehlen als Grundlage.

> Andere Optimierungen neben -Os würden nur Sinn machen, wenn man sie
> selektiv anwenden könnte (im Sourcecode auf einzelnen Funktionen).

Das geht ab 4.4.0 per
#pragma GCC optimize ...
__attribute__((__optimize__ ...))
http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Functi...

Johann

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Sven P. schrieb:
>> Jo, -O123 sind normalerweise für Geschwindigkeit, -Os für Programmgröße.
>
> Wobei das mit der Geschwindigkeit beim AVR schnell nach hinten losgehen
> kann, -Os ist oft auch am schnellsten.
Klar.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Außerdem arbeiten die Optimierungen mit der Brechstange, d.h. es wird
> alles gleich optimiert, egal, ob alle 10 Tage aufgerufen oder alle 10µs.

Nicht grundsätzlich, GCC kann Laufzeitergebnisse des Profilers gprof bei 
der Optimierung berücksichtigen. Nur leider gibt's gprof nicht für den 
AVR. Wäre ein lustiges Projekt etwas ähnliches für den AVR zu 
implementieren, ob's bei der Optimierung viel bringt sei mal 
dahingestellt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.