ich habe meinen Computer neu aufgesetzt, vermutlich auch mit neuer avr-gcc Version und jetzt kommt da folgender lss-Schnipsel raus: e8: 87 e9 ldi r24, 0x97 ; 151 ea: 99 e3 ldi r25, 0x39 ; 57 unsigned int i; for(i=0;i<WLC;i++) asm volatile ("nop"); ec: 00 00 nop ee: 01 97 sbiw r24, 0x01 ; 1 f0: 00 97 sbiw r24, 0x00 ; 0 f2: e1 f7 brne .-8 ; 0xec <warte+0x4> das subtrahieren von 0 war früher nicht da und ich möchte es auch in Zukunft nicht da haben, was kann ich tun? gcc Version ist: Target: avr Configured with: ../src/configure -v --enable-languages=c,c++ --prefix=/usr/lib --infodir=/usr/share/info --mandir=/usr/share/man --bindir=/usr/bin --libexecdir=/usr/lib --libdir=/usr/lib --enable-shared --with-system-zlib --enable-long-long --enable-nls --without-included-gettext --disable-libssp --build=i686-linux-gnu --host=i686-linux-gnu --target=avr Thread model: single gcc version 4.8.2 (GCC) und der Compiler-Aufruf: avr-gcc -c -mmcu=atmega88 -I. -gstabs -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=cnc.lst -std=gnu99 -MD -MP -MF .dep/cnc.o.d cnc.c -o cnc.o
g457 schrieb: > für > >> warte > > -schleifen gibts delay_[um]s() oder Assembler. > > HTH is recht, aber kannst Du auch was zu meiner die Frage sagen?
Walter schrieb: > das subtrahieren von 0 war früher nicht da und ich möchte es auch in > Zukunft nicht da haben, was kann ich tun? Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit. Wie hats das denn früher gemacht? Wie würdest du denn eine 16bit-Operation effizienter hinbekommen??
Dr. Sommer schrieb: > Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit. Warum? Und warum vom selben Registerpaar? sbiw ist doch bereits eine 16 bit operation, oder?
:
Bearbeitet durch User
Dr. Sommer schrieb: > Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit. Nö. Da wird ein Registerpaar auf 0 getestet. Unnötigerweise.
:
Bearbeitet durch User
Was genau stört dich denn daran? Ich meine wenn man in C programmiert kümmert man sich nur im äußersten Fall um Assembler.
Walter schrieb: > das subtrahieren von 0 war früher nicht da und ich möchte es auch in > Zukunft nicht da haben, was kann ich tun? Optimierung Abschalten. 8-Bit-Schleifenvariable verwenden. Grund: Der GCC hat deine Schleife umgedreht, statt >> for(i=0;i<WLC;i++) macht er >> for(i=WLC;i;--i) warum? 'i' kann er schön im Register-Paar r24,r25 behalten, der Schleifenrumpf interessiert sich nicht für den Wert von 'i', insofern ist nur die richtige Anzahl an Schleifendurchläufen wichtig, den Rest darf er ändern wie er lustig ist. Und Startwert WLC setzen, Subtraktion und Vergleich auf 0 ist eben "schicker" als auf 0 Initialisieren, Addieren, 16-Bit-Vergleich mit WLC durchführen.
> is recht, aber kannst Du auch was zu meiner die Frage sagen? Klar, hier nochmals Deine Frage: > [..] was kann ich tun? Für > warte -schleifen gibts fertige Funktionen wie delay_[um]s(), die kannst Du ohne Sorgen direkt benutzen. Oder Du kannst in selber in Assembler hinschreiben was Du genau haben willst. HTH und nix für ungut
Ingo schrieb: > Was genau stört dich denn daran? Ich meine wenn man in C programmiert > kümmert man sich nur im äußersten Fall um Assembler. nun, mich stört, dass das nur ein Beispiel war, wo es leicht zu erkennen ist. Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz und Zeit verschwenden. Ich habe nach der Neuinstallatuion eben vorher und nachher verglichen. Ich würde ja nichts sagen, wenn der gcc es halt nicht besser kann, aber er konnte das schon Mal
@ Walter (Gast) >nun, mich stört, dass das nur ein Beispiel war, wo es leicht zu erkennen >ist. >Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz Oh Gott, 2 Bytes! >und Zeit verschwenden. Einen Takt. >Ich würde ja nichts sagen, wenn der gcc es halt nicht besser kann, aber >er konnte das schon Mal Wahrscheinlich sind die falschen Compilerschalter gesetzt. Ausserdem ist i ein INT, und der ist nunmal 16 Bit. Den kann der Compiler nur bedingt kleiner machen. Mach es so, dann ist deine Schleife maximal schnell.
1 | #include <stdint.h> |
2 | #define nop() asm volatile("nop")
|
3 | #define WLC 100
|
4 | |
5 | int main (void) { |
6 | uint8_t i; |
7 | |
8 | for(i=WLC;i>0;i++) |
9 | asm volatile ("nop"); |
10 | }
|
1 | 6c: 84 e6 ldi r24, 0x64 ; 100 |
2 | uint8_t i; |
3 | |
4 | for(i=WLC;i>0;i++) |
5 | asm volatile ("nop"); |
6 | 6e: 00 00 nop |
7 | #define WLC 100 |
8 | |
9 | int main (void) { |
10 | uint8_t i; |
11 | |
12 | for(i=WLC;i>0;i++) |
13 | 70: 8f 5f subi r24, 0xFF ; 255 |
14 | 72: e9 f7 brne .-6 ; 0x6e <main+0x2> |
15 | asm volatile ("nop"); |
16 | } |
17 | 74: 80 e0 ldi r24, 0x00 ; 0 |
18 | 76: 90 e0 ldi r25, 0x00 ; 0 |
19 | 78: 08 95 ret |
Falk Brunner schrieb: > Oh Gott, 2 Bytes! > >>und Zeit verschwenden. > > Einen Takt. oder 30% mehr Platz und 30% langsamer - so könnte man es auch sehen.
Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt.
Falk Brunner schrieb: > Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt. aber wenn man ihm glauben kann, dann würde ich auch der Grund interessieren warum es schon mal anders ging. Das hat wohl nicht mit "Hochoptimierung" zu tun, sondern ist eventuell wirklich ein Bug.
Ahab schrieb: > Und Startwert WLC setzen, Subtraktion und Vergleich auf 0 ist eben > "schicker" als auf 0 Initialisieren, Addieren, 16-Bit-Vergleich mit WLC > durchführen. Das ist es aber nur dann wirklich, wenn er nach der Subtraktion nicht noch eine unnötige zweite Subtraktion mit 0 einfügt. Die stellt nämlich genau den Vergleich dar, den man sich durch das Umdrehen der Zählrichtung eigentlich einsparen wollte. Falk Brunner schrieb: >>Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz > > Oh Gott, 2 Bytes! > >>und Zeit verschwenden. > > Einen Takt. Ich finde die Frage, warum der Compiler auf einmal schlechter optimiert als eine frühere Version und warum er zusätzliche Instruktionen einfügt, durchaus gerechtfertigt. > Wahrscheinlich sind die falschen Compilerschalter gesetzt. Wleche sollten das denn sein? > Ausserdem ist i ein INT, und der ist nunmal 16 Bit. Ja, und? Bei 16 Bit muss man zwingend beim Zählen in jedem Schleifendurchlauf nochmal 0 vom Wert abziehen und bei 8 Bit nicht? > Mach es so, dann ist deine Schleife maximal schnell. WLC ist aber nicht 100, sondern offenbar 14743. Wie soll das in 8 Bit passen? Falk Brunner schrieb: > Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt. Das ist zwar richtig, aber trotzdem keine Begründung für eine schlechte Optimierung.
@ Rolf Magnus (rmagnus) >Ich finde die Frage, warum der Compiler auf einmal schlechter optimiert >als eine frühere Version und warum er zusätzliche Instruktionen einfügt, >durchaus gerechtfertigt. Ja. >> Wahrscheinlich sind die falschen Compilerschalter gesetzt. >Wleche sollten das denn sein? Kenn ich mich im Detail auch nicht aus. >> Ausserdem ist i ein INT, und der ist nunmal 16 Bit. >Ja, und? Bei 16 Bit muss man zwingend beim Zählen in jedem >Schleifendurchlauf nochmal 0 vom Wert abziehen und bei 8 Bit nicht? Sicher, wenn kein Optimierung eingeschaltet ist, denn es ist eine 16 Bit Subtraktion, welche auf einem 8 Bit Prozessor meistens zwei Subtraktionen (einmal Low Byte und eimal high Byte + Carry) benötigt. Mit aktiver Optimierung macht der avr gcc ein subiw draus, wodurch eine 16 Bit Subtraktion mit einem Befehl, wenn gleich auch 2 Takten erfolgen kann. >> Mach es so, dann ist deine Schleife maximal schnell. >WLC ist aber nicht 100, sondern offenbar 14743. Wie soll das in 8 Bit >passen? Womit man so oder so eine 16 Bit Subtraktion braucht.
Falk Brunner schrieb: > Womit man so oder so eine 16 Bit Subtraktion braucht. das ist ja ok, nur die Frage warum er 2 16bit Subtraktion macht steht ja.
Walter schrieb: > Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz > und Zeit verschwenden. Du kannst (und sollst!) nichts anderes machen als Deinen Code (menschenlesbar!) hinschreiben und davon ausgehen dass der Compiler einigermaßen gut optimiert. Einigermaßen bedeutet er tut alles was in seiner Macht steht und das ist unterm Strich schon nicht schlecht. An einigen Stellen wird er sogar Optimierungen finden an die hättest selbst Du nicht gedacht, an anderen Stellen hättest Du vielleicht von Hand noch 2 Takte rausgekitzelt oder ein paar Bytes gespart aber unterm Strich ist der gcc schon gar nicht mal so schlecht. Manchen sagen sogar er ist eigentlich ganz gut und auf jeden Fall ist er mindestens doppelt so gut wie die kastrierten 8 Bit Compiler von Microchip für PIC. Das Wichtigste ist daß Du Deinen Code hinschreiben kannst ohne Dir allzuviele Gedanken darüber zu machen und darauf zählen kannst daß beim Compilieren kein haarsträubender Unsinn rauskommt. Wo Du die Grenze von "haarsträubend" hinlegst ist natürlich eine persönliche Entscheidung, aber ich würde sie nicht näher als vielleicht 20% vom theoretischen Optimum entfernt hinlegen und das schafft der gcc allemal.
Bernd K. schrieb: > Wo Du die Grenze von > "haarsträubend" hinlegst ist natürlich eine persönliche Entscheidung, > aber ich würde sie nicht näher als vielleicht 20% vom theoretischen > Optimum entfernt hinlegen und das schafft der gcc allemal. scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann liegt er 100% daneben. Es geht darum, das er es schon mal besser gemacht hat!
Peter II schrieb: > scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann > liegt er 100% daneben. Ich dachte es geht um das gesamte Programm und das was unterm Strich an verpasster Einsparung übrig bleibt (so hab ich den zitierten Teil verstanden, darauf bezog ich mich). Vorzeitige (Mikro-)Optimierungen sind die Wurzel allen Übels und verschwendete Lebenszeit. Von zehntausend Zeilen in Deinem Programm werden vielleicht nachher nur zwei Dutzend wirklich zeitkritisch sein und 90% der CPU-Zeit verbrauchen. Das findest Du leicht mit geeigneten Profiling-Techniken raus und dann kannst Du Dich auf diesen einen Teil konzentrieren (falls es sich überhaupt als nötig erweist [meistens nicht]). Und in den 9976 übrigen Zeilen gibts bestenfalls noch leichte Ersparnisse an Flashverbrauch rauszuholen mit nem besseren Compiler (sofern sowas überhaupt existiert) aber wahrscheinlich nicht mehr als 20%, also sch*** drauf, nimms wie es ist, es ist schon verdammt gut so wie es ist, sehr viel besser wirds nicht mehr werden und spar Dir die Zeit über diesen belanglosen Nebenkriegsschauplatz nachzugrübeln, es bringt nichts. Wenns an dieser einen Stelle wirklich schon mal besser funktioniert hat und man das nachvollziehbar nachstellen kann und Dich das so sehr wurmt hilft vielleicht auch ein Bug-Report aber ich würde nicht versuchen die Luft anzuhalten bis es gefixt ist.
Peter II schrieb: > scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann > liegt er 100% daneben. > > Es geht darum, das er es schon mal besser gemacht hat! genau so ist es. Wie gesagt, ich beschwere mich nicht wenn ein open source tool nicht das macht was ich will, aber es ging schon Mal deutlich besser und ich würde gern wissen warum. Vielleicht mache ich ja auch einen Fehler, aber den Schalter -Os habe ich gesetzt wie immer und überhaupt ist der makefile auch der gleiche wie vorher.
Bernd K. schrieb: > Vorzeitige (Mikro-)Optimierungen sind die Wurzel allen Übels und > verschwendete Lebenszeit. Hier ist offenbar nur jemandem die selbst gebaute Delay-Loop um die Ohren geflogen. Das frustet natürlich, liegt aber am falschen Ansatz, weniger am Compiler.
avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.1_798) 4.6.2 liefert: bc: 8c ed ldi r24, 0xDC ; 220 be: 95 e0 ldi r25, 0x05 ; 5 c0: 00 00 nop c2: 01 97 sbiw r24, 0x01 ; 1 c4: e9 f7 brne .-6 ; 0xc0 <__vector_16+0x12>
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | #define WLC 1500
|
5 | |
6 | /****************************************************************************/
|
7 | ISR( USART0__RX_vect ) |
8 | {
|
9 | int i; |
10 | for(i=0;i<WLC;i++) { |
11 | asm volatile ("nop"); |
12 | }
|
13 | }
|
14 | |
15 | /****************************************************************************/
|
16 | int main(void) |
17 | {
|
18 | while(1); |
19 | }
|
Kann durchaus sein, dass in einer bestimmten Version des Compilers ein anderes suboptimales Ergebnis rauskommt. Und das später dann vielleicht wieder korrigiert ist. Das ist nicht schön, kann aber passieren.
A. K. schrieb: > Hier ist offenbar nur jemandem die selbst gebaute Delay-Loop um die > Ohren geflogen. Das frustet natürlich, liegt aber am falschen Ansatz, > weniger am Compiler. es geht doch nicht im das delay. Man kann eine LED blinken lassen und das gleiche Problem entsteht. Es geht darum, das der Compiler (scheinbar) schlechter geworden ist. Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen?`
Peter II schrieb: > Es geht darum, das der Compiler (scheinbar) schlechter geworden ist. > Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen?` 4.7.2 ist auch ok. 4.8.irgendwas gibts in debian-sid, müsste man mal probieren. > es geht doch nicht im das delay. Man kann eine LED blinken lassen und > das gleiche Problem entsteht. Jo, aber der Code ist ja nicht falsch, nur suboptimal. Was bei einer Delay-Loop fatal sein kann.
:
Bearbeitet durch User
Peter II schrieb: > Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen? wäre nett, dann würde ich wenigstens wissen ob's an mir liegt
A. K. schrieb: > 4.7.2 ist auch ok. 4.8.irgendwas gibts in debian-sid, müsste man mal > probieren. habe ich von Atmel direkt geladen
Peter II schrieb: > Es geht darum, das der Compiler (scheinbar) schlechter geworden ist. Die aktuelle ofizielle gcc Toolchain von Atmel fixt aber auch einige Bugs die vorher drin waren. Zum Beispiel hat eine ältere Version (ich glaub es war die bei Ubuntu (12 oder 14) mitgelieferte) einfach mal globale Registervariablen wegoptimiert. Komplett wegoptimiert samt allen Codes der sie verwendet hat! Einfach weg! Die aktuelle Atmel-Toolchain von deren Webseite macht das nicht mehr. Deshalb verwende ich jetzt nur noch die. Solche Showstopper (oder besser deren Abwesenheit) wären mir wichtiger als irgendeine winzige vergessene Optimierung.
Walter schrieb: > wäre nett, dann würde ich wenigstens wissen ob's an mir liegt kann es auch im avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.5_1522) 4.8.1 nachstellen: 96: 8c ed ldi r24, 0xDC ; 220 98: 95 e0 ldi r25, 0x05 ; 5 9a: 00 00 nop 9c: 01 97 sbiw r24, 0x01 ; 1 9e: 00 97 sbiw r24, 0x00 ; 0 a0: e1 f7 brne .-8 ; 0x9a
Dispol schrieb: > Ich habs das gleiche "Problem" mit 4.8.2 Peter II schrieb: > kann es auch im > > avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.5_1522) 4.8.1 > Danke, dann muss ich wohl damit leben. Schade dass 1,05 Schritte vorwärts, einer zurück wohl ein Naturgesetz ist ;-)
>Schade dass 1,05 Schritte vorwärts, einer zurück wohl ein Naturgesetz >ist ;-) Ist GCC nicht OpenSource? Dann kann man ja selbst "mitschreiten".
Walter schrieb: > das subtrahieren von 0 war früher nicht da und ich möchte es auch in > Zukunft nicht da haben, was kann ich tun? > > gcc version 4.8.2 (GCC) Vermutlich PR60486, behoben in 4.8.3+, evtl. auch PR61055, behoben in 4.8.3+ und 4.9.1+: http://gcc.gnu.org/PR60486 http://gcc.gnu.org/PR61055
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.