mikrocontroller.net

Forum: Compiler & IDEs Fatale Größenoptimierung


Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab vorhin ein Problem mit der Optimierung in gcc 4.0.1 gefunden. Ich
bin nicht ganz klar, ob man es als Bug in gcc oder in avr-libc werten
soll. Ich habe allerdings gesehen, daß jemand es bereits als Bug bei
der avr-libc gemeldet hat.
Die Auswirkungen sind recht "krass".
Also, folgendes Programm:
#define F_CPU 8000000L

#include <avr/delay.h>
#include <avr/io.h>

int main()
{
    DDRB = 0xff;

    PORTB |= _BV(PB5);

    _delay_ms(10);

    PORTB &= !_BV(PB5);

//    _delay_ms(10);
}

Compiliert und die Codegröße angezeigt:

$ avr-gcc -Os -mmcu=attiny2313 test.c
$ avr-size
   text    data     bss     dec     hex filename
    120       0       0     120      78 a.out

Jetzt ohne den Kommentar:
#define F_CPU 8000000L

#include <avr/delay.h>
#include <avr/io.h>

int main()
{
    DDRB = 0xff;

    PORTB |= _BV(PB5);

    _delay_ms(10);

    PORTB &= !_BV(PB5);

    _delay_ms(10);
}

$ avr-gcc -Os -mmcu=attiny2313 test.c
$ avr-size
   text    data     bss     dec     hex filename
   3610       8       0    3618     e22 a.out

Das Programm ist auf einmal bei weitem zu groß für den Flash-Speicher.

Ich hab mittlerweile rausgefunden, wo der Grund liegt:
Die delay-Funktion ist als _inline_ markiert, welches aber vom
Compiler bei -Os nur dann berücksichtigt wird, wenn die Funktion nur
einmal aufgerufen wird. Bei mehreren Aufrufen versucht er, Platz zu
sparen, indem er das Inlining nicht durchführt. Dadurch können aber die
in der Funktion eingebauten Fließkomma-Operationen nicht mehr im
Compiler, sondern muß zur Laufzeit durchgeführt werden. Deshalb muß
massenweise Code für die Fießkomma-Berechnung gelinkt werden.

Das ist die mit Abstand schlechteste Größen-"Optimierung", die ich je
gesehen hab.

Das Problem kann man lösen, indem man nicht auf Größe optimiert, denn
bei -O3 wird das Inlining immer gemacht.
Alternativ kann man in avr/delay.h alle Vorkommen von _inline_ durch
__attribute__((always_inline)) ersetzen.

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

Bewertung
0 lesenswert
nicht lesenswert
Nu, was beklagst du dich noch so auführlich, wenn es doch schon
jemand penibel analysiert und als Bug eingereicht hat?  Das Problem
ist doch offensichtlich, und der arme Compiler kann auch nichts
wirklich dafür.  Woher soll der auch wissen, dass wir uns eigentlich
auf sein inlining für zur Compilezeit bekannte Gleitkommausdrücke
verlassen möchten und dass die Gleitkommaoperationen für uns
dermaßen schweineteuer sind?

Der Bug ist ausschließlich in der Bibliothek zu suchen, und genau
dort ist ja auch der Bugreport gelandet.  Die Auflösung hast du ja
gleich mitgepostet (und nein, -O3 ist im Allgemeinen eine sehr
schlechte Idee, eben weil dann aller Mist inline reingepackt wird).

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Nu, was beklagst du dich noch so auführlich, wenn es doch schon
> jemand penibel analysiert und als Bug eingereicht hat?

Es ist eher als Information gedacht, damit andere, die evtl. auf so ein
Problem stoßen, durch das Posting Hilfe bekommen. Letztendlich das ja
bei jeder Funktion passieren, deren Programmierer darauf vertraut, daß
so eine Berechnung zur Compilezeit durchgeführt wird, und nicht nur bei
den delays.

>  Das Problem ist doch offensichtlich, und der arme Compiler kann
> auch nichts wirklich dafür.  Woher soll der auch wissen, dass wir
> uns eigentlich auf sein inlining für zur Compilezeit bekannte
> Gleitkommausdrücke verlassen möchten und dass die
> Gleitkommaoperationen für uns dermaßen schweineteuer sind?

Der "arme Compiler" sollte, wenn man ihm sagt, daß man möglichst
kleinen Code haben will, eigentlich schon merken, daß sein Verzicht auf
Inlining den Code statt dessen wesentlich größer machen würde. Er müßte
ja nur wissen, daß das Vorhandensein  von
Laufzeit-Fließkommaberechnungen für eine Explosion der Codegröße
sorgt.
Andererseits ist es vermutlich einfacher, wenn der Programmierer einer
Funktion das __attribute__((always_inline)) verwendet, um damit das
Inlining zu erzwingen, wo das für optimalen Code wichtig ist.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann durchaus zur Compilezeit in float rechnen, ohne daß es Code
kostet.

Man muß bloß darauf achten, ehe man was mit dem Ausdruck anfängt,
diesen nach einem Ganzzahlformat zu casten, z.B.: (unsigned
short)(blabla / 0.123)


Peter

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.