I’ve been evaluating Microsoft’s Visual Studio 2010 Beta 2 release recently on my Windows 7 x64 system. As can be expected, the beta has quite a few rough edges, but overall I like the new WPF-based IDE GUI and the refreshed code Editor in particular (I like how selecting a block of code now preserves syntax highlighting while the block is highlighted, for instance).
The new GUI does have some badness. I had particular distaste for the poor aliasing of tooltips in the editor. This can be seen, for example, when hovering over a function name like “printf”. The menu bar’s dark blue color scheme also appears rather peculiar.
Besides the “bling”, notable changes include the Visual C++ 2010 CRT reverting to the traditional deployment model used by the Visual C++ 2003 CRT. More specifically, the CRT DLLs no longer use SxS binding (“Fusion”) and are now simply deployed to the “system32” directory or to the application’s directory, as desired. Dropping SxS has some obvious disadvantages (SxS binding redirects would no longer be able to redirect applications that load a private copy of the CRT DLLs to updated versions with bug fixes and security updates) but presumably the pain of integrating SxS deployment into the setup process, which required either an MSI installation or pseudo-documented use of the SxS API, resulted in too much negative feedback and they chose to revert to the legacy approach.
Visual C++ projects are now built with MSBuild, like their C# and other .NET counterparts. This should have several benefits. One that comes to mind is the the Windows Installer XML Toolset’s Votive (its VS IDE integration component) should be able to support C++ projects as References in addition to .NET projects.
A more important update to the project system is support for multi-targeting. Most of Microsoft’s discussions on the subject mainly deal with said support for .NET projects, with the new Visual Studio being able to target .NET 2.0 through .NET 4.0 on a per-project basis. However, similar support is offered for native multi-targeting. A per-project setting specifies the “toolset” with which it is to be built. The product comes built-in with toolset definitions for the VC++ 10 and the VC++ 9 compilers, but since toolset definitions are simple XML files describing tool paths, older compilers and custom definitions are easy to define. Indeed, a toolset definition can be found for the Windows 7 SDK build environment. I foresee using this functionality to build user-space applications with headers and tools from the Windows Driver Kit build environment, resulting in being able to link with the OS CRT (msvcrt.dll) in a clean way, without modifying global Visual C++ directory settings, but rather keeping the changes contained to specific projects.
My enthusiasm for testing the product was struck a severe blow when my first attempt to run the Visual C++ debugger on a “Hello, World!” console application went awry. The IDE was hung for a good 15-20 seconds. The IDE sat frozen for quite a bit after F10 was pressed to initiate the debugging session, finally presented the console window for the test application and then spent some more time being frozen. After a lengthy wait, the session was finally ready.
But the worst part was that when the debugging session was finally ready, debugging symbols for all modules except the application .exe and the VC 10 CRT were NOT loaded! It appeared as though the lengthy wait was all for naught.
The experience was sufficiently poor for me to report it to Microsoft through one of the feedback channels. I was eventually contacted by helpful folks from the Visual Studio Debugger team and we analyzed the problem in an e-mail exchange. The performance issue is the result of problematic contents of the symbol path I configured for the debugger.
As I mentioned, I’m evaluating the beta on a Windows 7 machine. For this reason, the Windows 7 symbol packages, available from Microsoft’s public symbols download page, are deployed in my system and are a part of the symbol path defined by the _NT_SYMBOL_PATH environment variable. Since this is an x64 machine and I find myself debugging 32-bit processes quite often, both the 32-bit and 64-bit symbol packages are installed. My initial symbol path was:
The first issue with this symbol path is that the x64 symbols package (extracted to C:\Symbols) and the x86 symbols package (extracted to C:\Symbols32) are specified as directories in the symbol path, rather than symbol stores. This is what you’d expect from symbol packages designed for local deployment, but it turns out that the Windows 7 symbol packages, unlike the PDB packages for previous versions of Windows, come in the symbol store directory layout rather than the flat directory layout. This means, for example, that the symbols for ntdll.dll are in a path like C:\Symbols\ntdll.pdb\CFF40300FD804691B73E12CF2A150EE02\ntdll.pdb rather than the simpler C:\Symbols\dll\ntdll.pdb.
I did not notice this issue, however, before installing Visual Studio 2010 Beta 2, because apparently Windbg doesn’t mind when stores are specified in this syntax, as it exercises some sort of heuristic to determine the layout of a symbol directory. However, Visual Studio 2010 Beta 2 is not as liberal. Examining its I/Os with Sysinternals Process Monitor determined that it wasn’t trying to find PDBs under the symbol directories except directly under them or in a “dll” subdirectory, rather than looking for the appropriate hash as it would in a symbol store. The resolution for this issue is simple enough, refer to the Windows 7 symbol packages with SRV* syntax in the symbol path. Therefore, the symbol path is updated to something like:
With this change in place, the Visual Studio 2010 Beta 2 debugger was able to pick up symbols for system DLLs from the local stores, and now the debugging session started instantly. But the question remained: even if the debugger didn’t know how to look for symbols under C:\Symbols and C:\Symbols32 when they were not specified with a srv* directive, why did it download symbols from the HTTP public store, only to end up starting with symbols not being loaded for any of the system DLLs in the debugged process?
To get to the bottom of this, the local symbol caches were removed from the symbol path. At this point, it was
Running the debugger with this stripped down symbol path reproduced the poor debugger startup experience and the worse issue of symbols being downloaded only to end up not being used. At this point, Sysinternals Process Monitor was used to examine the actions of the debugger. Two curious facts were revealed.
The first was that the Visual Studio debugger was literally examining a directory called “cache*C:\websymbols” under its path in a vain attempt to find symbols. Since the “cache*” string made it to a file open request, obviously the cache* directive in the _NT_SYMBOL_PATH variable was not being correctly parsed or understood by the debugger.
The result of this deficiency is that the Visual Studio debugger should be using some default local cache directory for the downloaded symbols, instead of the one explicitly specified by the cache* directive. Therefore, the same behavior would be expected with the following symbol path:
And indeed, a quick check revealed that the same peculiarity reproduced with this symbol path setting: symbols were being downloaded from the HTTP server, but in the end of the process, symbols were not loaded for any of the system modules in the debugged process. Whatever the default directory is, attempts to download symbols there resulted in their loss into oblivion.
Specifying the local symbol cache using the SRV* directive is also possible. This is the legacy approach, before Windbg recommend using CACHE* instead. A symbol path of this form is
With this symbol path in place, the Visual Studio 2010 Beta 2 debugger both downloaded symbols from the HTTP store and actually ended up using them. Specifying the cache directory with CACHE* or not at all triggered the bug, while specifying it the old fashioned way in the SRV* directive satisfied the debugger.
As a result, my guidance for the Visual Studio 2010 Beta 2 debugger users experiencing performance issues or other symbol problems that have no issue with their symbol path when used with Windbg is:
- For each directory in your _NT_SYMBOL_PATH, determine whether it is in the “flat” format or in symbol store format. Prefix symbol stores with SRV*, changing “C:\Symbols” to “SRV*C:\Symbols”. Windows 7 users in particular should be aware that the symbol packages for their platforms should be specified with SRV* syntax for Visual Studio 2010 Beta 2.
- Specify local caches directories for remote symbol stores (SMB or HTTP) directly in the SRV* directive, to have Visual Studio 2010 Beta 2 pick them up. It is OK to keep the CACHE* directive in your symbol path as well, but for the time being, Visual Studio 2010 Beta 2 does not seem to use it correctly.
The Visual Studio Debugger team is addressing issues revealed by the investigation of this behavior for the forthcoming RTM release of Visual Studio 2010. However, several significant deficiencies in debugger symbol support will not be addressed in the 2010 release. One is that symbol loading is done synchronously rather than asynchronously to the debugging session. The other being that unless manual symbol loading is used, no progress indication nor cancellation UI is presented as the symbols are being transferred from a remote store. Therefore, the perceived performance of symbol support in the debugger will leave something to be desired for the time being.