www.mikrocontroller.net

Forum: Compiler & IDEs Verwendung von Structs langsamer?


Autor: peterguy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

wir haben hier eine Diskussion am Laufen, ob es den Code langsamer 
macht, wenn man structs anstelle von "normalen Variablen" verwendet.

Hat das mal jemand ausgemessen, bzw. den assembler code sich angeschaut?

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

Bewertung
0 lesenswert
nicht lesenswert
peterguy schrieb:
> Hallo Leute,
>
> wir haben hier eine Diskussion am Laufen, ob es den Code langsamer
> macht, wenn man structs anstelle von "normalen Variablen" verwendet.
>
> Hat das mal jemand ausgemessen, bzw. den assembler code sich angeschaut?

Warum macht ihr das nicht einfach?

Erwarten würde ich, dass sich beide Varianten nichts schenken, eher im 
Gegenteil, dass die struct Variante bei vernünftiger Programmierung 
schneller ist.

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich tippe mal auf gleich schnell. Im Endeffekt steht doch jede Variable 
an einer bestimmten Stelle im Speicher. Zum Verarbeiten muss sie erst in 
ein Register geladen werden usw.
Von daher wüsste ich jetzt nicht, warum es einen Unterschied machen 
sollte? Es sei denn vielleicht dass bei einer struct die Variablen 
direkt hintereinander im Speicher liegen und nicht "wild verstreut", und 
dass der Prozessor auf aufeinanderfolgende Speicherstellen schneller 
zugreifen könnte...

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

Bewertung
0 lesenswert
nicht lesenswert
Mark Brandis schrieb:

> sollte? Es sei denn vielleicht dass bei einer struct die Variablen
> direkt hintereinander im Speicher liegen und nicht "wild verstreut", und
> dass der Prozessor auf aufeinanderfolgende Speicherstellen schneller
> zugreifen könnte...

Das ist auch meine Überlegung, dass der Compiler dann mit einem 
Basisregister und Offset arbeiten kann anstatt ständig irgendwelche 
Adressregister mit Werten laden zu müssen. Auch sollten Funktionsaufrufe 
einen Tick schneller gehen, wenn anstelle von 5 Variablen nur eine 
Basisadresse einer struct übergeben werden muss.

Aber wie heißt es so schön: Versuch macht kluch.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube auf einem Atmel ist zu lesende zugriff auf eine struct member 
langsamber.

Erst muss er die adresse vom Struct lesen und dann darauf den offset 
addieren (ich glaube nicht das er es optimieren kann).

Aber bei der übergaben an eine Funktion sollte eine struct schneller 
sein, weil er ja nur eine Adresse übergeben muss, statt mehre Variablen.

Es wird wohl abhängig vom Programm sein, mal ist das eine mal das andere 
schneller.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
x = abcd;

ist ebenso schnell wie

x = a.b.c.d;

Weil der Compiler alle Offsets ausrechnen kann und keine zusätzlichen 
Befehle zur Laufzeit notwendig sind

Falls es nicht gecshachtelte Strukturen/Unions sind sondern Zeiger, 
müssen natürlich (idR) Indirektionen zur Laufzeit ausgeführt werden, 
also

x = a->b->c->d;

Strukturen können ja nach Anwendungsfall Vor- oder Nachteile bieten.

Beispiel 1
avr-gcc (sizeof(int) = 2)

Es ist eine Funktion mit 4 char-Werten aufzurufen:
void foo (char,char,char,char);

Die Werte werden dann in den Registern R24, R22, R20, R18 übergeben und 
R25,R23,R21,R19 bleiben ungenutzt. Mit Struktur
struct char2 {char a, b;};
struct char4 {char a, b, c, d;};

void foo2 (struct char2, struct char2);
void foo4 (struct char4);

wird die Struktur(en) in den Registern R22,R23,R24,R25 übergeben. Das 
bedeutet eine bessere Registerausnutzung.

Sollen mehrere Werte zurückgegeben werden, ist dies je nach ABI auch 
dann innerhalb eines Registers möglich, wenn eine Struktur zurückzugeben 
ist.

Sind zB 4 Chars zurückzugeben, dann geht das effizient mit struct char4, 
während die Standard-Lösung über Zeiger der Overkill ist:
void foo8_char (char,char,char,char,char*,char*,char*,char*);

struct char4 foo8_char4 (struct char4);

Die zweite Variante ist um Längen effizienter.

Weiterhin eröffnen Strukturen die Möglichkeut, effizienter auf Daten 
zuzugreifen, denn in einer Struktur sind alle Elemente definiert 
angeordnet und haben bekannte Offsets zum Strukturanfang, was bei 
Variablen nicht so ist. Deren Adressen haben keine dem Compiler bekannte 
Beziehung und werden erst zur Linkzeit festgelegt:
int a, b, c, d;
struct abcd { int a, b, c, d; };

void add1 (void)
{
    a++;
    b++;
    c++;
    d++;
};

void add2 (struct abcd * s)
{
    s->a ++;
    s->b ++;
    s->c ++;
    s->d ++;
}

Schaut man sie hier die Codegröße für an (avr-gcc) dann belegt add1 76 
Bytes, wohingegen add2 mit 46 auskommt und nur 2 Ticks langsamer ist. 
(Gesamtdauer ca. 26 Ticks).

Johann

Autor: dummi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Aber bei der übergaben an eine Funktion sollte eine struct schneller
>sein, weil er ja nur eine Adresse übergeben muss, statt mehre Variablen.


Aber nur bei der Übergabe, beim Zugriff muss dann über Offset 
zugegriffen werden, da kann sich das bei vielen zugriffen rächen.

Ist aber alles sehr Architektur und Compiler abhängig.


Also Compileroutput begutachten.

mfg.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:

> Erst muss er die adresse vom Struct lesen und dann darauf den offset
> addieren (ich glaube nicht das er es optimieren kann).

Hier mal ein Beispiel
int a, b, c, d;
struct s { int a, b, c, d[10]; struct {int e, d, f, g[5];} s; } s;

int get_a (void)
{
    return a;
}

int get_s_a (void)
{
    return s.a;
}

int get_s_d5 (void)
{
    return s.d[5];
}

int get_s_s_g4 (void)
{
    return s.s.g[4];
}

int get_pa (int *a)
{
    return *a;
}

int get_ps_a (struct s * s)
{
    return s->a;
}

int get_ps_d5 (struct s * s)
{
    return s->d[5];
}

int get_ps_s_g4 (struct s * s)
{
    return s->s.g[4];
}

Assembler
get_a:
  lds r24,a
  lds r25,(a)+1
  ret

get_s_a:
  lds r24,s
  lds r25,(s)+1
  ret

get_s_d5:
  lds r24,s+16
  lds r25,(s+16)+1
  ret

get_s_s_g4:
  lds r24,s+40
  lds r25,(s+40)+1
  ret

get_pa:
  movw r30,r24
  ld r24,Z
  ldd r25,Z+1
  ret

get_ps_a:
  movw r30,r24
  ld r24,Z
  ldd r25,Z+1
  ret

get_ps_d5:
  movw r30,r24
  ldd r24,Z+16
  ldd r25,Z+17
  ret

get_ps_s_g4:
  movw r30,r24
  ldd r24,Z+40
  ldd r25,Z+41
  ret

Wie man sieht, wird da nix unnötig zur Laufzeit berechnet.

Die nötige Arithmetik wird -- falls möglich -- aufgehteilt zwischen 
Compiler, Assembler und Linker.

Johann

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dummi schrieb:
>>Aber bei der übergaben an eine Funktion sollte eine struct schneller
>>sein, weil er ja nur eine Adresse übergeben muss, statt mehre Variablen.
>
>
> Aber nur bei der Übergabe, beim Zugriff muss dann über Offset
> zugegriffen werden, da kann sich das bei vielen zugriffen rächen.

Nö. Wie machst du es denn mit 10 Zugriffen wenn die Variablen im 
Speicher verstreut sind? 10 Adressen übergeben?

Johann

Autor: Thomas W. (wagneth)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gab es nicht genau deswegen solche Compilerschalter wie WordAlignment ?

Bei denen "leerblöcke" mit eingabaut würden um den Zugriff zu 
beschleunigen,
bzw weggelassen um Platz zu sparen ?!

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei einem 8-Bit-Prozessor mit 8-Bit-Datenbus (Atmel AVR) wohl eher nicht 
;-)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Mark Brandis
ist nicht der EEProm oder der Flash 16 Alignt - zumindest die 
Adressierung

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beim Flash glaube ja, ich meinte jetzt auch eher den Hauptspeicher in 
dem zur Laufzeit die Variablen herum(f)liegen.

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.