Visual Basic Profiler

User Guide Source Back to projects

This VB profiler will help you optimise the performance of middle-tier Visual Basic DLLs running under ASP, Microsoft Transaction Server (MTS) on NT4, and Component Services (COM+) on Windows 2000. It also profiles VB executables (EXEs). It records the number of clock cycles consumed by each Sub, Function and Property. It also counts how many times each method is called.

This is an instrumenting profiler. It works by adding instrumentation to the subject program. Don't be put off though! It doesn't touch your source or even your compiled binaries. Instrumentation is added by patching your code in memory. The runtime overhead is so light you won't notice it.

The profiler was orignally designed to work with MTS. Go here if you wish to profile a VB Form EXE.



Install this DLL in the same MTS package (COM+ application) as your VB component(s).


We'll use this applet to control the profiler.


Place this re-distributable Microsoft DLL in the same folder as the profiler if you have NT4. W2K already includes it.

You also need a way to view Windows debug output, such as DebugView from or DBWIN32 from the NT Resource Kit.


The first step is to re-compile your component(s) with symbolic debugging information. VB will generate a PDB file for each DLL. The profiler needs this information to instrument your code. Just check the box on the Compile tab of project properties and re-compile:

VB6 Project properties dialog

Next, install Profiler.dll in your MTS Package. If your components run under ASP, and you haven't done so already, you'll need to configure your web site to run in a separate memory space (isolated process):

Web site properties

This creates an MTS package with the same name as the web site. Drag and drop Profiler.dll into the IIS package. VB components created by ASP will run in the associated process. You don't need to add them to the package. If your VB components are in another package, deploy Profiler.dll there. If you don't currently use ASP or MTS, create a temporary package for Profiler.dll and your DLLs:


On Windows 2000 you need to make sure the identity of the package is a member of the local machine Administrators group. If the package is running as the interactive user, that means you! The identity of the IIS package will be the Internet Guest Account (IUSR_machinename).


First you need to exercise your application to make sure everything is loaded. You could create a test harness (EXE or ASP) that instantiates the component's of interest. Calling CreateObject() is enough. Alternatively just rehearse the scenario you'll be profiling.

Launch Profiler.exe when you're ready:

Before instrumenting

Enter the path to where the PDB files are located and click Instrument:

After instrumenting

You should see a list of DLLs. Against each, you will see the number of symbols instrumented. Zero means the DLL was not compiled with debugging information or the PDB file could not be found.

The profiler is now logging all Sub, Function and Property calls. Exercise the code of interest. When you're ready to examine the results, launch DBWIN32 or DebugView and click the Report button:


You'll get one line for every symbol reached. I usually Select all, copy and paste into Excel. I then convert the space-delimited data into columns using the Text to Columns wizard:

348: is the process ID inserted by DBWIN32

Here's an Excel macro to automate it:

Sub Profiler_Output_Format()

    Selection.TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, _
        TextQualifier:=xlNone, ConsecutiveDelimiter:=True, Tab:=False, Semicolon _
        :=False, Comma:=False, Space:=True, Other:=False, FieldInfo:=Array( _
        Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1))
    Selection.NumberFormat = "#,##0"
    Columns("E:E").ColumnWidth = 26.71
    Columns("F:F").ColumnWidth = 45.14
    Selection.Sort Key1:=Range("C1"), Order1:=xlDescending, Header:=xlGuess, _
        OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom

End Sub

Interpreting Results

For each method, the profiler reports the number of times it was called and the number of CPU clock cycles consumed by it. The latter is presented inclusive and exclusive of time spent in instrumented sub-methods. I usually want to do a descending sort on the time exclusive column.

The following examples may help to clarify this. Let's say you have two subroutines: Sub1 and Sub2. Sub1 is called at time t1 and, in turn, calls Sub2 at time t2. Sub2 returns to Sub1 at time t3. Sub1 finally returns to its caller at t4. This is best illustrated graphically:

Sub 1 calls sub 2

This would be reported by the profiler as follows:

Sub11t4-t3 + t2-t1t4-t1

Here's another example:

Sub 1 calls sub 2 twice

This would be reported by the profiler as:

Sub11t6-t5 + t4-t3 + t2-t1t6-t1
Sub22t5-t4 + t3-t2t5-t4 + t3-t2

Time is measured in CPU cycles. To convert this to seconds, divide by the clock speed of your machine. For example, if you have a 750MHz machine, divide by 750,000,000.

Profiling EXEs

The profiler was originally designed to work with MTS but it can also profile VB form applications. Instead of using my applet (Profiler.EXE) to control the profiler, you must add two extra buttons to your VB Form.

Download Profiler.dll and register it (using the Microsoft regsvr32 utility): regsvr32 Profiler.dll

If you're running on NT4, place dbghelp.dll in the same folder.

You will also need DebugView from or DBWIN32 from the NT Resource Kit.

Add Instrument and Report buttons to your VB Form:

VB Form

Re-compile your project(s) with the option to create symbolic debugging information checked. You will find this option on the Compile tab of the project properties dialog.

Launch the executable (the profiler will not work in debug mode) and click Instrument. The profiler is now recording. Open DebugView or DBWin32 in readiness. Exercise your code (e.g. click Test) and then click report. The analysis and interpretation of results is explained above. The profiler will also instrument DLLs and OCXs - if it can find debugging information for them - as long as they are loaded before you click Instrument.

Instrument() and Report() are not the only methods exposed by the Profiler COM interface. The Main.frm code in my control applet illustrates how to use the others: NextDLL() returns details of what has been instrumented; and Disconnect() removes the instrumentation.

You may wish to enable/disable the buttons (as I do in Main.frm) to prevent Instrument() being called twice, or Report() being called first.