PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : CodeOptimierungen durch AVR-GCC Attribute



DerMaddin
18.03.2008, 20:20
Hi,

ich versuche seit einer Weile, die Compilerattribute des GCC zu nutzen um den Code efizienter zu compilieren. Im Artikel "AVR-GCC Internals" sind die einzelnen Attribute beschrieben. Beim Übersetzen mit und ohne dieser Attribute stelle ich jedoch keine Veränderung im .hex file fest. Ich habe etliche Funktionen, die zB keine globalen Variablen lesen oder schreiben und deshalb mit
__attribute__((const))
versehen werden können.

Was mache ich falsch? Wieso ändert sich das Compilat nicht?

Danke!!

Hubert.G
19.03.2008, 11:41
Den Optimierungsgrad stelle ich im makefile ein, bei mir sieht das so aus:
# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = 2

Im Programm selbst muss man nichts vorsehen, ausser darauf zu achten das nicht zuviel wegoptimiert wird.

DerMaddin
19.03.2008, 13:41
Sorry, ich hab eindeutig zu wenig geschrieben:

Ich hab auch den Optimierungsgrad 2 eingeschaltet. Ich starte den GCC mithilfe eines Batches vom Visual Studio aus (Anleitung im Wiki unter "Microsoft Visual Studio als Buildumgebung..." (oder so ähnlich)).
Also Optimierung 2 ist immer an, aber bei den avr-gcc internals steht, dass zB ein "noreturn" vor einer Funktion, die nicht zurückkehrt zusätzliche Optimierungen bewirken.
...
Diese Optimierungen bleiben bei mir aus.
Also sehe ich zwei Möglichkeiten: Ich habe Code, der so perfekt ist, dass man ihn nicht besser machen kann (... unwahrscheinlich) oder ich hab irgendeine Einstellung beim GCC vergessen (und wüßte gern, welche das ist)

Mfg, Martin

SprinterSB
19.03.2008, 23:42
Welche Optimierung hättest du denn erwartet?

Mit dem Attribut kann man Funktionen kennzeichnen, die nur von ihren Argumenten abhängen. Dazu gehört, daß sie keine globale/statische Variable schreibt oder liest (falls sie nicht konstant ist), und keine Zeiger dereferenziert (der zeiger mag konstant sein, aber nicht das, worauf er zeigt,...). Zudem darf die Funktion keine andere Funktion aufrufen, die nicht auch CONST ist.

Ein Beispiel für so ne Funktion ist sin(). sin(x) hat immer den selben Wert, wenn x den selben Wert hat. sin() ist also eine Funktion im mathematischen Sinne. Wenn mehrfach in der Quelle sin(x) gebraucht wird, und der gcc nachweisen kann, daß x jeweils den gleichen Wert hat (damit der das kann, müssen auch einige Voraussetzungen erfüllt sein), kann er das Ergebnis der Berechnung wiederverwenden, falls er das als günstig erachtet.

const hat also keine Wirkung auf den Callee (aufgerufene Func), sondern bestenfalls auf den Caller (Aufrufer).

Ein inkorrekt angegebenes const lässt gcc inkorrekte Annahmen über die Quelle machen und kann zu fehlerhaftem Code führen.

Die Frage ist auch, was (und auch warum) du optimieren willst:
-- Programmspeicher
-- Datenspeicher
-- Laufzeit
-- Entwicklungszeit
-- Wartbarkeit
-- Portabilität

Wo was zu holen ist, sieht man am besten, wenn man nen Blick auf C-Quelle und s-File wirft.

DerMaddin
20.03.2008, 13:56
Naja, ich hätte erwartet, dass bei meiner Reset Funktion (die einen WatchDog-Reset auslöst) durch das Attribut noreturn die Codegröße abnimmt da die StackParameter nicht mehr gepoppt werden müssen und der Compiler das wegoptimieren könnte.
Ein anderes Beispiel sind Funktionen wie GetADCValuie(), die einfach nur einen Analogwert umwandelt und zurück gibt. Die wollte ich mit dem attribut static versehen, da in keiner Weise mit globalen Variablen zusammenhängt. Aber das Attribut hat nichts an der Codegröße geändert.
...

warum?

Mfg, Maddin

SprinterSB
23.03.2008, 22:18
Das kann einige Gründe haben.

Wenn deine reset-Func nicht returnt, muss gcc das in dem Modul wissem, das die reset-Func verwendet. Am besten attribuiert man also am Prototyp im Header:


// reset.h
extern void __attribute__((noreturn)) reset(void);




// foo.c
#include "reset.h"
...
reset();
...


statische Funktionen, die nur 1x verwendet werden, werden von gcc idR geinline, falls kein f-pointer genommen wird und man optimieren lässt.

Ansonsten kann es günstiger sein, die Func nicht zu inlinen. Wenn der Code sehr kurz ist, kann man dem Compiler helfen, indem man "inline" sagt oder __attribute__((always_inline))

Für Funktionen, die extern inline sind, muss gcc dennoch Code erzeugen, weil er nicht wissen kann, ob die Funk extern aufgerufen wird.

In diesem Falle sollte die Funktion also static inline sein. Um sie in mehreren Modulen verwenden zu können, definiert man sie also im Header


// acd.h
#ifndef _ADC_H_
...
static inline void getADC()
{
blah
}
...


Beachte, daß trotz Inlining ein C-Compiler Argumente und Return-Werte promoten muss (C-Spec). Falls das stört (die Werte sind dann immer 16-Bit, auch wenn man sie als 8-Bit Werte deklariert hat) kommt man nur über ein Makro drumrum, weil das keine Argumente im Sinne von C hat.

Als Optimierungsstufe find ich -Os übrigens besser als -O2. Vielleicht bringt das schon nen Codegewinn?