Having fun debugging Reporting Services...

Do you know about tracepoints?  They're a way to simulate the effects of a Debug/Trace.WriteLine in your code without actually modifying your source.  They came in handy today when I was debugging an issue in Reporting Services 2005 when rendering the Product Catalog sample report.  The bug is interesting - if I render this report to TIFF via UrlAccess:

https://InfiniteLoop/ReportServer?/Samples/ProductCatalog&rs:Command=Render&rs:Format=IMAGE&rc:OutputFormat=TIFF

I get a TIFF back with 64 pages in it.  However, if I request just the last couple of pages:

https://InfiniteLoop/ReportServer?/Samples/ProductCatalog&rs:Command=Render&rs:Format=IMAGE&rc:OutputFormat=TIFF&rc:StartPage=63&rc:EndPage=64

I get a TIFF with only one page, page 63 as described by the footer, but it contains the correct last few rows of data.  The problem with this second request is obviously that our pagination code behaves different when paginating pages 1-62 without actually drawing them to a surface.

To debug this, I needed to pare down the data or pinpoint the problem area.  I first tried a few quick "top x" additions to the main query and changes to the complexity of the report but didn't come away with a simple enough repro so I changed tactics.  I placed a tracepoint on the method that creates each new table group which output enough data to discover how the group was paginated: an ID, the group label, and the number of rows on the current page.

2007-07-13 TracePoint Definition

I then attached a remote VS debugger to my Yukon SP2 virtual machine and executed both URLs, dumping the results of the Debug Output window to a text file between requests.  Running those through WinDiff made it very clear when pagination started to go wrong.  Everything was the same until here:

2007-07-13 WinDiff Results

Page 5 starts by finishing the Pannier's Accessory group by adding the Touring-Panniers child group to the page.  We then start on the Pumps group by working through its child groups bottom-up.  Both executions add the Mini-Pump child group but notice the red section (rendering the entire report into TIFF) thinks it is out of room on the page and comes back up the Pumps then Accessory group stack while the yellow (partial rendering to TIFF) continues on to the Mountain Pump child group and then moves on to the Tires & Tubes group.  This confirms my earlier diagnosis that pagination was happening differently when the results weren't being rendered to a surface.

I used the same tracepoint technique to check the horizontal start and height information of groups and found that all but the first were different.  Now that I knew where to look and what to look for, stepping through the code to find the cause of the bug was much easier.  In this case, it turned out that we were not taking into account padding on images when we are not rendering to a surface.  Each product image had top padding of 2pt and bottom padding of 4pt and this added up to cause the pagination of later pages to differ.

Since there is at least one easy way to work-around this issue - place the image with zero padding positioned inside of a rectangle - I'm not sure what vehicle this fix will be part of.  It has been fixed indirectly by a reworking of code in this area for our SQL Server 2008 Katmai release.

I enjoy reading other people's debugging tips and tricks and felt it was time to post my own as well as to raise awareness of features (like tracepoints) that serve as useful additions to the bag of tricks of anyone who directly interacts with source code.

Debugging music: Richard Shindell - Courier.