Ist es wirklich eine gute Praxis zu deaktivieren Optimierungen bei der Entwicklung und Debugging-Phasen?


15

Ich habe Programmieren von 16-Bit-PIC-Mikrocontrollern in C gelesen und es gibt diese Bestätigung im Buch:

Bei der Entwicklung und Debugging-Phasen eines Projektes, ist es allerdings immer gute Praxis alle Optimierungen zu deaktivieren, da sie die Struktur des Codes ändern könnten werden Single-Stepping und Breakpoint-Platzierung problematisch analysiert und rendern.

Ich gestehe, ich war ein bisschen verwirrt. Ich habe nicht verstanden, ob der Autor dies aufgrund des C30- Evaluierungszeitraums gesagt hat oder ob es wirklich eine gute Praxis ist.

Ich würde gerne wissen, ob Sie tatsächlich diese Praxis verwenden, und warum?

Antworten:


16

Das ist ziemlich Standard in der Softwareentwicklung als Ganzes - wenn Sie Code zu optimieren, wird der Compiler erlaubt, die Dinge neu ordnen ziemlich aber es will, solange man keinen Unterschied in Betrieb berichten. So zum Beispiel, wenn Sie eine Variable innerhalb jeder Iteration einer Schleife zu initialisieren, und nie die Variable innerhalb der Schleife ändern, wird der Optimierer, dass die Initialisierung aus der Schleife bewegen kann, so dass Sie nicht Zeit damit verschwenden.

Es kann auch vorkommen, dass Sie eine Zahl berechnen, mit der Sie dann nichts mehr tun, bevor Sie sie überschreiben. In diesem Fall könnte es die nutzlose Berechnung beseitigen.

Das Problem mit der Optimierung ist, dass Sie auf einige Stück Code einen Haltepunkt setzen wollen werden, die der Optimierer bewegt hat oder eliminiert. In diesem Fall kann der Debugger nicht tun, was Sie wollen (in der Regel wird es den Haltepunkt irgendwo in der Nähe setzen). Also, um den generierten Code stärker ähneln, was Sie geschrieben, Sie deaktivieren Optimierungen während debug - Dies stellt sicher, dass der Code, den Sie brechen auf wirklich wollen, gibt es.

Sie müssen jedoch vorsichtig sein, da die Optimierung je nach Code zu Problemen führen kann! Im allgemeinen Code, der von einem korrekt funktionierenden Optimierer gebrochen ist wirklich nur Buggy-Code, der mit etwas entkommt, so dass Sie in der Regel, warum der Optimierer bricht es herauszufinden wollen.


5
Der Kontrapunkt zu diesem Argument ist , dass das Optimierungsprogramm wird wahrscheinlich Dinge kleiner und / oder schneller machen, und wenn Sie Timing oder Größe beschränkt Code haben , dann können Sie etwas brechen durch die Optimierung deaktivieren und Ihre Zeit Debuggen ein Problem , dass doesn‘ t wirklich existieren. Natürlich kann der Debugger Code langsamer und größer sowie machen.
Kevin Vermeer

Wo kann ich mehr darüber erfahren?
Daniel Grillo

Ich habe nicht mit dem C30 - Compiler , aber für den C18 - Compiler gibt es eine App Notiz / Handbuch für den Compiler gearbeitet , die abgedeckt , welche Optimierungen sie unterstützten.
Mark

@O Engenheiro: Überprüfen Sie Ihre Compiler - Dokumentation für das, was Optimierungen unterstützt wird . Die Optimierung ist je nach Compiler, Bibliotheken und Zielarchitektur sehr unterschiedlich.
Michael Kohne

Auch nicht für den C30 - Compiler, aber gcc veröffentlicht eine lange Liste der verschiedenen Optimierungen, die angewendet werden können. Sie können diese Liste auch verwenden, um eine detaillierte Optimierung zu erhalten, falls Sie eine bestimmte Kontrollstruktur haben, die Sie beibehalten möchten. Die Liste ist hier: gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
Kevin Vermeer

7

Ich habe diese Frage an Jack Ganssle gesendet und er hat mir Folgendes geantwortet:

Daniel,

Ich ziehe es zu debuggen, was Optimierungen unter Verwendung von in dem freigegebenen Code sein wird. NASA sagt „Test, was Sie fliegen, fliegen, was Sie zu testen.“ Mit anderen Worten, nicht tun zu testen und dann den Code ändern!

Manchmal muss man jedoch Optimierungen deaktivieren, damit der Debugger funktioniert. Aus diesem Grund glaube ich daran, Dateien klein zu halten, sagen wir ein paar hundert Codezeilen oder so.

All the best, Jack


Ich denke , es gibt eine unausgesprochene Unterscheidung zwischen den beiden Absätzen in dieser Antwort. Prüfung bezieht sich auf ein Verfahren , das beweisen sollte , dass die weiche, feste und / oder harte Ware ordnungsgemäß funktionieren. Das Debuggen ist der Prozess, bei dem der Code Anweisungen für Anweisungen durchlaufen wird, um festzustellen, warum er [noch] nicht funktioniert.
Kevin Vermeer

Es ist schön , eine Wahl zu haben. So kann der Test mehr Sorten / Permutationen deckt mit und ohne Optimierung. Mehr der Abdeckung wird die bessere Prüfung

@reemrevnivek, wenn Sie das Debuggen, nicht testen Sie auch?
Daniel Grillo

@O Engenheiro - Nein , ich debuggen nur , wenn der Test nicht bestanden .
Kevin Vermeer

6

Abhängt, und dies ist in der Regel gilt für alle Werkzeuge nicht nur C30.

Optimierungen oft entfernen und / oder Umstrukturierung des Codes auf verschiedene Weise. Ihre switch-Anweisung kann mit einem, wenn / else Konstrukt oder in einigen Fällen neu implementiert bekommen werden alle zusammen entfernt. y = x * 16 kann mit einer Reihe von Linksverschiebungen ersetzt bekommen, usw., obwohl diese letzte Art der Optimierung in der Regel nach wie vor durch verstärkt werden kann, seine meist die Umstrukturierung der Steueranweisung, ya bekommt.

Dies kann es unmöglich machen, einen Debugger durch Ihren C-Code zu führen, da die von Ihnen in C definierten Strukturen nicht mehr existieren. Sie wurden vom Compiler ersetzt oder neu angeordnet, sodass der Compiler der Ansicht ist, dass sie schneller sind oder weniger Speicherplatz beanspruchen. Es kann auch Ihr Bruch auf, nicht länger besteht, da die Anweisung Auflistung Stützpunkte unmöglich Satz aus dem C machen. Zum Beispiel können Sie versuchen, einen Haltepunkt in einer if-Anweisung zu setzen, aber der Compiler entfernt haben kann, dass, wenn. Sie können versuchen, einen Haltepunkt innerhalb einer while- oder for-Schleife zu setzen, aber der Compiler hat beschlossen, diese Schleife zu entrollen, damit sie nicht mehr existiert.

Aus diesem Grund können , wenn Sie mit Optimierungen debuggen aus, seine in der Regel einfacher. Sie sollten immer Retest mit Optimierungen auf. Dies ist über die einzige Art und Weise werden Sie feststellen , dass Sie einen wichtigen verpasst volatileund seine was zu sporadischen Ausfällen (oder eine andere Seltsamkeit).

Im Fall der Embedded-Entwicklung, müssen Sie auf jeden Fall mit Optimierungen vorsichtig sein. Speziell in Codeabschnitten, das Timing kritisch, einige Interrupts zum Beispiel. In diesen Fällen sollten Sie entweder Code der kritischen Bits in der Montage oder Richtlinien Verwendung Compiler um sicherzustellen, dass diese Abschnitte nicht optimiert werden, so dass Sie wissen, dass sie eine feste Ausführungszeit oder eine Worst-Case-Laufzeit festgelegt.

Der andere gotcha kann Code in das uC werden passend, können Sie Codedichte Optimierungen müssen einfach den Code in den Chip passen.


5

Wenn ich optimierten Code veröffentlichen würde, würde ich mit optimierten Code debuggen. Wenn ich nicht optimierten Code veröffentlichen würde, würde ich mit nicht optimierten Code debuggen. Ich tue dies aus zwei Gründen. Erstens kann Optimizern signifikant genug Timing Unterschiede machen das Endprodukt verursachen anders als nicht optimierte Code zu verhalten. Zweitens, obwohl die meisten sind ziemlich gut, Compiler-Anbieter tun machen Fehler und optimierten Code unterschiedliche Ergebnisse aus nicht optimierten Code erzeugen. Als Ergebnis, wie ich mit so viel Testzeit wie möglich zu bekommen, was Einstellung, ich plane, mit zu lösen.

Davon abgesehen, können Optimizern schwierig machen, das Debuggen, wie in den vorherigen Antworten zur Kenntnis genommen. Wenn ich einen bestimmten Codeabschnitt finden, die schwer zu debuggen ist, werde ich vorübergehend das Optimierungsprogramm deaktivieren, führen Sie die Debuggen den Code zum Laufen zu bringen, dann drehen Sie den Optimierer wieder auf und testen Sie noch einmal.


1
Aber Einzelschritt kann der Code fast unmöglich sein , mit Optimierungen eingeschaltet. Debug mit Optimierungen aus, und die Komponententests mit Release - Code ausführen.
Rocketmagnet

3

Meine normale Strategie ist mit der endgültigen Optimierung (max für Größe oder Geschwindigkeit je nach Fall), sondern spiegeln die Optimierung off vorübergehend zu entwickeln, wenn ich ot Spur etwas debuggen müssen. Dies reduziert das Risiko von Fehlern infolge Oberflächenoptimierungsstufen zu ändern.

Ein typischer Fehlermodus ist, wenn zunehmende Optimierung bisher unbekannte Bugs Oberfläche verursacht aufgrund Sie nicht als flüchtigen deklarierten Variablen mit, wo erforderlich - dies ist wichtig, den Compiler zu sagen, welche Dinge sollen nicht ‚optimierten‘ werden.


2

Verwenden Sie jedes Formular, mit dem Sie veröffentlichen möchten, Debugger und Kompilierer zum Debuggen, um eine Menge (VIELE) Fehler zu verbergen, die Sie erst sehen, wenn Sie für die Veröffentlichung kompilieren. Bis dahin ist es viel schwieriger, diese Fehler zu finden, als das Debuggen, während Sie gehen. 20 etwas Jahre und ich nie eine Verwendung für ein GDB oder andere wie Debugger hatte, keine Notwendigkeit, Variablen oder einzelnen Schritt zu beobachten. Hunderttausende von Zeilen pro Tag. Es ist also möglich, dass Sie nicht dazu gebracht werden, etwas anderes zu denken.

Das Kompilieren für das Debuggen und das spätere Kompilieren für die Veröffentlichung kann und wird den doppelten bis mehr als doppelten Aufwand erfordern. Wenn Sie in einen Bind geraten und ein Tool wie einen Debugger verwenden müssen, kompilieren Sie, damit der Debugger das spezifische Problem löst, und kehren Sie dann zum normalen Betrieb zurück.

Andere Probleme sind auch wahr, wie der Optimierer des Code macht so schneller für insbesondere Ihr Timing Änderungen mit Compiler-Optionen eingebettet und dass die Funktionalität des Programms beeinflussen kann, benutzen Sie wieder die zu liefernde Compilierung Wahl während der gesamten Phase. Compiler sind ebenfalls Programme und haben Bugs und Optimierer, die Fehler machen, und manche glauben nicht daran. Wenn das der Fall ist, gibt es nichts falsch mit ihm ohne Optimierung kompilieren, es einfach so tut die ganze Zeit. Der von mir bevorzugte Pfad ist die Kompilierung für die Optimierung. Wenn ich ein Compilerproblem vermute, deaktivieren Sie die Optimierung, wenn dies das Problem behebt. Gehen Sie in der Regel hin und her und überprüfen Sie manchmal die Assembler-Ausgabe, um herauszufinden, warum.


1
1 nur auf Ihrer gute Antwort zu erarbeiten: oft in „debug“ Modus Pad , um den Stapel / Haufen um Variablen mit nicht zugewiesenen Raum Kompilieren eher kleine Ausbuchung-the-Ende und Format - String - Fehler zu mildern. Sie erhalten häufiger eine gute Laufzeit Absturz , wenn Sie in Release kompilieren.
Morten Jensen

2

Ich entwickle immer Code mit -O0 (gcc Option aktivieren Optimierung off). Wenn ich das Gefühl habe, an dem Punkt angelangt zu sein, an dem ich die Dinge mehr auf ein Release zusteuern lassen möchte, beginne ich mit -Os (für die Größe optimieren), da es im Allgemeinen umso besser ist, je mehr Code im Cache gespeichert werden kann. auch wenn es nicht super-duper optimiert ist.

Ich finde, dass gdb funktioniert viel besser mit -O0 Code, und es ist viel einfacher zu folgen, wenn Sie Schritt in die Baugruppe haben. Hin- und Herschalten zwischen -O0 und -Os können Sie auch sehen, was der Compiler Code tut. Es ist zuweilen eine ziemlich interessante Ausbildung und kann auch Compiler-Bugs aufdecken ... diese fiesen Dinge, die Sie dazu bringen, sich die Haare auszureißen und herauszufinden, was mit Ihrem Code nicht stimmt!

Wenn es wirklich nötig ist, füge ich in -fdata-Abschnitten und -fcode-Abschnitten --gc-Abschnitte hinzu, mit denen der Linker ganze Funktionen und Datensegmente entfernen kann, die eigentlich nicht verwendet werden. Es gibt viele kleine Dinge, die Sie mit basteln können, um zu versuchen die Dinge weiter nach unten oder den Dingen schneller schrumpfen, aber im Großen und Ganzen diese die einzigen Tricks sind mit ich am Ende, und alles, was kleiner oder schneller sein muß ich die Hand -montieren.


2

Ja, das Deaktivieren von Optimierungen während des Debuggens hat sich aus drei Gründen seit einiger Zeit bewährt:

  • (A), wenn Sie Single-Step fahren, um das Programm mit einem High-Level-Debugger, dann ist es etwas weniger verwirrend.
  • (A) (veraltet), wenn Sie mit einem Assemblersprachen- Debugger einstufiges Debug das Programm fahren zu, es ist viel weniger verwirrend. (Aber warum sollten Sie sich darum kümmern, wenn Sie einen High-Level-Debugger verwenden könnten?)
  • (B) (lange veraltet) wirst du wahrscheinlich nur diese bestimmte ausführbare Datei ausführen einmal, dann etwas ändern und neu kompilieren machen. Es ist eine Verschwendung von Zeit Person um weitere 10 Minuten zu warten, während der Compiler „optimiert“ diese besonderen ausführbar, wenn das wird weniger als 10 Minuten Laufzeit zu sparen. (Dies ist nicht mehr relevant mit modernen PCs, die einen typischen Mikrocontroller ausführbar, mit voller Optimierung, in weniger als 2 Sekunden kompilieren können).

Viele Menschen gehen sogar noch weiter in dieser Richtung, und Schiff mit Behauptungen eingeschaltet .


Single-Stepping durch Assembler - Code kann zur Diagnose von Fällen sehr nützlich sein , wenn der Quellcode gibt tatsächlich etwas anderes als das, was es sieht aus wie (zB „longvar1 & = ~ 0x40000000; longvar2 & = ~ 0x80000000;“) , oder wenn ein Compiler generiert fehlerhaften Code . Ich habe einige Probleme aufgespürt mit Maschinencode - Debugger , die ich glaube nicht , dass ich wirklich nach unten auf andere Weise verfolgt haben könnte.
supercat

2

Ganz einfach: Optimierungen sind zeitintensiv und kann nutzlos sein , wenn Sie dieses Stück Code ändern müssen , um später in der Entwicklung. So können sie auch eine Verschwendung von Zeit und Geld.
Sie sind jedoch für fertige Module nützlich. Teile des Codes, die wahrscheinlich keine Änderungen mehr benötigen.


2

sicherlich macht es Sinn, im Fall von Bruchstellen ... wie die Compiler viele Aussagen entfernen, die nicht wirklich Memory-Effekt zu tun.

Sehen Sie so etwas wie:

int i =0;

for (int j=0; j < 10; j++)
{
 i+=j;
}
return 0;

vollständig optimiert werden kann (weil inicht immer lesen). es aus der Sicht des Breakpoint aussehen würde , dass es all dieser Codes übersprungen, wenn es im Grunde war einfach gar nicht da .... gehe ich davon aus, dass bin , warum in Funktionen Schlaf Typ oft Sie so etwas wie sehen:

for (int j=delay; j != 0; j--)
{
    asm( " nop " );
    asm( " nop " );
}
return 0;

1

Wenn Sie den Debugger verwenden, dann würde ich Optimierungen deaktivieren und zu debuggen aktivieren.

Persönlich finde ich , dass die PIC - Debugger mehr Probleme verursacht , als es hilft mir zu beheben.
Ich benutze nur printf () zu USART meine Programme in C18 geschrieben zu debuggen.


1

Die meisten Argumente gegen ermöglicht Optimierung in Ihrer Compilierung kommen auf:

  1. Probleme beim Debuggen (JTAG-Konnektivität, Haltepunkte usw.)
  2. falsche Software Timing
  3. sh * t nicht mehr funktioniert richtig

IMHO die ersten beiden sind echt, die dritte nicht so sehr. Es bedeutet oft Sie einige schlechte Code haben oder auf unsichere Ausbeutung der Sprache / Implementierung setzen oder vielleicht der Autor ist nur ein Fan von guten alten Onkel nicht definiertes Verhalten.

Der Embedded in Academia Blog hat ein oder zwei Dinge über zu undefiniertem Verhalten zu sagen, und dieser Beitrag ist, wie Compiler auszubeuten: http://blog.regehr.org/archives/761


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.