DebugDiag is a tool for collecting and
analyzing memory dumps. Version 2.0 was just
released and makes it extremely easy to write your own custom analysis rules using any language
that target the CLR.

SPListAnalysis is a sample analysis rule I implemented to show the basic steps involved in the process.
The rule does the following:

  • Iterates over all threads found in the process dumps to identify any threads that are
    querying an SPList object (or causing it to load the items contained therein).
  • Identifies the CAML
    query associated with the operation.
  • Generates a warning if the query contains more than 10 fields, loads all the fields in the list,
    or if the query fails to specify a RowFilter.
  • Prints the stack traces and query details for each matching thread.

The code for this sample can be found here.

This particular sample if very simple, consisting of a single class called SPListAnalysis,
which implements the IHangDumpRule interface to process one dump at a time. It also implements the
IAnalysisRuleMetadata interface to define the category and description for this analysis.

[caption id="attachment_1371" align="alignnone" width="755"]DebugDiag Analysis DebugDiag Analysis[/caption]

The basis for the analysis is looking at all threads that contain a significant function in the
call stack, and then looking for a matching object in the stack frames (similar to doing a !DumpStackObjects)
command):

private void RunSPListAnalysis(NetDbgObj debugger)
{
// initialize report
foreach ( var thread in debugger.Threads )
{
AnalyzeThread(thread);
}
// report findings
}

private void AnalyzeThread(NetDbgThread thread)
{
// ...
if ( ContainsFrame(thread, SPLIST_FILL_FRAME) )
{
//...
dynamic obj = thread.FindFirstStackObject("Microsoft.SharePoint.SPListItemCollection");
if ( obj != null )
{
String viewXml = (string)obj.m_Query.m_strViewXml;
//...
XDocument doc = XDocument.Parse(viewXml);
AnalyzeViewXml(thread, doc);
//...
}
PrintThreadStack(thread);
}
}

Reporting the results is mostly a matter of generating HTML. However, we can also generate
warnings that are included at the top of the report, allowing us to quickly alert the user
that something of interest was found in the dump:

private void ReportThreadsWithLargeSPQueries()
{
if ( threadsWithLargeSPQueries.Count > 0 )
{
StringBuilder sb = new StringBuilder();
sb.Append("The following threads appear to be executing SPList queries requesting many fields.");
sb.Append("
    ");
    foreach ( int threadId in threadsWithLargeSPQueries.Keys )
    {
    sb.AppendFormat("
  • {0} ({1} fields)
  • "
    ,
    threadId, threadsWithLargeSPQueries[threadId]);
    }
    sb.Append("
"
);
this.manager.ReportWarning(sb.ToString(), "");
}
}

The resulting report will look like this:

[caption id="attachment_1372" align="alignnone" width="691"]DebugDiag Warnings DebugDiag Warnings[/caption]

Enjoy!


Tomas Restrepo

Software developer located in Colombia.