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
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.
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.
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.
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
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.
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
voidSwap(uint8_t*pA,uint8_t*pB)
2
{
3
*pA^=*pB
4
*pB^=*pA
5
*pA^=*pB
6
}
7
8
intmain()
9
{
10
uint8_ti;
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.
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
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.
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
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.)
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.
Karl heinz Buchegger schrieb:> Aber über eine Funktionshierarchie, 5 Funktionsaufrufe runter kann das> schon mal vorkommen.
Dann sollte man nochmal das ganze Programmkonzept durchdenken.
>> 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^^)
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)
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.
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
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...