Quando eseguo il debug di qualcosa che va storto all'interno di un loop, diciamo sulla 600esima iterazione, può essere un dolore dover rompere per ognuno. Così ho provato a impostare un breakpoint condizionale, per interrompere solo se I = 600. Funziona, ma ora ci vuole quasi un minuto intero per raggiungere quel punto, dove prima era quasi istantaneo. Cosa sta succedendo e c'è un modo per risolverlo?Perché i breakpoint condizionali rallentano così tanto il mio programma?
risposta
I punti di interruzione condizionale in qualsiasi debugger (sto solo ipotizzando qui) richiedono che il processo si capovolga avanti e indietro ogni volta tra il programma e il debugger ogni volta che viene colpito il punto di interruzione. Questo processo richiede molto tempo, ma non penso che ci sia qualcosa che puoi fare.
Quando si preme un punto di interruzione, Windows arresta il processo e notifica il debugger. Deve cambiare contesto, valutare la condizione, decidere che no, non si vuole essere avvertiti, riavviare il processo e tornare indietro. Ciò può richiedere molti cicli del processore. Se lo stai facendo in un circuito chiuso, ci vorranno un paio di ordini di grandezza in più cicli del processore rispetto a una singola iterazione del ciclo.
Se sei disposto a fare confusione con il tuo codice un po ', c'è un modo per fare i breakpoint condizionali senza incorrere in tutto questo sovraccarico.
if <condition here> then
asm int 3 end;
Si tratta di una semplice istruzione di montaggio che invia manualmente una notifica punto di interruzione per il sistema operativo. Ora puoi valutare la tua condizione all'interno del programma, senza cambiare contesto. Assicurati di estrarlo di nuovo quando hai finito. Se un int 3 si spegne all'interno di un programma che non è collegato a un debugger, solleverà un'eccezione.
In genere i punti di interruzione delle condizioni funzionano inserendo l'istruzione di interruzione appropriata nel codice e quindi controllando le condizioni specificate. Controllerà ad ogni iterazione e potrebbe essere che il modo in cui viene implementato il controllo sia responsabile del ritardo poiché è improbabile che il debugger compili e inserisca il codice completo di controllo e interruzione nel codice esistente.
Un modo in cui si potrebbe essere in grado di accelerare questo è se si inserisce la condizione seguita da un op senza alcun effetto collaterale nel codice direttamente e si interrompe su tale operazione. Ricordati di rimuovere la condizione e l'operazione quando hai finito.
Probabilmente non è il controllo condizionale stesso, sono gli switch di contesto e il sovraccarico di arresto e riavvio del processo. Non ti accorgi che con un normale punto di interruzione, dal momento che atterri comunque nel debugger, ma su un condizionale in cui continua ad andare avanti diventa molto evidente molto rapidamente. –
Rallenta perché ogni volta che raggiungi quel punto, deve controllare le tue condizioni.
Quello che tendo a fare è creare temporaneamente un'altra variabile come questa (in C ma dovrebbe essere fattibile in Delphi).
int xyzzynum = 600;
while (true) {
doSomething();
if (--xyzzynum == 0)
xyzzynum = xyzzynum;
}
poi ho messo un punto di interruzione non condizionale sulla linea "xyzzynum = xyzzynum;"
.
Il programma funziona a piena velocità fino a quando non ha attraversato il ciclo 600 volte, poiché il debugger esegue semplicemente un normale interrupt di breakpoint anziché controllare le condizioni ogni volta.
È possibile rendere la condizione complicata come si desidera.
+1 In questo caso l'op probabilmente potrebbe usare qualcosa di semplice come se I = 600 poi scrivesse; e inserire un punto di interruzione nella clausola di scrittura. –
+1 per il riferimento delle grotte colossali. : D –
Le spiegazioni di Mason sono abbastanza buone.
suo codice potrebbe essere fatto un po 'più sicuro dai test che si esegue nel debugger:
if (DebugHook <> 0) and <your specific condition here> then
asm int 3 end;
Questo non farà nulla quando l'applicazione è in esecuzione normalmente e si arresta se è in esecuzione nel debugger (se lanciato dall'IDE o collegato al debugger).
E con il collegamento booleano <your specific condition here>
non verrà nemmeno valutato se non si è nel debugger.
E fornirà anche [Pascal Warning] Dist.dpr (72): W1002 Symbol 'DebugHook' è specifico per una piattaforma - rendendoli facili da trovare prima del check in. –
seguito alla risposta di Mason, si potrebbe creare l'int 3 assember essere compilato solo se il programma è costruito con debug condizionale e definita:
{$ifdef debug}
{$message warn 'debug breakpoint present in code'}
if <condition here> then
asm int 3 end;
{$endif}
Così, quando si esegue il debug nell'IDE, avete il debug condizionale nelle opzioni del progetto. Quando costruisci il prodotto finale per i tuoi clienti (con lo script di compilazione?), Non includeresti quel simbolo, quindi non verrà compilato.
Ho anche incluso la direttiva del compilatore $ message, quindi vedrai un avviso quando compili facendoti sapere che il codice è ancora lì. Se lo fai ovunque usi int 3, avrai quindi una bella lista di luoghi che puoi fare doppio clic per portarti direttamente al codice incriminato.
N @
ho pensato tanto lol ma hanno detto meglio. –
Mason: buon riassunto; fai attenzione però che è facile lasciare alcune di queste costruzioni nel codice. Quindi suggerisco che sia fatto con alcune osservazioni (io uso qualcosa con @@@) o macro che sono garantite per non finire in un prodotto reale. – Adriaan
Viene contrassegnato come Delphi, che non dispone di macro del preprocessore o di commenti @@@. Un modo semplice per essere sicuri di non lasciarne alcuno è di svuotare il codice base per "int 3" prima di creare una versione di rilascio. –