Forum: Mikrocontroller und Digitale Elektronik gcc optimiert zu viel


von Jörg T. (brause)


Lesenswert?

Hallo zusammen,

ich habe folgende (abgespeckte) Zeilen, die einen Dreiecktausch 
durchführen:
1
  uint8_t    A[10], B[10];
2
  uint8_t*  temp;
3
  uint8_t*  pA =&A[0];
4
  uint8_t*  pB =&B[0];
5
6
  temp =pA;
7
  pA =pB;
8
  pB =temp;
Wie schaffe ich es, dass der Compiler mir diese Zeilen nicht 
wegoptimiert?
Die triviale Lösung "Optimierung deaktivieren" gilt aber nicht.

Danke und Grüße
Jörg

von Floh (Gast)


Lesenswert?

Jörg T. schrieb:
> Wie schaffe ich es, dass der Compiler mir diese Zeilen nicht
> wegoptimiert?

Wie optimiert er es weg?
Außerdem, solange die Funktion erhalten bleibt darf er optimieren wie er 
will.

von Helfer (Gast)


Lesenswert?

Kennzeichne die Zeiger als volatile.

von Helfer (Gast)


Lesenswert?


von g457 (Gast)


Lesenswert?

Eigentlich gibts da nix zum wegoptimieren (vorausgesetzt pA und pB 
werden noch genutzt). Ich vermute mal stark dass der TO uns den 
wichtigen Teil vom Code vorenthält, deswegen rate ich einfach mal drauf 
los: Also die Variablen sind global deklariert, das Durchtauschen 
geschieht in einer ISR und verwendet wirds dann irgendwo 'im 
Hauptprogramm'. Und jetzt optimiert der Compiler scheinbar zu viel weg. 
Falls dem so ist lautet die Lösung wie von 'Helfer' schon geschrieben: 
volatile an der richtigen(tm) Stelle hülft.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

volatile doktert nur an Symptomen.

Bei den Variablen/Arrays handelt es sich wohl (kann man nur raten) um 
lokale Variablen, die nicht weiterverwendet werden. Wozu soll dann deren 
Wert berechnet werden...? Der Compiler kickts also raus.

Mach was mit den Werten (und das ist nicht, sie im Debugger anzuschauen 
oder anschauen zu wollen) sondern verwende sie zB in einer Augabe.

Der Compiler wird genau den Code erzeugen, der da steht -- bzw. Code, 
der äquivalent dazu ist. Zeig einfach mal den gesamten Kontext, und 
nicht nur ein Schnippelchen.

Wenn das Schnippelchen nämlich genauso in einer Funktion steht, nur mit 
lokalen Variablen, ist's ok das alles weg zu optimieren.

von hp-freund (Gast)


Lesenswert?

static ?

von hp-freund (Gast)


Lesenswert?

Für solche Probleme mach ich einfach einen Test:
1
#include <stdio.h>
2
3
int main()
4
{
5
  volatile uint8_t    A[10];
6
  static uint8_t B[10];
7
  static uint8_t*  temp;
8
  volatile uint8_t*  pA =&A[0];
9
  static uint8_t*  pB =&B[0];
10
11
  temp =pA;
12
  pA =pB;
13
  pB =temp;
14
15
}

und schaue mir das Ergebnis an.

Auszug aus der .sym Datei:

00800060 D __data_start
00800060 d pB.1371
00800062 B __bss_start
00800062 D __data_end
00800062 D _edata
00800062 b temp.1369
00800064 b B.1368
0080006e B __bss_end
0080006e N _end
00810000 N __eeprom_end

von rw (Gast)


Lesenswert?

habt ihr nicht bald genug mit c-schlüsselwörtern um euch geworfen?

bevor jörg uns das problem nicht besser beschreibt ist das alles nur 
gerate...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hier mal ein "reales" Programm:
1
#include <stdint.h>
2
3
uint8_t    A[10], B[10];
4
5
void tausch()
6
{
7
  uint8_t*  temp;
8
  uint8_t*  pA =&A[0];
9
  uint8_t*  pB =&B[0];
10
11
  temp =pA;
12
  pA =pB;
13
  pB =temp;
14
}

Es werden nur lokale Variablen (Zeiger) rumgeschubst.

Oder ist vielleicht sowas gemeint? Das tauscht A[0] mit B[0]:
1
void tausch()
2
{
3
  uint8_t  temp;
4
  uint8_t*  pA =&A[0];
5
  uint8_t*  pB =&B[0];
6
7
  temp = *pA;
8
  *pA = *pB;
9
  *pB = temp;
10
}

von bitte löschen (Gast)


Lesenswert?

OT:

Variablen ordinaler Typen lassen sich auch ohne temporäre Variablen 
vertauschen:

*pA ^= *pB
*pB ^= *pA
*pA ^= *pB

von Peter (Gast)


Lesenswert?

Philipp Klostermann schrieb:
> Variablen ordinaler Typen lassen sich auch ohne temporäre Variablen
> vertauschen:
> *pA ^= *pB
> *pB ^= *pA
> *pA ^= *pB
schön, aber das ganze ist zum schlus langsamer als das Original.

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
> Philipp Klostermann schrieb:
>> Variablen ordinaler Typen lassen sich auch ohne temporäre Variablen
>> vertauschen:
>> *pA ^= *pB
>> *pB ^= *pA
>> *pA ^= *pB
> schön, aber das ganze ist zum schlus langsamer als das Original.

Und es gibt einen schönen Sonderfall
1
void Swap( uint8_t * pA, uint8_t * pB )
2
{
3
 *pA ^= *pB
4
 *pB ^= *pA
5
 *pA ^= *pB
6
}
7
8
int main()
9
{
10
  uint8_t i;
11
12
  i = 5;
13
14
  Swap( &i, &i );
15
}

Danach ist i gleich 0.
Kurz und gut: Diese Techniken bringen meistens keinen Vorteil.
Sind für mich ein Beispiel für "wahnsinnig clevere" Low-Level Hacks, die 
kein Mensch braucht. In Assembler ist sowas manchmal ganz nett um ein 
Register zu sparen, aber in Hochsprachen bringt das nicht viel.

von bitte löschen (Gast)


Lesenswert?

1. Wieso ist das langsamer? Auf welcher Architektur ist es langsamer? 
(Abgesehen davon, dass Funktionsaufruf und Rückkehr hier das 
Zeitaufwendigste sind? :D
2. Da es ja so irre häufig vorkommt, dass man eine Variable mit sich 
selbst tauschen muss, ist dieser Sonderfall natürlich das Hauptargument 
gegen diese Technik. :D

von XOR kack!! (Gast)


Lesenswert?

Es MUSS langsamer sein.
Du machst 3 xors. Und die daten müssen trotzdem geladen und gespeichert 
werden.

Ein normales Tauschen verbraucht NUR laden und speichern.

load Wert1, Addr1
load Wert2, Addr2
store Wert2, Addr1
store Wert1, Addr2

Das X-Orgeraffel (was auch noch falsch ist,  wen Wert1 == Wert2 ist)

load Wert1, Addr1
load Wert2, Addr2
xorkack
store Wert2, Addr2
store Wert1, Addr1

seindeutig verloren, langsamer und falsch. Kein Vorteil, nur schwerer zu 
lesen. Sinnlos. Von Vorn bis hinten.


Hmmh: einadress Maschine wäre eventuell das einzige wos wirklich besser 
ist, bleibt noch das Problem: es ist falsch.

von Jörg T. (brause)


Lesenswert?

Hallo zusammen,

ersteinmal vielen, vielen Dank für die Antworten.
Ich hätte ja nicht gedacht, dass innerhalb so kurzer Zeit schon so viel 
Response reinkommt. Ich muss jetzt leider in eine Besprechung, werde 
aber versuchen noch heute mehr Hintergrundinfos zu dem Sinn der paar 
Codezeilen zu übermitteln. Also hebt Euch noch etwas von Eurer Energie 
auf... :-)

Danke nochmals und Grüße
Jörg

von bitte löschen (Gast)


Lesenswert?

Welche von beiden Alternativen langsamer ist, hängt von so vielen 
Faktoren ab, dass die pauschale Aussage, dass eine davon langsamer sein 
muss als die andere, sicher falsch ist. Deine Aussage gilt vielleicht 
für den genannten Codeschnippsel, aber ich hatte ja nur eine 
Grundaussage, nämlich dass es auch anders geht, als Nebenbemerkung ("OT" 
- off topic) gepostet.

Je nach Situation kann das XOR-Geraffel schon sinnvoll sein, besonders 
in Assembler, wenn man Register als Variablen benutzt und kein Register 
mehr frei hat. Das ist wiederum von der Prozessor-Architektur abhängig.

Dass so etwas sorgfältig im Source kommentiert wird, wenn man es 
benutzt, versteht sich von selbst. (Ich selbst habe es seit bestimmt 20 
Jahren nicht mehr benutzt, aber ich habe es immer noch im Hinterkopf.)

von Karl H. (kbuchegg)


Lesenswert?

Philipp Klostermann schrieb:

> 2. Da es ja so irre häufig vorkommt, dass man eine Variable mit sich
> selbst tauschen muss, ist dieser Sonderfall natürlich das Hauptargument
> gegen diese Technik. :D

Absichtlich wirst du das natürlich nicht machen.
Aber über eine Funktionshierarchie, 5 Funktionsaufrufe runter kann das 
schon mal vorkommen.

von bitte löschen (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Aber über eine Funktionshierarchie, 5 Funktionsaufrufe runter kann das
> schon mal vorkommen.

Dann sollte man nochmal das ganze Programmkonzept durchdenken.

von Sebihepp (Gast)


Lesenswert?

>> Aber über eine Funktionshierarchie, 5 Funktionsaufrufe runter kann das
>> schon mal vorkommen.
>
>Dann sollte man nochmal das ganze Programmkonzept durchdenken.

Nicht unbedingt. Will man in einem Array das kleinste/größe Element 
finden kann man einfach sortieren und hat dann als erstes/letztes 
Element die gesuchten Werte. Wer sagt, dass in dem Array keine gleichen 
Elemente vorhanden sind? Und wenn der Algorithmus zum sortieren diese 
vertauscht...

Achtung: Natürlich unter der Annahme dass man das so löst. Ob es der 
effizienteste Weg ist, sei mal dahingestellt. Genauso der 
Sortieralgorithmus welcher gleiche Elemente tauscht... (Mir fällt gerade 
keiner ein^^)

von Mathias A. (mrdelphi)


Lesenswert?

XOR kack!! schrieb:
> Das X-Orgeraffel (was auch noch falsch ist,  wen Wert1 == Wert2 ist)

nee, die Werte sind egal, nur wenn Addr1 == Addr2 ist klappt es nicht...

Zur Geschwindigkeit: was besser ist kommt wie so oft auf die Architektur 
und weitere Randbedingungen an -- meine mich z.B. zu erinnern, dass beim 
x86 ein Register auf Null zu setzen durch XOR mit sich selbst schneller 
war als eine 0 zu laden ;-)  (zumindest zu DOS-zeiten wurde das so 
gemacht, ob das für aktuelle x86 noch gilt weiß ich nicht)

von (prx) A. K. (prx)


Lesenswert?

Mathias A. schrieb:

> und weitere Randbedingungen an -- meine mich z.B. zu erinnern, dass beim
> x86 ein Register auf Null zu setzen durch XOR mit sich selbst schneller
> war als eine 0 zu laden ;-)

Auf jeden Fall kürzer (2 Bytes statt 3 oder 5). Bei einigen 
Implementierungen (ca. Intel PPro bis Pentium M) war dieses XOR mal 
schneller und mal langsamer als der MOV, weil (1) sie die Unabhängigkeit 
vom vorigen Inhalt nicht erkannten und damit eine mögliche 
Parallelausführung unabhängiger Datenpfade verhinderten, aber (2) die 
altertümliche XOR/MOVB-Sequenz für Byte-Loads speziell optimierten.

von bitte löschen (Gast)


Lesenswert?

Sebihepp schrieb:
> Will man in einem Array das kleinste/größe Element
> finden kann man einfach sortieren und hat dann als erstes/letztes
> Element die gesuchten Werte.

Witzig, genau dafür habe ich damals in der Uni einen Rüffel bekommen, 
als es in "Programmierung I" (oder so) um die genannte Aufgabenstellung 
ging. Ich hatte das damals mit einem Bubblesort gelöst, weil ich den 
noch aus der Schule kannte. (Damals hat man im Informatikunterricht 
nicht nur Word und Excel gemacht. ;-) ) Dass das die unsinnigste 
Herangehensweise ist, war mir damals auch schon klar, nur war ich jung, 
und wollte mit dem Bubblesort glänzen. :-D

Sebihepp schrieb:
> Wer sagt, dass in dem Array keine gleichen
> Elemente vorhanden sind?

Mehrere gleiche schon, aber nicht mehrere selbe. ;-)

Sebihepp schrieb:
> Und wenn der Algorithmus zum sortieren diese
> vertauscht...

..dann ist er grottig. :-D

von Mathias A. (mrdelphi)


Lesenswert?

A. K. schrieb:
> Mathias A. schrieb:
>
>> und weitere Randbedingungen an -- meine mich z.B. zu erinnern, dass beim
>> x86 ein Register auf Null zu setzen durch XOR mit sich selbst schneller
>> war als eine 0 zu laden ;-)
>
> Auf jeden Fall kürzer (2 Bytes statt 3 oder 5).

stimmt, das kann auch der Grund gewesen sein, ist schon so lange her. 
Sollte nur ein Beispiel sein, dass manchmal der Weg um mehrere Ecken 
herum günstiger sein kann als der direkte  ;-)
Ob man auf Platz oder Geschwindigkeit optimieren will ist ja meistens 
ein Gegensatz und man muss eben entscheiden was wichtiger ist...

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.