Fatale Größenoptimierung

Gast #237971
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:
1
#define F_CPU 8000000L
2

3
#include <avr/delay.h>
4
#include <avr/io.h>
5

6
int main()
7
{
8
    DDRB = 0xff;
9

10
    PORTB |= _BV(PB5);
11

12
    _delay_ms(10);
13

14
    PORTB &= !_BV(PB5);
15

16
//    _delay_ms(10);
17
}

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:
1
#define F_CPU 8000000L
2

3
#include <avr/delay.h>
4
#include <avr/io.h>
5

6
int main()
7
{
8
    DDRB = 0xff;
9

10
    PORTB |= _BV(PB5);
11

12
    _delay_ms(10);
13

14
    PORTB &= !_BV(PB5);
15

16
    _delay_ms(10);
17
}

$ 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.
Moderator Persönliche Seite #237972
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).
Gast #237973
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.
Gast #237974
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

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.