SPListAnalysis: A sample DebugDiag v2.0 Analysis Rule

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.

DebugDiag Analysis

DebugDiag Analysis

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("<br/><ul>");
    foreach ( int threadId in threadsWithLargeSPQueries.Keys )
    {
      sb.AppendFormat("<li><a href='#thread{0}'>{0}</a> ({1} fields)</li>",
          threadId, threadsWithLargeSPQueries[threadId]);
    }
    sb.Append("</ul>");
    this.manager.ReportWarning(sb.ToString(), "");
  }
}

The resulting report will look like this:

DebugDiag Warnings

DebugDiag Warnings

Enjoy!

1 comment

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>