2009-08-06 9 views
14

Cuando estoy depurando algo que sale mal dentro de un bucle, por ejemplo en la iteración número 600, puede ser difícil tener que romper para cada uno. Así que traté de establecer un punto de corte condicional, para romper solo si I = 600. Eso funciona, pero ahora se tarda casi un minuto completo en llegar a ese punto, donde antes era casi instantáneo. ¿Qué está pasando, y hay alguna manera de solucionarlo?¿Por qué los puntos de interrupción condicionales ralentizan tanto mi programa?

Respuesta

1

Los puntos de interrupción condicionales en cualquier depurador (estoy suponiendo aquí) requieren que el proceso se mueva hacia atrás y hacia adelante cada vez entre su programa y el depurador cada vez que se golpea el punto de interrupción. Este proceso lleva mucho tiempo, pero no creo que haya nada que puedas hacer.

22

Cuando llega a un punto de interrupción, Windows detiene el proceso y notifica al depurador. Tiene que cambiar contextos, evaluar la condición, decidir que no, no desea que se le notifique, reiniciar el proceso y volver atrás. Eso puede tomar muchos ciclos de procesador. Si lo haces en un circuito cerrado, tomará un par de órdenes de magnitud más de ciclos de procesador que una iteración del ciclo.

Si está dispuesto a meterse con su código un poco, hay una manera de hacer puntos de interrupción condicionales sin incurrir en todos estos gastos generales.

if <condition here> then 
    asm int 3 end; 

Ésta es una instrucción de montaje sencillo que envía manualmente una notificación punto de interrupción en el sistema operativo. Ahora puede evaluar su condición dentro del programa, sin cambiar contextos. Solo asegúrate de volver a sacarlo cuando termines con él. Si un int 3 se activa dentro de un programa que no está conectado a un depurador, se generará una excepción.

+0

Me figuré tanto jajaja pero lo ha dicho mejor. –

+0

Mason: buen resumen; ten en cuenta que es fácil dejar algunas de estas construcciones en el código. Así que sugiero que se haga con algunas observaciones (utilizo algo con @@@) o macros, que tienen la garantía de no terminar en un producto real. – Adriaan

+0

Esto está etiquetado como Delphi, que no tiene macros de preprocesador o @@@ observaciones. Una forma sencilla de asegurarse de no dejar ninguno es grep su base de código para "int 3" antes de crear una versión de lanzamiento. –

0

Normalmente, los puntos de interrupción funcionan insertando la instrucción de interrupción apropiada en el código y luego verificando las condiciones que ha especificado. Verificará en cada iteración y bien podría ser que la forma en que se implementa el cheque sea responsable de la demora, ya que es poco probable que el depurador compile e inserte el código completo de verificación y punto de interrupción en el código existente.

Una forma en que puede acelerar esto es si pone la condición seguida de una operación sin efectos secundarios en el código directamente y rompe esa operación. Solo recuerde eliminar la condición y la operación cuando haya terminado.

+0

Probablemente no sea la comprobación condicional en sí misma, sino los cambios de contexto y la sobrecarga de detener y reiniciar el proceso. No se da cuenta de que con un punto de interrupción normal ya que aterriza en el depurador de todos modos, pero en un punto condicional donde continúa, se vuelve muy aparente muy rápidamente. –

6

Se ralentiza porque cada vez que llega a ese punto, tiene que verificar su condición.

Lo que suelo hacer es crear temporalmente otra variable como esta (en C pero debería ser posible en Delphi).

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

entonces puse un punto de interrupción no condicional en la línea "xyzzynum = xyzzynum;".

El programa se ejecuta a toda velocidad hasta que ha pasado por el bucle 600 veces, porque el depurador está haciendo una interrupción de punto de interrupción normal en lugar de comprobar las condiciones todo el tiempo.

Puede hacer que la condición sea tan complicada como desee.

+0

+1 En este caso, el operador probablemente podría usar algo simple como si I = 600 y luego escribir; y poner un punto de interrupción en la cláusula de escritura. –

+0

+1 para la referencia Colosal Caves. : D –

3

Las explicaciones de Mason son bastante buenas.
Su código se podría hacer un poco más seguro por la prueba que se ejecuta en el depurador:

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

Esto no va a hacer nada cuando la aplicación se está ejecutando normalmente y se detendrá si se está ejecutando en el depurador (ya sea lanzado desde el IDE o conectado al depurador).
Y con el acceso directo booleano <your specific condition here> ni siquiera se evaluará si no está bajo el depurador.

+0

Y también dará [Advertencia Pascal] Dist.dpr (72): W1002 El símbolo 'DebugHook' es específico de una plataforma, lo que facilita su búsqueda antes del check in. –

4

con la respuesta de Mason, que podría hacer que el int 3 Assember sólo puede ser compilado en si el programa está construido con la depuración condicional definido:

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

lo tanto, cuando se está depurando en el IDE, usted tiene el condicional de depuración en las opciones del proyecto. Cuando construyes el producto final para tus clientes (¿con tu script de compilación?), No incluirías ese símbolo, por lo que no se compilará.

También incluí la directiva del compilador de $ mensajes, por lo que verás un advertencia cuando compila, haciéndole saber que el código aún está allí. Si haces eso en cualquier lugar donde uses int 3, entonces tendrás una buena lista de lugares en los que puedes hacer doble clic para llevarte directamente al código ofensivo.

N @

Cuestiones relacionadas