More off-road monster truck madness: How to read a VS Profiler (vsp) file programmatically

Happy New Year!  Thought I'd start the new year with some more off-road fun on how to interact with the diagnostic components in VS.

 People have often asked me "what is the format for a VSP file John".  The answer is "it depends".  That sounds a bit glib, but realistically, the VSP is too raw for most people to get any value out of.  It contains the blobs of data that we have read at profile time, and varies in format depending on profile type used. It has not done any analysis of what the data means and does not contain any symbolic information (i.e. no names of functions or classes).  To make sense of it, you'd really have to duplicate our analysis engine, which seems kinda pointless.  The analysis basically has two major outputs:

1) An ADO.Net dataset with the aggregate tables like function, module, type

2) A calltree that gets represented in the call tree view

In future we hope to build a real extensibility and automation model that is fully supported, but for the moment let me mirror what I did with code coverage in previous articles but in a much shorter way.  Note, this is using VS2008 bits.  This was not available in VS2005, we essentially re-architected the engine in VS2008 to set us up to provide richer extensibility.  Here's a code snippet to read a VSP and print the methods from the method table. 

using System;

using System.Collections.Generic;

using System.Text;

// There are actually 4 references you will need to add to

// your project that includes this code :

// VSPerfPresentation, VSPerfAnalysis, VSPerfData, VSPerfReader

using VSPerfPresentation;

using VSPerfAnalysis;

using VSPerfReader;

namespace VSPMethodDump

{

    class VSPMethodDump

    {

        string _filename;

        ProfileDataProvider _pdp;

        // A simple method dumper program that dumps profiler data for all the

        // methods/functions in a VSP file

        static void Main(string[] args)

        {

            VSPMethodDump vmd = new VSPMethodDump(args[0]);

            vmd.Dump();

        }

        VSPMethodDump(string filename)

        {

            _filename = filename;

            // The ProfileDataProvider class is the class that allows

            // reading and analysis of profiler data in VSP files

            // First parameter is a reghive for when PDP is working inside VS

       ProfileDataProvider.Initialize(null);

            _pdp = new ProfileDataProvider();

        }

        void Dump()

        {

            // The option store gives a variety of ways for analysis

            // to be performed on the target file. We'll keep it to a simple

            // Function summary

            VSPerfAnalysis.OptionStore ops = new VSPerfAnalysis.OptionStore();

            ops.Clear();

            ops.FunctionSummary = true;

            // Noise reduction is the folding you see in the VS2008 profiler

            _pdp.EnableNoiseReduction = false;

            // Read the file and anlayze. There are certain operations that can

            // be performed after the open step, which is basically a read of the index

            // of the file

            _pdp.OpenFile(_filename, ops);

            _pdp.Analyze();

            // A ProfileDataViewer is a class that allows access to the analyzed data

            // in this case the Function summary, which is the same as the Function view

            // in VS2008. They are pre-populated with a set of default visible columns

            ProfileDataViewer pdv = _pdp.GetViewer("Function");

            WriteHeaders(pdv);

            // A flat provider mimics the flat table view as seen in the profiler. Others

            // are available when the view is more tree like, e.g. CallTree

            IFlatProfileViewer flat = pdv as IFlatProfileViewer;

            // Each IProfileRow has the data for a given method/function in this example

     IList<IProfileRow> rows = flat.GetRows();

            foreach (IProfileRow row in rows)

            {

                WriteRow(row,pdv);

            }

            // Close is needed to ensure proper closure of symbol files and files

            _pdp.Close();

        }

        void WriteHeaders(ProfileDataViewer viewer)

        {

            // As well as visible columns you can inspect AvailableColumns to see

            // what could be written here. If you want to write said columns, they

       // need to be turned visible by updating the "Visible" property

            for (int i = 0; i < viewer.VisibleColumns.Count; i++)

            {

                string colString = viewer.VisibleColumns[i].MediumName;

                Console.Write(colString + ",");

            }

            Console.WriteLine();

        }

        void WriteRow(IProfileRow row, ProfileDataViewer viewer)

        {

            for (int i = 0; i < viewer.VisibleColumns.Count; i++)

            {

                string colString = viewer.GetText(row, i);

                Console.Write(colString + ",");

            }

            Console.WriteLine();

        }

    }

}

Sadly I'm not good enough at blogging to have this as an attachment.  Next time out on the ramps, I'll show some other areas of the API that can provide more insight.

Enjoy!

John