Ich habe Problem beim Debugging (WinAVR), wenn ich Zeitverzögerung aus delay.h benutze. Compiler lässt sich den Code nach _delay_us oder _delay_ms nicht debuggen. Kann jemanden dabei helfen?
Stell uns doch mal Deinen Code zu Verfügung, vielleicht kann man Dir dann helfen.
vermutlich weil der Funktionsaufruf wegoptimiert wird -> Optimierung ausschalten. Die andere Falle bei diesen Funktionen: die max. erzielbare Verzögerung hängt vom CPU Takt ab und ist nicht sehr gross -> Funktion in Schleife verwenden.
JojoS wrote: > vermutlich weil der Funktionsaufruf wegoptimiert wird -> Optimierung > ausschalten. Wenn es um die mitgelieferten Delay-Funktionen geht (Sehe ich doch richtig, oder?) sollte man es vermeiden die Optimierung auszuschalten. Mal davon abgesehen, dass das keine Lösung des Problems ist, sondern nur Lösung des Symptoms ;)
Der nicht optimierte Code ist i.d.R. langsamer und grösser, da hängt es natürlich von der Anwendung ab ob das so bleiben kann. Aber zum Debuggen ist es manchmal günstiger weil gemeinsam genutzter oder inline Code nicht wegoptimiert wird. Man kann aber auch versuchen in dem optimierten Code einen Breakpoint vor das delay zu setzen und sich dann durch den asm Code hangeln, soviel wird da ja auch nicht erzeugt.
JojoS wrote: > vermutlich weil der Funktionsaufruf wegoptimiert wird -> Optimierung > ausschalten. Die Funktionen aus der delay.h sind Inline-Assembler-Routinen. Die sind volatile. Demzufolge darf der Optimizer die gar nicht wegoptimieren. Wichtig bei der Benutzung der _delay_XX-Funktionen sind zwei Dinge: 1.: Der Parameter muss konstant und zur Compile-Zeit bekannt sein. 2.: Die Optimierung muss eingeschaltet sein. Andernfalls kann alles Mögliche rauskommen, nur i.a. nicht das, was man gern hätte.
ich habe auch nicht geschrieben das die Funktion wegoptimiert wird sondern der Funktionsaufruf. Wenn man dann einen BP in die delay Funktion setzt wird der nicht gefunden.
> Wenn man dann einen BP in die delay > Funktion setzt wird der nicht gefunden. "Doktor, es tut weh, wenn ich hier draufdrücke." "Dann drücken Sie da nicht drauf." Ja, die delays funktionieren nur, wenn sie auch inline implementiert werden, und nein, man kann dann da keinen breakpoint reinsetzen. Dann setzt man ihn eben einfach danach, wo ist da das Problem? Wenn man die Optimierung ausschaltet, debuggt man sowieso etwas völlig anderes. Wenn man dann fürs endgültige Projekt die Optimierung wieder einschaltet, debuggt man gleich nochmal -- warum dann also die erste Runde überhaupt? Die ist überflüssig.
Das liegt wohl daran, daß der Breakpoint in der delay-Funktion sitzt. Bei der Optimierung wird diese wohl "geinlined" (inline), also in den Programmablauf hineinkopiert (anstatt aufgerufen) - somit wird der Breakpoint nie erreicht. Generelle Faustregel: Code ohne Optimierung debuggen... sollte er dann mit Optimierung fehlschlagen, ist zu 95% der Programmierer schuld (vergessene volatile Variablen etc. sprich: schlechter Code) und zu 5% der Compiler :-)
antworter wrote: > Bei der Optimierung wird diese wohl "geinlined" (inline), also in den > Programmablauf hineinkopiert (anstatt aufgerufen) - somit wird der > Breakpoint nie erreicht. Das wäre ein Fehler im Debugger. Er sollte den Breakpoint schon erreichen. In die Inline-Funktion selbst kann man sowieso keinen Breakpoint setzen, da sie kein Stück Code generiert hat (static inline). > Generelle Faustregel: Code ohne Optimierung debuggen... sollte er dann > mit Optimierung fehlschlagen, ist zu 95% der Programmierer schuld > (vergessene volatile Variablen etc. sprich: schlechter Code) und zu 5% > der Compiler :-) Diese Vorgehensweise halte ich für Quatsch. Erstens ist zu 99,999 % der Programmierer Schuld und bestenfalls mit einer Wahrscheinlichkeit von 1E-5 der Compiler ;-), und zweitens ist genau das ja aber das, wofür ich debuggen möchte. Wozu also zuvor die Zeit verschwenden, und erstmal den völlig anderen unoptimierten Code debuggen? kopfschüttel Ganz davon abgesehen: wenn's auf Zeiten ankommt (und wer delay.h benutzt, dem kommt es offensichtlich auf Zeiten an), hat man gute Chancen, den nicht optimierten Code einfach gar nicht zum Laufen zu bekommen, weil er einfach zu langsam ist. Gleiches gilt, falls man an der ROM-Auslastungsgrenze ankommt, weil der Code dann viel größer ist.
>Das wäre ein Fehler im Debugger. Er sollte den Breakpoint schon >erreichen. Schonmal optimierten Code debuggt ? Es ist nämlich in der Tat so, daß es dann vielen Debugger beim Stepping auf Source-Code-Ebene schnell die Füße weghaut. Für einen Breakpoint in einer Funktion, die automatisch geinlined wurde, müßte der Debugger nämlich im worst-case hunderte Breakpoints setzen - das sprengt (nebenbei) auch die Breakpoint-Limits bestimmter Hardware. > Erstens ist zu 99,999 % der Programmierer Schuld Diese Aussage ist Unsinn. Selbst ausgewachsene Compiler haben ellenlange Buglisten, und gerade im Bereich der Optimierung liegt naturgemäß das höchste Potential für den Compiler zu versagen. Natürlich gibt es auch Programmierer, die die 99,999% "Schuldgrenze" schaffen und brechen. >, hat man gute Chancen, den nicht optimierten Code einfach gar nicht zum >Laufen zu bekommen, weil er einfach zu langsam ist. Wenn Code zu langsam ist, hört er auf zu funktionieren ? Aha... Ach ja... Compilerbugs... der gcc hat z.B. bis heute Probleme, für Interrupts auf dem ARM7 passende Stack-Frames zu errichten (FIQs, wenn ich mich recht erinnere) - bei voller Optimierung.
antworter wrote: > >> Erstens ist zu 99,999 % der Programmierer Schuld > > Diese Aussage ist Unsinn. Selbst ausgewachsene Compiler haben ellenlange > Buglisten, und gerade im Bereich der Optimierung liegt naturgemäß das > höchste Potential für den Compiler zu versagen. Klar haben Compiler auch Fehler. Ist ja schliesslich auch nur ein Programm. Aber die Wahrscheinlichkeit, dass ein Neuling über einen Compiler- bug stolpert, ist nahe 0. Auch wenn die Neulinge das nicht glauben wollen, stellt sich in praktisch allen Fällen heraus, dass bei einem gut gewartetem Compiler, es praktisch immer ein Fehler im Programm und nicht im ein Fehler im Compiler ist. > > Ach ja... Compilerbugs... der gcc hat z.B. bis heute Probleme, für > Interrupts auf dem ARM7 passende Stack-Frames zu errichten (FIQs, wenn > ich mich recht erinnere) - bei voller Optimierung. Das ist aber, wenn wir die Gesammtheit aller Compiler betrachten, eher die Ausnahme als die Regel. Wobei der gcc im vergleich zu einem für eine bestimmte Hardware geschriebenen Compiler, ein vergleichsweise schwereres Leben hat.
antworter wrote: >>Das wäre ein Fehler im Debugger. Er sollte den Breakpoint schon >>erreichen. > Schonmal optimierten Code debuggt ? Ständig. Ich debugge keinen unoptimierten Code, weil ich das als Zeitverschwendung empfinde. >> Erstens ist zu 99,999 % der Programmierer Schuld > Diese Aussage ist Unsinn. Selbst ausgewachsene Compiler haben > ellenlange Buglisten, und gerade im Bereich der Optimierung liegt > naturgemäß das höchste Potential für den Compiler zu versagen. Und? Trotzdem stimmt deine Relation überhaupt nicht. Ich kenne im Moment einen Bug im AVR-GCC recht genau, für den er falschen Code erzeugt (man kann keine drei 64-Bit-Integer-Argumente an eine Funktion übergeben), und ich habe vielleicht ein oder zwei weitere Bugs dieser Art in Erinnerung. Der größte Teil der Bugs sind entweder in der Kategorie "missed optimization" (es wird als größerer oder langsamerer Code erzeugt, als nötig wäre) oder "internal compiler error" (der Compiler erkennt einen Fehler mit sich selbst und bricht ab, erzeugt aber dann gar keinen Code). Die Bugs mit falscher Codegenerierung kannst du suchen, und das ist gut so. Man kann ruhigen Gewissens davon ausgehen, dass es wahrscheinlicher ist, dass ein C-Anfänger beim Überqueren der Straße von einem Auto umgefahren wird als dass er den Compiler beim Generieren falschen Codes erwischt... >>, hat man gute Chancen, den nicht optimierten Code einfach gar nicht zum >>Laufen zu bekommen, weil er einfach zu langsam ist. > Wenn Code zu langsam ist, hört er auf zu funktionieren ? Natürlich, wenn du Code hast, der an bestimmte Abarbeitungszeiten gebunden ist, was ist daran ungewöhnlich? Ich habe eine Zeit lang einen IEEE 802.15.4 MAC-Layer geschrieben, der muss sein acknowledgment innerhalb von 192 µs raussenden. Ich bekomme es mit manuellem Umsortieren des Codes auf ungefähr diese Zeit, aber ohne Optimierung? Keine Chance, da ist er fast eine Größenordnung zu langsam. Dann läuft mir kein einziger test case mehr durch. > Ach ja... Compilerbugs... der gcc hat z.B. bis heute Probleme, für > Interrupts auf dem ARM7 passende Stack-Frames zu errichten (FIQs, > wenn ich mich recht erinnere) - bei voller Optimierung. Den ARM-GCC kenne ich nicht, aber wenn dem so ist, sollte das wohl jemand reparieren... Für den AVR-GCC sind mir derzeit keine Bugs bekannt, die durch Einschalten der Optimierung eine Generierung falschen Codes bewirken würden. Kann sein, dass mir hier ein oder zwei obskure Bugs entgangen sind, aber selbst der genannte Bug mit drei 64-Bit-Argumenten ist unabhängig von der Optimierung.
>Für den AVR-GCC sind mir derzeit keine Bugs bekannt, die durch Einschalten >der Optimierung eine Generierung falschen Codes bewirken würden Ich habe mich zu keinem Zeitpunkt auf den AVR-GCC beschränkt... ich meinte eher komplexere Architekturen (ab ARM7-Niveau). Auf dem AVR entfallen viele Optimierungsstrategien (Alignment, Cache-Kohärenz, Registerabhängigkeiten etc)... die dann eben bei größeren Architekturen mit Fehlern zuschlagen. Zitat IBM (unterstützt meine Strategie): For example, the optimizer may remove all stores to a variable and keep it alive only in registers. Most debuggers are incapable of following this and it will appear as though that variable is never updated. First debug your program, then recompile it with any optimization options, and test the optimized program before placing the program into production. If the optimized code does not produce the expected results, isolate the specific optimization problems in another debugging session. http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?topic=/com.ibm.xlf91l.doc/xlfug/ug56.htm
antworter wrote: > Ich habe mich zu keinem Zeitpunkt auf den AVR-GCC beschränkt... Darum ging es aber dem Fragesteller. > ich > meinte eher komplexere Architekturen (ab ARM7-Niveau). Auch da sollte der Compiler korrekt arbeiten. ARM7 ist ja gar nicht so komplex, ARM9 wäre schon eher ein Kandidad, oder UltraSPARC zum Beispiel. > Auf dem AVR entfallen viele Optimierungsstrategien (Alignment, Ist kein Problem, da es entweder (IA32 & Co.) eine "missed optimization" ist oder aber (RISC CPUs) sofort knallt (misaligmnet trap). Es entsteht also kein mehr oder minder unbemerkt fehlerhafter Code. > Cache-Kohärenz, Registerabhängigkeiten etc)... Muss der Compiler beherrschen (bzw. bei unseren beliebten CISC-CPUs macht's der Prozessor selbst). > For example, the optimizer may remove all stores to a variable and keep > it alive only in registers. Most debuggers are incapable of following > this and it will appear as though that variable is never updated. Ja, und? Dann ist der Debugger bzw. das Interface zwischen Compiler und Debugger schlecht. Ich kann mich an ein Statement erinnern, dass GCC und GDB mittlerweile versuchen, dieses Dilemma aufzulösen, indem die Debug-Information Angaben zur Gültigkeit der Variablen enthält. Auch wenn das Statement von IBM kommt, wird es davon nicht besser: es hat keinen Sinn, auf einer Architektur, auf der der Compiler gut optimieren kann (und muss), ein Programm ohne Optimierung überhaupt zu debuggen. Das Programm ist so sehr verschieden vom Endergebnis, dass das die Zeit nicht wert ist, die man reinsteckt. Man debuggt es ja am Ende doch alles nochmal. Ich gebe zu, dass diese meine Sicht durch meine Erfahrungswelt geprägt ist. Kann sein, dass man irgendwelche typischen C-Anfängerfehler auch im nicht optimierten Code schon finden könnte. Bleibt aber selbst in diesem Falle noch, dass nach den Anfängerfehlern genügend weitere folgen werden, die erst durch den Optmierer zu Tage kommen (das berüchtigte vergessene "volatile" macht hier den Anfang), sodass man selbst in diesem Falle trotzdem zweimal debuggen muss. Btw., du hast natürlich (weil es nicht in deine Aussage passt) komplett untern Tisch fallen lassen, dass ich dir bestätigt habe, seit Jahren ausschließlich den optimierten Code zu debuggen. Es ist gewöhnungsbedürftig, keine Frage, aber das habe ich schon vor 15 Jahren auf einem m88100 feststellen dürfen. Es ist aber trotzdem machbar.
Die Diskussion bekommt langsam eine eigenartige Wendung. Wenn ich behaupte, daß der gcc auf dem AVR eher wenig Fehlerpotential bei der Optimierung hat (wegen o.g. "fehlender" Features), antwortest Du, daß diese Features vom Compiler gehandelt werden müssen... das macht irgendwie keinen Sinn. Die Aussage von IBM habe ich auf gutdünken aus den google-Hits ausgewählt, da ich im Gegensatz zu Dir eine fundierte Argumentation aufzubauen versuche - im Gegensatz zu Deinem "bei mir geht's... ist schwierig aber geht" ------------------------------------------------------ nebenbei: ich zitiere Dich aus einem anderen Thread (google erinnert sich): Beitrag "Funktionsaufruf mit Zeiger" >Wie geschrieben, der Compiler könnte eine derartig simple Funktion als >inline-Code implementieren, dann wird dein Breakpoint nie >erreicht, obwohl trotzdem alles funktioniert.
antworter wrote: > Die Diskussion bekommt langsam eine eigenartige Wendung. Wenn ich > behaupte, daß der gcc auf dem AVR eher wenig Fehlerpotential bei der > Optimierung hat (wegen o.g. "fehlender" Features), 5 % sind eher wenig? > antwortest Du, daß diese Features vom Compiler gehandelt werden > müssen... das macht irgendwie keinen Sinn. Was hat keinen Sinn? Dass ein Compiler korrekten Code erzeugen soll, egal ob der Prozessor nun einen Cache, instruction pipelining oder was auch immer hat? Das ist nach wie vor mein Standpunkt. Wenn korrekter Code (gemäß dem C-Standard korrekt) mit -O2 oder -O3 kaputt geht an etwas anderes als geändertem Timing, dann ist das ein Compilerbug und gehört als solches repariert. > Die Aussage von IBM habe ich auf gutdünken aus den google-Hits > ausgewählt, da ich im Gegensatz zu Dir eine fundierte Argumentation > aufzubauen versuche - im Gegensatz zu Deinem "bei mir geht's... ist > schwierig aber geht" Ich baue die fundierte Argumentation (auf der Basis mittlerweile jahrelanger Erfahrungen) in der anderen Richtung auf: die Unterschiede zwischen dem nicht optimierten und dem optimiertern Code sind so gravierend, dass es meiner Meinung nach schlicht Zeitverschwendung ist, den nicht optimierten Code überhaupt erst durch den Debugger zu ziehen. Ich habe bereits zugegeben, dass ich diese Aussage aus einer Position heraus mache, die Sprache C so einigermaßen zu beherrschen, dass ich in einem großen Teil der Fälle keine allzu großen algorithmischen Schnitzer drin habe -- wenn man sich im Wesentlichen mit sowas rumschlagen muss, mag es Sinn haben, erstmal mit dem nicht optimierten Code zu beginnen. Für jeden halbwegs erfahrenen C-Programmierer streite ich diese Sinnhaftigkeit aber ab. Du könntest deinen Algorithmus genauso gut in einer anderen Sprache schreiben und debuggen und dann davon ausgehen, dass das Umschreiben nach C keinen großen Fehleranteil mehr bringen würde -- der Effekt wäre ungefähr derselbe. Hast du dir denn mal die Unterschiede im generierten Assemblercode für beide Fälle angesehen? (Damit meine ich einen nicht-i386-artigen Prozessor, bei dem der Compiler auch optimieren kann.) > nebenbei: ich zitiere Dich aus einem anderen Thread (google erinnert > sich): >>Wie geschrieben, der Compiler könnte eine derartig simple Funktion >>als inline-Code implementieren, dann wird dein Breakpoint nie >>erreicht, obwohl trotzdem alles funktioniert. Ja, hast du dir beide Sachverhalte auch mal durchgelesen? "static inline" ist etwas anderes als das Inlining einer Funktion mit global scope. Für letztere generiert der Compiler auch im Optimierungsfalle eine Kopie des Codes, auf die man einen Breakpoint setzen könnte, der dann aber nie erreicht wird, weil alle aktuellen Instanzen stattdessen inline generiert worden sind. Der Thread hier ging aber um die Funktionen aus <util/delay.h> der avr-libc, und diese sind static inline. Damit generieren sie keine zusätzliche Kopie, sondern werden ausschließlich inline generiert. Damit kann man aber auch auf keine zusätzliche Kopie mehr einen breakpoint setzen, sondern bestenfalls auf die inline generierten -- und dieser sollte dann aber auch im Programmlauf erreicht werden.
> mag es Sinn haben, erstmal mit dem nicht optimierten Code zu beginnen. > Für jeden halbwegs erfahrenen C-Programmierer streite ich diese > Sinnhaftigkeit aber ab. Da dürfte Dich das Verhalten vieler irritieren, hier noch ein Zitat: ------------- zu Visual C++: ... >Because of these limitations, you should do your debugging using an >unoptimized version of your program if at all possible. By default, >optimization is turned off in the Debug configuration of a Visual C++ >program >and turned on in the Release configuration. http://msdn2.microsoft.com/en-us/library/606cbtzs(VS.80).aspx ---------------- HP: >Ordinarily, you first compile and debug your program without optimization. >All or nearly all of the bugs in your program will show up in the >unoptimized version. >After eliminating all the bugs that you can find, turn on optimization >(compile with -O). If the program behaves incorrectly, scan the source >code for the most common kinds of bugs that appear for the first time in >optimized code http://docs.hp.com/en/B3476-90015/ch08s05.html --------------- In diesem Sinne...
Visual Affenzirkus spielt hier keine Geige: das läuft nur auf Prozessoren, die in unserer Diskussion keine Rolle spielen. Auf einem i386 kann der Compiler sowieso dank der hervorragend knappen Register kaum was sinnvoll optimieren. Stattdessen haben die Prozessorbauer mittlerweile die Optimierungen eingebaut. Nur mit dieser Strategie war man MS-kompatibel genug bis zurück zur Jungsteinzeit von CP/M-86... HP wundert mich schon eher (zumal es ja hier um PA-RISC geht, also eine Maschine, bei der alles außer optimiertem Code keinen Sinn hat -- denn die Idee hinter RISC war ja, dass man die Optimierung besser dem Compiler überlässt als dem Prozessor), aber trotzdem bleibe ich bei meinen Erfahrungen -- während du nicht nur namenlos bleiben willst, sondern außer einer Behauptung über eine fehlerhafte Codegenerierung für ARM7 hier lediglich andere Meinungen ins Feld führst, um diese dann fundierte Argumentationen zu nennen. Nur zur Erinnerung: angefangen hat das alles damit, dass du 95 % der Bugs, die bei der Optimierung auftreten, den Programmierern zuschlägst, also immerhin 5 % den Compilerbauern, während ich die Wahrscheinlichkeit der Compilerbugs eher im 5N-Bereich sehe (5 Nullen nach dem Komma). Aber da du ja ein Fan von Meinungen anderer Leute zu sein scheinst statt der derjenigen, mit denen du dich gerade unterhälst, hier mal ein Link, der nicht nur meine Meinung bezüglich des Debuggens optimierten Codes unterstützt, sondern auch meine Ansicht über die Wahrscheinlichkeit von Compilerfehlern bestätigt: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=53060#348825 Ich finde es an deinem Diskussionsstil übrigens sehr amüsant, dass du dich zu Dingen, die man dir widerlegt hat (wie den Unterschied zwischen static inline und automatischem Inlining) einfach mal gar nicht mehr äußerst... Da wir uns drastisch vom Urpsrung des Threads weg bewegt haben, werde ich hier maximal noch ein Followup verfassen, danach ist Schluss.
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.