2009-08-06 4 views
14

Wenn ich etwas debugge, das innerhalb einer Schleife falsch läuft, sagen wir auf der 600. Wiederholung, kann es ein Schmerz sein, für jeden brechen zu müssen. Also habe ich versucht, einen bedingten Breakpoint zu setzen, um nur zu brechen, wenn I = 600. Das funktioniert, aber jetzt dauert es fast eine volle Minute, um diesen Punkt zu erreichen, wo es vorher fast augenblicklich war. Was ist los und gibt es einen Weg, es zu reparieren?Warum verlangsamen bedingte Breakpoints mein Programm so sehr?

Antwort

1

Bedingte Breakpoints in jedem Debugger (ich vermute nur hier) erfordern, dass der Prozess jedes Mal zwischen Ihrem Programm und dem Debugger hin und her blättert, wenn der Breakpoint getroffen wird. Dieser Prozess ist zeitaufwendig, aber ich glaube nicht, dass Sie etwas tun können.

22

Wenn Sie einen Haltepunkt treffen, stoppt Windows den Prozess und benachrichtigt den Debugger. Es muss Kontexte wechseln, die Bedingung auswerten, nein entscheiden, nicht darüber informiert werden, den Prozess neu starten und zurückschalten. Dies kann viele Prozessorzyklen erfordern. Wenn Sie es in einer engen Schleife tun, dauert es ein paar Größenordnungen mehr Prozessorzyklen als eine Iteration der Schleife dauert.

Wenn Sie bereit sind, mit Ihrem Code ein wenig zu durcheinander zu kommen, gibt es eine Möglichkeit, bedingte Breakpoints zu erstellen, ohne diesen Overhead zu verursachen.

Dies ist eine einfache Assemblierungsanweisung, die manuell eine Haltepunktbenachrichtigung an das Betriebssystem sendet. Jetzt können Sie Ihre Bedingung innerhalb des Programms auswerten, ohne den Kontext zu wechseln. Stellen Sie sicher, dass Sie es wieder herausnehmen, wenn Sie damit fertig sind. Wenn ein int 3 in einem Programm, das nicht mit einem Debugger verbunden ist, ausgeht, wird eine Ausnahme ausgelöst.

+0

Ich dachte so viel lol, aber Sie haben es besser gesagt. –

+0

Mason: gute Zusammenfassung; Achten Sie jedoch darauf, dass es leicht ist, einige dieser Konstruktionen im Code zu belassen. Also schlage ich vor, dass es mit einigen Bemerkungen gemacht wird (ich verwende etwas mit @@@) oder Makros, die garantiert nicht in einem tatsächlichen Produkt landen. – Adriaan

+0

Dies ist markiert Delphi, die keine Präprozessormakros oder @@@ Bemerkungen hat. Ein einfacher Weg, um sicherzustellen, dass Sie keine in lassen, ist, Ihre Codebase für "int 3" zu grep, bevor Sie eine Release-Version erstellen. –

0

Normalerweise Bedingung Haltepunkte funktionieren, indem Sie die entsprechenden Break-Anweisung in den Code einfügen und dann für die Bedingungen, die Sie angegeben haben. Es wird bei jeder Iteration überprüft und es ist gut möglich, dass die Art und Weise, wie die Überprüfung implementiert wird, für die Verzögerung verantwortlich ist, da es unwahrscheinlich ist, dass der Debugger den vollständigen Prüf- und Haltepunktcode in den vorhandenen Code kompiliert und einfügt.

Ein Weg, den Sie vielleicht beschleunigen können, ist, wenn Sie die Bedingung, gefolgt von einem Op ohne Nebeneffekt in den Code direkt und brechen Sie auf diese Op. Denken Sie daran, den Zustand und die OP zu entfernen, wenn Sie fertig sind.

+0

Es ist wahrscheinlich nicht die bedingte Überprüfung selbst, es sind die Kontextwechsel und der Overhead des Stoppen und Neustarten des Prozesses. Das merkt man bei einem normalen Breakpoint nicht, da man sowieso im Debugger landet, aber bei einer Bedingung, wo es weiterläuft, wird es sehr schnell sehr offensichtlich. –

6

Es verlangsamt es, denn jedes Mal, wenn Sie diesen Punkt erreichen, muss es Ihren Zustand überprüfen.

Was ich tendiere zu tun, ist vorübergehend eine andere Variable wie diese zu erstellen (in C, sollte aber in Delphi machbar sein).

int xyzzynum = 600; 
while (true) { 
    doSomething(); 
    if (--xyzzynum == 0) 
     xyzzynum = xyzzynum; 
} 

dann habe ich einen nicht-bedingten Haltepunkt auf der "xyzzynum = xyzzynum;" Linie.

Das Programm wird mit voller Geschwindigkeit ausgeführt, bis es die Schleife 600 mal durchlaufen hat, da der Debugger nur einen normalen Haltepunkt-Interrupt ausführt, anstatt die Bedingungen jedes Mal zu überprüfen.

Sie können die Bedingung so kompliziert machen, wie Sie möchten.

+0

+1 In diesem Fall könnte die Op wahrscheinlich etwas Einfaches verwenden, wenn I = 600 dann schreibe; und setzen Sie einen Haltepunkt auf die Write-Klausel. –

+0

+1 für die Kolossalhöhle Referenz. : D –

3

Masons Erklärungen sind ziemlich gut.
Sein Code könnte etwas sichere von Tests durchgeführt werden, die Sie unter dem Debugger ausführen:

if (DebugHook <> 0) and <your specific condition here> then 
    asm int 3 end; 

Das wird nichts tun, wenn die Anwendung normal läuft und stoppt, wenn es unter dem Debugger ausgeführt hat (ob es von der IDE gestartet oder an den Debugger angehängt wurde).
Und mit boolescher Verknüpfung <your specific condition here> wird nicht einmal ausgewertet, wenn Sie nicht unter dem Debugger sind.

+0

Und es wird auch geben [Pascal Warning] Dist.dpr (72): W1002 Symbol "DebugHook" ist spezifisch für eine Plattform - so dass sie leicht vor dem Einchecken zu finden. –

4

Weitere Mason Antwort, könnten Sie die int 3 Assember machen nur in kompiliert werden, wenn das Programm mit dem Debug-bedingten definiert aufgebaut ist:

{$ifdef debug} 
{$message warn 'debug breakpoint present in code'} 
if <condition here> then 
    asm int 3 end; 
{$endif} 

Also, wenn Sie in der IDE Debuggen sind, haben Sie die Debug-Bedingung in den Projektoptionen. Wenn Sie das endgültige Produkt für Ihre Kunden erstellen (mit Ihrem Build-Skript?), Würden Sie dieses Symbol nicht einschließen, so dass es nicht kompiliert wird.

Ich habe auch die $ Nachricht Compiler-Direktive, so dass Sie ein sehen Warnung, wenn Sie kompilieren, dass Sie wissen, dass der Code immer noch da ist. Wenn Sie das überall tun, wo Sie Int 3 verwenden, haben Sie dann eine schöne Liste von Orten, auf die Sie doppelklicken können, um direkt zu dem fehlerhaften Code zu gelangen.

N @

Verwandte Themen