Download source files - 124 Kb
Introduction
VC++ has an excellent built-in profiler,
but in keeping with the (apparent) design philosophy of the product, MS doesn’t
provide a nice GUI for the feature, preferring to provide flexible low-level
functionality that can be customized. An associated tool is a macro to be found
in the VC98/Bin folder, titled PROFILER.XLM. This macro will take the tabbed
text output from the profiler output processor program PLIST.EXE, and present
it as an Excel chart showing either function timing or hit counts. The down
side is that this functionality is a bit awkward to use, and consequently I
personally found myself somewhat hesitant to use it.
VB is an ideal tool to produce a simple front
end to automate this sort of process. I’ve noticed some resistance to the use
of VB among people who consider themselves to be ‘real’ programmers (witness
the recent discussions at CodeProject). I find this amusing. Blind prejudice on
the basis of some perceived superiority of self is self-defeating, if for no
other reason than that it limits one’s horizons. I suppose a ‘real’ programmer
would prefer to use command line options to run this process, or a VC++
solution… but this took two days, and I’d never worked with the VB/Office
interface before. VB has its uses – this little project works for me, and I
suspect others may find it useful as well.
Use
of the PROFILER.XLM Macro
The process of running the profiler from
the VC++ Development Environment is described in the VC++ Programmers Guide
under Performance Tuning. Further detailed information is available under the
headings ‘Using PROFILE, PREP and PLIST’, and ‘Using the PROFILER.XLM Macro’.
The process is synopsized here.
Typically, when collecting function timing
/ hit count information, you don’t want to collect data for the entire program,
but rather starting with a particular function, and including the functions
that it calls. To accomplish this, you first need to create a debug build of
your application with ‘Enable Profiling’ and ‘Generate MapFile’ boxes checked
in the ‘Project/Settings/Link’ property page. After building the project, you
then search the .map file in the /Debug folder for the decorated name of the
desired start function. (Several entries in the VC++ Programmer’s Guide
describe decorated names.) Select ‘Build/Profile’ to bring up the profiler
dialog box. Check ‘Function Timing’, and then enter ‘/SF ‘ (that’s slash S-F
followed by a space), and the decorated function name. The resultant entry
would look something like this:
/SF ?DrawObjects@CGLDisplay@@AAEXW4TRenderMode@@@Z
Clicking ‘OK’ on the dialog box launches
the application under the control of the profiler. Do whatever is desired to
exercise the code being profiled, then quit the application. The raw function
timing and hit count data appears in the VC++ output window, sorted by time.
Now open a DOS command window. The program ‘PLIST’ must be run with the ‘/t’
option, to produce a tabbed text output suitable for import into Excel. The
syntax is something like ‘PLIST /t inputpath > outputpath’, where
‘inputpath’ is the location of the .pbt file produced by PREP (by default the
project’s /Debug folder), and ‘outputpath’ is the desired loation of the tabbed
text file.
There may be a hitch at this point. PREP,
PLIST and PROFILE live in the VC98/Bin folder. A required DLL, mspdb60.dll, is
not, by default, in the path where PREP can find it (at least w/ VS 6.0 SP3-4).
I believe that running the VC++ Environment Variables option at setup
accommodates this, but if you get a ‘file not found’ error, just copy the
mspdb60.dll into the VC98/Bin folder.
Once the tabbed text file has been
generated, open Excel, then select File/Open’, and navigate to the PROFILER.XLM
macro. Open it. Now select ‘File/Open’ again, and navigate to the tabbed text
file. Open it, going with the default options for processing the tabs. The data
is loaded into Excel and processed. Now by pressing Ctrl-T, a timing chart like
that pictured below will be produced. Pressing Ctrl-C will produce a similar
chart w/ hit count data.
As I said, killer results, but a bit of a
pain in the ass to produce.
The
VB Front End
If you’ve followed the preceding
description, this will be pretty straightforward. Using the VB Drive List Box,
Directory List Box and File List Box components, locate the debug build of the
app you want to profile. (NOTE – you still have to create a debug build with
profiling and map file generation enabled, as described above.) Type the name
of the desired start functionwhere indicated, and press ‘Search’. The program
will look in the .map file and pull all the decorated names containing the
search string. Select on of the decorated names and press ‘Run Profiler’. The
program will create a batch file in the /Debug folder containing the code
necessary to run the profiler sequence, then executes it.� The VB front end minimizes to the task bar,
the app will run, and you perform whatever tasks are necessary to exercise the
code you’re profiling. When you’re ready, quit the app under test, bring up the
VB app by clicking on it’s task bar icon, and select the desired output by
clicking on of the remaining buttons. Pressing either of the ‘Chart’ buttons
will open an instance of Excel, open the PROFILER.XLM macro file, open the text
file generated by PLIST, and create the appropriate chart. You can switch from
one chart to the other without re-running the profiler. By clicking the ‘View
Sorted Text Output’ button, you can see the data in the format originally
presented in the VC++ Dev. Env. Output window, with the added twist that it’ll
sort by time or hit count, depending on which Excel view you’ve selected. (If
you haven’t selected an Excel chart, it’ll default to sort by time.)� Optionally, as the controls indicate, you
can enable ‘Call Attribute’ data collection. This will change the timing sort
of the text output to indicate more clearly which functions where called by
whom, and how much time was spent processing calls from a particular function.
(There’s a bug written up in MSDN about using the Call Attribute option with
decorated function names longer than 255 characters – something you might want
to be aware of.)
Implementation
Details
- Files
created/destroyed – As noted, a batch file is created in the VC++ project’s
/Debug folder which contains the commands necessary to run the profiler job.
This file is called ‘xcelprof.bat’, and is cleaned up when the program exits.
The tabbed text output fed to Excel is called excel_profile.txt, and is also
created in the /Debug folder. It is left behind for further viewing. Likewise,
the sorted text file created by clicking ‘View Sorted Text Output’ is in the
/Debug folder. It’s called ‘profile.txt’, and is left behind.
- Default Tool
Directory – If you’ve gone with the default install options for Visual Studio,
PLIST, PROFILE and PREP all live at c:\program files\microsoft visual
studio\vc98\bin\. If you’ve placed them elsewhere, you’ll have to modify the
string constant strToolDir at the top of the VB source code.
- Excel compatibility
issues – I put this together using Win2K Pro SP1, VS6 SP4, and MS Office 2000
SP1. I’m not familiar enough with other versions of Excel to say for sure that
it will work, but if not I suspect it’ll be due to some difference in the code
required to open PROFILER.XLM and the tabbed text file. If this is a problem,
the solution is simple. The code affected is in the VB functions
‘btnTimingClick()’ and ‘btnHitCountClick()’, and is noted with a comment. The
snippet was created using the ‘Record Macro’ option from inside Excel, and
performing the sequence necessary to open the files and create the chart.
Simple, no?
- Registry entries –
the program remembers the last .exe tested as well as the name of the last
function profiled. This information is stored in the registry under Current
User/Software/VB and VBA Program Settings/VC++-Excel Profiler.
- VB Runtime DLLs - these have not been included in the zip file.