Verwendung von Structs langsamer?

#1336601
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.
#1336624
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...
#1336633
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.
Gast #1336643
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.
Persönliche Seite #1336647
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:
1
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
1
struct char2 {char a, b;};
2
struct char4 {char a, b, c, d;};
3

4
void foo2 (struct char2, struct char2);
5
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:
1
void foo8_char (char,char,char,char,char*,char*,char*,char*);
2

3
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:
1
int a, b, c, d;
2
struct abcd { int a, b, c, d; };
3

4
void add1 (void)
5
{
6
    a++;
7
    b++;
8
    c++;
9
    d++;
10
};
11

12
void add2 (struct abcd * s)
13
{
14
    s->a ++;
15
    s->b ++;
16
    s->c ++;
17
    s->d ++;
18
}

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
Gast #1336660
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.
Persönliche Seite #1336692
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
1
int a, b, c, d;
2
struct s { int a, b, c, d[10]; struct {int e, d, f, g[5];} s; } s;
3

4
int get_a (void)
5
{
6
    return a;
7
}
8

9
int get_s_a (void)
10
{
11
    return s.a;
12
}
13

14
int get_s_d5 (void)
15
{
16
    return s.d[5];
17
}
18

19
int get_s_s_g4 (void)
20
{
21
    return s.s.g[4];
22
}
23

24
int get_pa (int *a)
25
{
26
    return *a;
27
}
28

29
int get_ps_a (struct s * s)
30
{
31
    return s->a;
32
}
33

34
int get_ps_d5 (struct s * s)
35
{
36
    return s->d[5];
37
}
38

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

Assembler
1
get_a:
2
  lds r24,a
3
  lds r25,(a)+1
4
  ret
5

6
get_s_a:
7
  lds r24,s
8
  lds r25,(s)+1
9
  ret
10

11
get_s_d5:
12
  lds r24,s+16
13
  lds r25,(s+16)+1
14
  ret
15

16
get_s_s_g4:
17
  lds r24,s+40
18
  lds r25,(s+40)+1
19
  ret
20

21
get_pa:
22
  movw r30,r24
23
  ld r24,Z
24
  ldd r25,Z+1
25
  ret
26

27
get_ps_a:
28
  movw r30,r24
29
  ld r24,Z
30
  ldd r25,Z+1
31
  ret
32

33
get_ps_d5:
34
  movw r30,r24
35
  ldd r24,Z+16
36
  ldd r25,Z+17
37
  ret
38

39
get_ps_s_g4:
40
  movw r30,r24
41
  ldd r24,Z+40
42
  ldd r25,Z+41
43
  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
Persönliche Seite #1336696
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren