Microsoft KB Archive/169275

{|
 * width="100%"|

INFO: Troubleshooting CAP/WST Utilities Under Windows NT

 * }

Q169275

-

The information in this article applies to:


 * Microsoft Win32 Software Development Kit (SDK)

-

SUMMARY
This article provides a collection of tips, tricks, and traps to you can use to avoid and solve common problems that you may encounter while using the Call Attribute Profiler (CAP) and Working Set Tuner (WST) utilities for Windows NT and Windows 2000. Note that these utilities are included with the Win32 Software Development Kit. You can use these powerful utilities to make your application run faster and use less RAM.

This article assumes that you have read the preliminary information on the use of these tools that is available in the Win32 SDK Tools documentation. The information in this article applies to the versions of CAP/WST utilities that are shipped on the January 97 Win32 SDK or later.

Preparing Your Application
We recommend that you build applications that you want to tune with CAP or WST with slightly different switches than the documentation suggests. For the compiler, use /Zi or /Z7 (don't forget /Gh). For the linker, use /debug /debugtype:both and /pdb: .pdb or /pdb:none.

One benefit of using these switches is that you can do full symbolic debugging under the Visual C++ or WinDbg debugger in case either the CAP or WST utility manages to flush out a problem in your code. This is more common than you may think. For example, /Gh causes the compiler to insert a call to a function called _penter in front of each and every function in your code. This global increase in code size causes your functions to load into slightly different offsets in memory, which may cause a pointer bug or array-overrun bug in your code to now show itself. By using these switches, you can debug your application normally when it is compiled for CAP/WST.

TIP: We recommend that you do not use capsetup.exe to prepare your applications for tuning. Instead, building your applications with the proper switches works more reliably.

TRAP: Running "capsetup -a" and then building your application for tuning causes the CAP utility to not work. Just avoid Capsetup.exe if you can.

Tuning/Profiling DLLs and OCXs
Tuning DLLs and OCXs is fairly straightforward for both CAP and WST, once you know the details, though the procedure is slightly different for each.

WST:

When an executable compiled for WST is initialized, WST gets control and looks at all the DLLs loaded in that process's memory space. Only DLLs that are present and built for WST are tuned, which means that the DLLs must be statically linked. Dynamically-loaded DLLs (and OCXs) are not tuned even though they may be compiled for tuning.

TRICK: However, you can tune all static DLLs/OCXs. The trick is to build only the DLL/OCXs that you want to tune for tuning. Do not build the executable for tuning. Then do the following:


 * 1) Remove the name of the .exe from the [exes] section in WST.ini file to cut down on extraneous output files in the output directory.
 * 2) Put the name of the DLL/OCX into the [exes] section in WST.ini.
 * 3) The symbols for the DLL/OCX (whether it is the DLL/OCX itself, or a .dbg or .pdb file) must be on the symbol search path (which is %_NT_SYMBOL_PATH%, %_NT_ALT_SYMBOL_PATH%, %SystemRoot%, and the working directory, in that order). Otherwise, you will get empty output files in the WST directory. This is especially important for an OCX, which is usually residing (and also usually registered) in another directory.

TIP: We have had best luck by simply putting and registering the DLL/OCX in the same directory as the executable, or by making sure the application and DLL/OCX are in subdirectories of the current directory when you run the executable.

TRAP: You will get output files for static DLL/OCXs loaded after the desired module anyway. If present, the environment variables %_NT_SYMBOL_PATH% and %_NT_ALT_SYMBOL_PATH% might each contain only one path containing less than 256 characters.

For additional information, please see the following article in the Microsoft Knowledge Base:

"Q148659 How to Set Up Windows NT Debug Symbols"

CAP:

Fortunately, CAP supports dynamically loaded libraries without any special caveats. You just need to make sure that loadlibrary=on in the CAP.ini file. However, if you're not getting symbolic information for your DLLs, you can try something similar to the procedure for WST--except you must put the name of the .exe in the [exes] section, unlike for WST.

Known Problems, Limitations
The following is a list of known problems and limitations with the CAP and WST utilities. It's best to contact Microsoft Professsional Support Services for help with any problems encountered with these utilities. A support professional may be able to provide a workaround or help with critical problems.


 * 1) If you are tuning with CAP/WST under Windows NT version 3.51 and run into problems, it is highly recommended that you switch to Windows NT version 4.0 and use the latest version of CAP/WST utilities from the Platform SDK.

TIP: Note that you can use CAP.DLL for Windows NT 4.0 on a Windows NT Version 3.51. However, you must copy IMAGEHLP.dll from Windows NT 4.0 into your application's directory that you are tuning because the latest version of CAP/WST utilities need an updated IMAGEHLP.DLL to do symbol lookups. Be careful not to replace the IMAGEHLP.DLL in the Window NT 3.51 %systemroot%\system32 directory.
 * 1) On rare occasions, when using CAP, a fault occurs in the C-runtime library's strcpy function call from CAP.dll. This causes the target DLL, that is being tuned by CAP, to not load its symbols. This results in missing symbols in the .END file after a profile run for such a DLL. Unfortunately, this could be the DLL or OCX that you are trying to tune, as opposed to a child or system DLL. You can identify this problem if you have linked with the debug C-runtime (CRT) library and you see strcpy at the top of the call stack in the debugger after stopping at the second-chance exception.

We are researching this known problem with the CAP utility and will post new information here in the Microsoft Knowledge Base as it becomes available.
 * 1) The system IMAGEHLP.dll for Windows NT versions 4.0 with Service Pack 2 (and previous versions of Windows NT) returns corrupted symbolic name strings when CAP is doing symbol lookups and when the setting "undecorate=off" is set in CAP.ini. In this situation, your .END file will contain a few "garbage" characters embedded, usually a control-Z. In addition, this problem could also crash Capview.exe utility. This problem can typically be fixed by stripping out any non-printable characters from your .END file.

We are researching this known problem with the CAP utility and will post new information here in the Microsoft Knowledge Base as it becomes available.
 * 1) The CAP tool has certain problems with Visual C++ style exception- handling. If a Visual C++ exception occurs, CAP does not correctly clean up the stack, causing strange crashes and application lockups. In order to avoid this problem, you have to modify your application so that no Visual C++ exceptions occur during a profile run. Note that this problem may also occur with the WST utility, since both these utilities share common code.

We are researching this known problem with CAP, WST utilities and will post new information here in the Microsoft Knowledge Base as it becomes available.
 * 1) WST cannot tune static functions. This is due to a limitation of the Visual C++ linker. When WST encounters static functions, it will tune them like other functions and they will be listed in the .PRF output file. But, the Visual C++ linker cannot reorder static functions, and, consequently, will generate a few harmless warnings that it is unable to reorder them.

Note that for Visual C++ applications you may see some mysterious static functions in the .prf file with a name in the format of _$Ennn, where "nnn" is some numeric value. These are static helper functions generated by the compiler. WST puts these function names in the .PRF output, but the resulting linker warnings can be safely ignored. Unfortunately these static functions (and any that you defined in your application) will not be reordered and, consequently, will not be tuned either.
 * 1) The section headers in the WST.ini and CAP.ini initialization files must appear in the same order as the example files copied during setup. A missing or misspelled section header causes WST to ignore the remaining portion of WST.ini. Although it must be present, WST completely ignores the [PATCH IMPORTS] section of the WST.ini initialization file.
 * 2) WST might fail to initialize when tuning extremely large projects. This might cause the application being tuned to freeze on startup. A warning message that the system is low on virtual memory might indicate that too many symbols exist in the modules to be tuned. In this case, reducing the number of modules built for tuning or adding more RAM to the test computer may help.
 * 3) WSTune.exe cannot dump analysis data for modules whose base file name is greater than 17 characters.

CAP Memory Usage Information
CAP memory usage can be a factor in the performance of your application. If CAP's memory usage becomes too great (usually due to a lot of chronological data), this will result in a lot of swapping, which in turn can affect the performance of your application.

CAP's memory usage can be divided into the following three groups (ordered from smallest to largest):


 * 1) Symbol information.
 * 2) Calling tree structure.
 * 3) Chronological calling data.

The symbol data is loaded when the app starts, and also when a DLL is dynamically loaded (if 'loadlibrary=on' in CAP.ini). The symbol information is a kind of dictionary, mapping function names to raw hex addresses. This allows CAP to log the profile information by name rather than hex addresses. The size of the symbol information depends on how many DLL's are loaded, and how many symbols are in each DLL.

The calling tree structure is continuously built as the profiled application executes. Each node in this tree represents one caller-callee pair. For example, the first time function A calls function B, a new node is created. Each additional call from function A to function B changes the profiling values in node A-B, but does not increase the storage space. So the size of the calling tree is dependent on the number of caller-callee relations that are actually exercised by the application. Each node requires 80 bytes of memory.

The calling tree information is dumped to the log file and provides the input for Capview.exe. It contains information such as the number of times function A called function B, the shortest/longest/average time function B executed when called by function A, and how much of function B's time was due to calls that it made itself.

Chronological calling data is by far the largest user of CAP memory. Unlike the calling tree data, the chronological data contains a data cell for every function call that occurs. If function A calls function B 100 times, 100 cells are created. This allows for a very detailed log that shows the exact order that calls were made and how much time each call took. The size of the chronological data, then, depends on how many function calls are made by the application. Each data cell requires 40 bytes.

Preparing to Contact Professional Support Services
When CAP or WST fails, the most common symptoms are failure to produce any output or an exception while your application executes (usually during initialization). To determine if the failure is due to a problem in CAP.dll or WST.dll, you will have to debug your application. When you hit a 2nd- chance exception in the debugger (ignore all 1st-chance exceptions - they are normal and are handled by an exception handler in CAP/WST), look at the top of the call stack to see if the exception occurred in CAP or WST. To do this, use LINK -dump -headers on CAP.dll or WST.dll (or you can do a "quick view" in Windows Explorer on the DLL) and note the image base address and the "size of image" value. If the address where the exception occurred is within image base + size of image, then you have most likely encountered a bug in CAP.dll or WST.dll.

Before contacting Microsoft Professional Support Services for help in diagnosing the problem, please debug your application and do the following (these instructions are for an x86 machine). Visual C instructions are for version 5.0 and later:


 * 1) Dump the stack as follows:

WinDbg: In the command window, enter "dd esp" and leave the output there.

Visual C debugger: On the View menu, click Debug Windows, click Memory, enter "esp", and then copy downward 20 lines or so (right-click, then click Copy). Paste it into a new document in Notepad or any other editor.
 * 1) Get the contents of the registers as follows:

WinDbg: In the command window, type r.

Visual C debugger: Get the contents of the registers from the View menu, Debug Windows menu, Registers window.
 * 1) Get the call stack as follows:

WinDbg: In the command window, type kbsv. Visual C debugger: On the View menu, Debug Windows menu, Call Stack. Copy everything.
 * 1) Get a disassembly listing of the code around the exception as follows: WinDbg: Click the assembly toolbar button (with the 1's and 0's in it) and get a screenful of code both above and below the address of the 2nd- chance exception.

Visual C debugger: On the View menu, Debug Windows menu, click Disassembly. Copy a few pages above and below the address of the exception.
 * 1) Assemble information as follows:

WinDbg: The output from all the commands that you typed into the command window should still be in the command window. Scroll back in the command window, copy all the debug output from CAP/WST, and include the stack dump, register dump, and call stack you created.

Visual C debugger: Copy the output from CAP/WST from the Debug window into your document.

TIP: To skip past all the 1st-chance exceptions that you may hit when debugging CAP-compiled applications (which are normal) do the following:

WinDbg: On the Options menu, click Exceptions, set "Access Violation" (0xc0000005) to "Notify", and then click Change.

Visual C debugger: On the Debug menu, click Exceptions and make sure that "access violation" is set to "stop if not handled".