Performance on MDbg Step and Break function

Each time I issue a break command on MDbg process, it takes about 120 to 300ms for the operation to complete on my machine. Why it takes that much time to break the debuggee What determine the time for the operation to complete Would it be the number of thread the process has, the context the debuggee is executing, or it is the implementation of MDbg break function


Currently, I am trying to design an extension which give the user more control on thread level debugging. These threads do not share any resource so technically stepping though a thread shouldn't affect the other thread. This is done by stopping the debugee process, performs a debug operation, suspends the debugging thread and resume the non-debugging threads. I am hoping to minimize the performance impact on the non-debugging thread when the user stepping though the debugging thread.

Thanks



Answer this question

Performance on MDbg Step and Break function

  • Nonu_k

    What you're trying to do is very cool; but I have to warn you that it's using ICorDebug in a way that has not been well trodden.

    What exactly do you mean by MDbg's break function Hitting a breakpoint Calling ICorDebugProcess::Stop

    Re Break: Sending managed debug events is relatively expensive. It requires:
    1) interprocess communication to send a event from debuggee to debugger
    2) stopping the debuggee so that it's in a stable state to inspect it. This is cheap with 1 thread; but it becomes more expensive with more threads.
    3) having the debugger handle the event, and thus pay some overhead in the debugger process. Mdbg's handlers are not optimized at all.
    4) having the debugger continue to debuggee from step 2 (and thus doing another interprocess communication)

    In general, debugging events are rare enough that this isn't a problem. The debuggee runs at full speed between events.

    "These threads do not share any resource so technically stepping though a thread shouldn't affect the other thread"
    FWIW, they may share things underneath the covers. For example, generics has code-sharing, where two different generic functions that happen to generate the same code can be shared. If each thread jits such a function, that may be an example of sharing. There could be other CLR internal things that are shared. From a performance perspective, this is important because the CLR debugging services must still be aware of the thread synchronization here.

    One thing to be aware of is that most operations require the debuggee to be stopped. (see http://blogs.msdn.com/jmstall/archive/2006/03/22/att_macros.aspx ). So suspending a thread and resuming the process isn't enough to let you inspect that thread while the rest of the process is running. (Some of the internal CLR sharing issues are part of the technical reason for this limitation). I guess you've hit that problem, and are stopping (async-break) the debuggee before each time you want to do such inspection; and now noticing the perf hit of stopping



  • ron nash

    Thank you for the insightful info. This helps me understand more how the debugger work.

    There seem to be a number of places in MDbg where I can optimize. I still have a couple of questions related to performance on MDbg in general.

    I see that MDbgProcess.InternalSignalRuntimeIsStopped() runs Thread.Sleep(100), is there a race condition or other reasons why you need the thread to sleep. I am wondering what would happen if I removed it

    Is it possible to cache MDbgValue variables and MDbgFunction when calling the function evaluation or they have to be re-evaluated everytime

    Right now for realibility reson, I am doing a async-break everytime before executing debug operation. Then once the operation is completed, I then set the thread running state and resume the debuggee. Doing this definately has a perfromance hit. It would be nice can find out which operations I can perform on the suspended thread while the other threads are executing.

    Thanks


  • Lucas Pasquali

    1) That Sleep(100) is embarassing and is on our radar to remove. I'm not sure why it's there.
    2) ICoDebugFunction (and thus MdbgFunction) is safe to cache across continues . ICorDebugValue / MDbgValue in general is not. (see http://blogs.msdn.com/jmstall/archive/2006/03/05/writing_funceval_in_a_debugger.aspx, http://blogs.msdn.com/jmstall/archive/2006/02/08/CORDBG_E_OBJECT_NEUTERED.aspx for details)

    3) Most inspection operations, notably stackwalking, require the debuggee to be stopped. I think you'll either have to always do an async-break; or cache interesting state (especially stackwalks) on the suspended thread when you're stopped and read fromt the cache when the debuggee is running.



  • Performance on MDbg Step and Break function