mikrocontroller.net

Forum: Compiler & IDEs Programmgröße optimieren, globale Variablen in struct?


Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich versuche gerade die Programmgröße eines größeren Projektes zu 
optimieren, dessen Umfang langsam an die Grenze des Mega8 kommt.

Ich habe mir die application note AVR035: Efficient C Coding for AVR 
http://www.atmel.com/dyn/resources/prod_documents/... 
durchgelesen und dort heißt es unter Anderem: "Collect non-local data in 
structures whenever natural. This increases the possibility
of indirect addressing without pointer reload."

was mir nicht ganz klar ist: gilt das nur für einzelne Variablen, wie 
z.B. Flags oder Zähler, oder macht es auch Sinn größere Speicherbereiche 
in structs zu packen?

Ich habe testweise Datenbereiche, die global liegen müssen in eine 
struct gepackt, das Ergebnis war, dass der code deutlich größer 
(~400Byte) war als vorher. Das sah in etwa so aus:
//global in einer header datei
typedef struct{
unsigned char var1[32];
unsigned char var2[64];
}daten;

daten a;

//irgendwo
a.var1[3] = 134;
/usw...
Wieso wird hier plötzlich soviel mehr Code erzeugt? Habe ich etwas 
übersehen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ben wrote:
>
> Ich habe testweise Datenbereiche, die global liegen müssen in eine
> struct gepackt, das Ergebnis war, dass der code deutlich größer
> (~400Byte) war als vorher. Das sah in etwa so aus:
>
> //global in einer header datei
> typedef struct{
> unsigned char var1[32];
> unsigned char var2[64];
> }daten;
> 
> daten a;
> 
> //irgendwo
> a.var1[3] = 134;
> /usw...
> 

Das wird dir nichgt viel bringen (wenn überhaupt)

Wovon die Appnote spricht, ist sowas:

Anstelle von
uint8_t day;
uint8_t month;
uint8_t year;

wird vorgeschlagen, das so zu machen
struct date
{
  uint8_t day;
  uint8_t month;
  uint8_t year;
};

struct date d;

Die angegebene Begründung folgt folgender Idee:
Wenn du ein Datum verändern muss, dann müssen nacheinander
day, month, year aus dem Speicher geladen (oder geschrieben)
werden. Dazu muss aber die Speicheradresse gebildet werden,
damit mit einem Load bzw. Store darauf zugegriffen werden
kann. Da es sich um 3 getrennte Variablen handelt, wird die
Adresse mglw. 3 mal in einem Register zusammengebaut um die
Operation über die Bühne gehen zu lassen.
In der Strukturvariante hingegen, genügt es die Speicheradresse
nur einmal zu bestimmen um dann alle 3 Operationen relativ
zu dieser Adresse durchzuführen.

Ob dieses Argument heute noch zieht: Keine Ahnung. Schreib
so, wie es dir am Natürlichsten vorkommt. Wenn einzelne Variablen
logisch zusammengehören, so wie im obigen Beispiel ein Datum,
dann verpass dem Ganzen eine Struktur. Dadurch wird dann oft
die Übergabe solcher Daten an Funktionen vereinfacht.
Wenn die Daten nichts miteinander zu tun haben, dann lass es sein.

> Wieso wird hier plötzlich soviel mehr Code erzeugt? Habe ich etwas
> übersehen?

Man müsste sich den Code genau ansehen und was der Compiler
daraus macht. Allerdings ist eine Erhöhung von 400 byte schon
keine Kleinigkeit mehr. Daher war diese Änderung kontraproduktiv.
So ist das bei Optimierungen: Manchmal bewirken gut gemeinte
Optimierungen das genaue Gegenteil.

Gerade für Optimierungen gibt es kein Patentrezepz.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ben wrote:
> Hallo, ich versuche gerade die Programmgröße eines größeren Projektes zu
> optimieren, dessen Umfang langsam an die Grenze des Mega8 kommt.

Ehe Du anfängst, an irgendner Schraube zu drehen, mußt Du erstmal 
wissen, wer die Speicherfresser sind.

Also laß Dir mal das MAP-File und das LST-File mit den Quelltextzeilen 
erzeugen.

Im MAP stehen die Speichergrößen für jede Funktion.
Die Funktionen mit den größten Werten mal genauer ansehen.

Im LST sieht man sehr schön, wieviel Code jede einzelne C-Zeile erzeugt.
Schön sind Zeilen, die nur 1..2 Assemblerbefehle erzeugen.
Es können aber auch 100 Assemblerbefehle sein, dann könnte 
Optimierungspotential bestehen.


Oftmals sind große Optimierungen durch Aufräumen von Spaghetticode 
möglich.
D.h. viele ähnliche Codeabschnitte durch eine Unterfunktion ersetzen und 
diese dann mit den entsprechenden Parametern aufrufen.


Peter

Autor: Philipp Burch (philipp_burch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger wrote:
> Oftmals sind große Optimierungen durch Aufräumen von Spaghetticode
> möglich.
> D.h. viele ähnliche Codeabschnitte durch eine Unterfunktion ersetzen und
> diese dann mit den entsprechenden Parametern aufrufen.

Ausserdem sollten grosse/grössere if/switch-Blöcke vermieden werden 
(Sprünge sind manchmal ziemlich teuer). Wenn immer möglich, so viel 
ähnliche Funktionalität wie möglich in eine Tabelle packen und nur noch 
einmal mit dem entsprechenden Tabellenwert erzeugen lassen.
Bsp:
uint8_t x;
//...
switch(x) {
  case 0: PORTA = 0x05; break;
  case 1: PORTA = 0x06; PORTB |= 0x01; break;
  case 2: PORTA = 0x80; break;
  case 3: PORTA = 0x00; PORTB |= 0x01; break;
  //...
}

//Ändern in
uint8_t x;
//...
const uint8_t table[] PROGMEM = {0x05, 0x06, 0x80, 0x00 /* , ... */};
if (x < 4) {
  PORTA = pgm_read_byte(&table[x]);
  if (x % 2) {   //% 2 wird hoffentlich in & 1 umgesetzt...
    PORTB |= 0x01;
  }
}

Oder so irgendwie...

inline-ifs würde ich übrigens auch vermeiden, die scheint der GCC gerne 
in 16 Bit-Operationen umzusetzen (x = y < 3 ? 4 : 2).

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du bindest doch diese eine global.h nicht in allen .c dateien?
dann hast du doch den salat in jeder datei.
extern daten a; // <<

grüsse, daniel

Autor: ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter Dannegger
danke, ich werde mir die files mal anschauen

@Philipp Burch
Sowas kommt bei mir nicht vor, aber danke für den Tip, werde ich mir 
merken.

@daniel
hatte tatsächlich die deklaration in der h datei.
habe das jetzt mal geändert, d.h. alle deklarationen in ein c file und 
im h file dann mit extern. Die Dateigröße hat sich dadurch allerding 
überhaupt nicht geändert.
Muss dazu sagen, dass ich die variablen alle volatile deklariert habe, 
da auf sie aus verschiedenen interrupts zugeriffen werden muss..

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.