Forum: Compiler & IDEs Fatale Größenoptimierung


von Rolf Magnus (Gast)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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).

von Rolf Magnus (Gast)


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.

von peter dannegger (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.