Forum: Compiler & IDEs delay.h - Problem beim Debugging


von Denis T. (denist)


Lesenswert?

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?

von Patrick (Gast)


Lesenswert?

Stell uns doch mal Deinen Code zu Verfügung, vielleicht kann man Dir 
dann helfen.

von JojoS (Gast)


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

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 ;)

von JojoS (Gast)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

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.

von JojoS (Gast)


Lesenswert?

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.

von Denis T. (denist)


Lesenswert?

Ich habe Optimierung weggeschaltet. Funktioniert.
Danke)))

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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.

von antworter (Gast)


Lesenswert?

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 :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von antworter (Gast)


Lesenswert?

>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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von antworter (Gast)


Lesenswert?

>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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von antworter (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von antworter (Gast)


Lesenswert?

> 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...

von Törö (Gast)


Lesenswert?

Compilerbauer vs. Mr. Know-it-all, einfach köstlich.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.