[MonoDevelop] debug data inspection algorithm [why is it so slow and faulty]

Michael Hutchinson m.j.hutchinson at gmail.com
Thu Jan 26 22:23:36 UTC 2012

On 20 January 2012 16:23, Jonathan Shore <jonathan.shore at gmail.com> wrote:
> Hi,
> I want to know more about the algorithm / approach used in monodevelop when inspecting the value of locals.   The data inspection in MonoDevelop is peculiar in that it is extraordinarily slow.
> Very often the debugger says "Evaluating ...".   Sometimes observing an integer local can take many seconds to come back and other times is more-or-less immediate.    This slows down debugging enormously.
> Worse, sometimes it "gives up" and indicates "Timed out".  The timeouts tend to happen in the context of the debugger attempting to render large data structures or data structures that have a large ToString() representation.   The time to actually generate strings for these structures if often very small, but perhaps the UI has difficulties in digesting.    Once a timeout occurs on one variable, subsequent variables in a view (such as Locals) will also timeout, probably due to an overall time-limit on variable resolution.
> This tends not to happen much with trivial programs, but very often in large codebases.   It makes debugging very painful or in some cases unfeasible such that have to move to windows / visual studio for debugging.    The problem is much worse when attaching to an embedded application via the socket-based protocol (as one might expect).
> What is going on with inspection?  Is it walking the stack for each variable or something like that?    If I understand this better then can offer a "bug" report / feature improvement request that is more finely targetted.

TBH, it is REALLY complicated.

Once the debugger is stopped, at minimum the debugger inspects the
stack locals and any parameters on the stack. It may also have to
inspect objects in referred to by watches or inspection tooltips.
Getting these primitives or object references is very fast. Where it
gets slow is rendering things for displaying them "correctly".

Rendering an object by default requires a ToString invocation, and
rendering a property requires invoking the getter method. If the type
has a DebuggerDisplayAttribute, then rendering it may require property
invocations. These invocations are the things that time out
(MonoDevelop aborts them if they take too long). You can disable
implicit evaluations or change the timeout in the debugger

I would strongly recommend making sure MD and Mono are fully updated
to take advantage of some recent changes we made to batch the transfer
of metadata, to reduce chatter and suspend/resume overhead by only
subscribing to a subset of type load events, and to transfer truncated
values from long strings. I'm not sure offhand whether these were
backported to 2.10.x, they might only be on master.

Here are some other things that could potentially be improved:
* Have MonoDevelop retrieve debugger/type metadata from local copies
of the assemblies, instead of over the wire. We tried this, the gain
over batched metadata didn't seem worth the complexity.
* Batching invocations and value retrieval to reduce wire chatter (for
embedded targets, each TCP request/response could be 10ms).
* Implement a simple IL interpreter so that a subset of methods (e.g.
trivial property getters) could be interpreted client-side instead of
requiring invocation on the target.

Since the debugger is TCP/IP based, you might be able to use a
WireShark trace to figure out exactly what is slow in your case.

Michael Hutchinson

More information about the Monodevelop-list mailing list