You can use Visual Studio to debug itself!
How do you find out why your computer or a running program is so slow? Here’s one way.
Let’s attach the VS debugger to VS itself. The main executable for VS is devenv.exe.
Start Visual Studio 2008. This will be the “debugger”
Choose File->Open Project C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe
(You can also choose Debug->Attach to process to debug another instance of devenv.exe, or any other EXE, like Foxpro.exe or Excel.exe)
Hit F5, and a dialog pops up:
“Debugging information for ‘devenv.exe’ cannot be found or does not match. Symbols not loaded. Do you want to continue debugging?”.
Answer yes, and Visual Studio starts. This will be the “debuggee”
Do anything you like in the debuggee, such as create or load a project. Hit F12 to cause an asynchronous breakpoint (or go to the debugger and choose Debug->Break All).
That will freeze all the debuggee threads and put you in the debugger.
You can then examine the Threads window (Debug->Windows->Threads) and see what threads are running. There are several. You can dbl-click various threads and look at the Call stack for it (Debug->Windows->Call stack).
You’ll probably see that most threads are just waiting for something to happen.
Choose the main thread. When VS is idling, the stack will look like this:
ntdll.dll!7c90eb94()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7c90e9ab()
kernel32.dll!7c8094e2()
> msvcr90.dll!_onexit_nolock(int (void)* func=0x0072006f) Line 157 + 0x6 bytes C
00660072()
Each stack entry shows the module and address that called the next stack entry. This isn’t very useful, so you need to load symbols. You can use the public Microsoft Symbol Server:
Tools->Options->Debug->Symbols
https://msdl.microsoft.com/download/symbols
Cache the symbols to a local dir, like C:\Symbols
Right click on the various modules (like ntdll.dll, kernel32.dll, msenv.dll etc.) in the call stack to load symbols. Now it’s a little more intelligible:
> ntdll.dll!_KiFastSystemCallRet@0()
user32.dll!_NtUserKillTimer@8() + 0xc bytes
msenv.dll!CMsoCMHandler::FPushMessageLoop() + 0x36 bytes
msenv.dll!SCM::FPushMessageLoop() + 0x4f bytes
msenv.dll!SCM_MsoCompMgr::FPushMessageLoop() + 0x28 bytes
msenv.dll!CMsoComponent::PushMsgLoop() + 0x28 bytes
msenv.dll!VStudioMainLogged() + 0x19b bytes
msenv.dll!_VStudioMain() + 0x7d bytes
devenv.exe!util_CallVsMain() + 0xd8 bytes
devenv.exe!CDevEnvAppId::Run() + 0x5cb bytes
devenv.exe!_WinMain@16() + 0x60 bytes
devenv.exe!License::GetPID() - 0x4cf9 bytes
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
You can see the WinMain calls a MessageLoop.
Let’s make the foreground thread busy. Create a VB console application. Add an XML literal:
Module Module1
Sub Main()
Dim bigxml = <xml>
</xml>
End Sub
End Module
Make the XML literal big: open the file C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.Linq.xml and copy everything except the <?xml version="1.0" encoding="utf-8"?> into the literal (between the <xml> and the </xml>), so you have about 2000 lines.
Start Task Manager (Ctrl-Shift->Escape, or right click on the task bar and choose Task Manager). Observe the little tray icon in the System tray. It will indicate how busy your computer is.
For example, if you have 2 processors and 1 thread is very busy, it’ll show 50% busy.
Now, if you hover your mouse over the “bigxml”, you’ll trigger VB to create a Quick Info tooltip, but it takes quite a lot of calculation to figure out the tip.
Do your asynchronous breakpoint trick and you’ll see something like this:
> msvb7.dll!BCSYM::IsNamedRoot()
msvb7.dll!BCSYM::AreTypesEqual()
msvb7.dll!EquivalentTypes() + 0x17 bytes
msvb7.dll!ClassifyPredefinedCLRConversion() + 0x22 bytes
msvb7.dll!Semantics::ClassifyPredefinedCLRConversion() + 0x28 bytes
msvb7.dll!Semantics::ClassifyPredefinedConversion() + 0xbf bytes
msvb7.dll!Semantics::ResolveConversion() + 0x234 bytes
msvb7.dll!Semantics::ClassifyUserDefinedConversion() + 0x40685 bytes
msvb7.dll!Semantics::ClassifyConversion() + 0x21e31 bytes
msvb7.dll!Semantics::CompareParameterTypeSpecificity() + 0x57 bytes
msvb7.dll!Semantics::CompareParameterSpecificity() + 0xa3 bytes
msvb7.dll!Semantics::InsertIfMethodAvailable() + 0x461 bytes
msvb7.dll!Semantics::CollectOverloadCandidates() + 0x1e6 bytes
msvb7.dll!Semantics::ResolveOverloading() + 0xd9 bytes
msvb7.dll!Semantics::ResolveOverloadedCall() + 0x5e bytes
msvb7.dll!Semantics::InterpretCallExpression() + 0x2656f bytes
msvb7.dll!Semantics::CreateConstructedInstance() + 0xfa bytes
msvb7.dll!Semantics::CreateConstructedInstance() + 0x5b bytes
msvb7.dll!Semantics::InterpretXmlElement() + 0x241 bytes
msvb7.dll!Semantics::InterpretXmlContent() + 0x56 bytes
msvb7.dll!Semantics::InterpretXmlElement() + 0x27c bytes
msvb7.dll!Semantics::InterpretXmlContent() + 0x56 bytes
msvb7.dll!Semantics::InterpretXmlElement() + 0x27c bytes
msvb7.dll!Semantics::InterpretXmlContent() + 0x56 bytes
msvb7.dll!Semantics::InterpretXmlElement() + 0x27c bytes
msvb7.dll!Semantics::InterpretXmlContent() + 0x56 bytes
msvb7.dll!Semantics::InterpretXmlElement() + 0x27c bytes
msvb7.dll!Semantics::InterpretXmlExpression() - 0x13d bytes
msvb7.dll!Semantics::InterpretXmlExpression() + 0xb0 bytes
msvb7.dll!Semantics::InterpretXmlExpression() + 0xc3 bytes
msvb7.dll!Semantics::InterpretExpression() - 0x1fc bytes
msvb7.dll!Semantics::InterpretExpressionWithTargetType() + 0x43 bytes
msvb7.dll!Semantics::InterpretInitializer() + 0x36 bytes
msvb7.dll!Semantics::InterpretInitializer() + 0x1a bytes
msvb7.dll!Semantics::InterpretInitializer() + 0x127 bytes
msvb7.dll!Semantics::InterpretVariableDeclarationStatement() + 0x158c bytes
msvb7.dll!Semantics::InterpretStatement() + 0x7b2f bytes
msvb7.dll!Semantics::InterpretStatementSequence() + 0x2f bytes
msvb7.dll!Semantics::InterpretBlock() + 0x24 bytes
msvb7.dll!Semantics::InterpretMethodBody() + 0x1fa bytes
msvb7.dll!SourceFile::GetBoundMethodBodyTrees() + 0x126 bytes
msvb7.dll!CBaseSymbolLocator::GetBoundMethodBody() + 0xb6 bytes
msvb7.dll!CSymbolLocator::LocateSymbolInMethodImpl() + 0x29 bytes
msvb7.dll!CSymbolLocator::LocateSymbol() + 0x81f bytes
msvb7.dll!CIntelliSense::GenQuickInfo() + 0x52399 bytes
msvb7.dll!CIntelliSense::HandleQuickInfo() + 0x29 bytes
msvb7.dll!CIntelliSense::ProcessCompletionInfo() + 0x66cda bytes
msvb7.dll!CIntelliSense::GenIntelliSenseInfo() + 0x402 bytes
msvb7.dll!SourceFileView::GenIntelliSenseInfo() + 0x94 bytes
msvb7.dll!SourceFileView::GetDataTip() + 0x743 bytes
msvb7.dll!CVBLangService::GetDataTip() + 0x11d bytes
msenv.dll!CEditView::GetFilterDataTipText() + 0x37 bytes
msenv.dll!CEditView::HandleHoverWaitTimer() + 0x213 bytes
msenv.dll!CEditView::TimerTick() + 0x7d bytes
msenv.dll!CEditView::WndProc() + 0x1685b9 bytes
msenv.dll!CEditView::StaticWndProc() + 0x39 bytes
user32.dll!_InternalCallWinProc@20() + 0x28 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 bytes
user32.dll!_DispatchMessageWorker@8() + 0xdc bytes
user32.dll!_DispatchMessageW@4() + 0xf bytes
msenv.dll!EnvironmentMsgLoop() + 0xb6 bytes
msenv.dll!CMsoCMHandler::FPushMessageLoop() + 0x36 bytes
msenv.dll!SCM::FPushMessageLoop() + 0x4f bytes
msenv.dll!SCM_MsoCompMgr::FPushMessageLoop() + 0x28 bytes
msenv.dll!CMsoComponent::PushMsgLoop() + 0x28 bytes
msenv.dll!VStudioMainLogged() + 0x19b bytes
msenv.dll!_VStudioMain() + 0x7d bytes
devenv.exe!util_CallVsMain() + 0xd8 bytes
devenv.exe!CDevEnvAppId::Run() + 0x5cb bytes
devenv.exe!_WinMain@16() + 0x60 bytes
devenv.exe!License::GetPID() - 0x4cf9 bytes
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
Note how it’s easy to read the stack. The bottom of the stack (the first thing put on it) is _BaseProcessStart, which starts the process. You can see that a timer tick caused GetDataTip to call GenIntelliSenseInfo, which calls GenQuickInfo, -> LocateSymbol, etc.
Each stack entry indicates the name of the routine being executed. The “+ 0x23 bytes” means the # of bytes into the routine that the call occurred. A low number means near the beginning of that method.
Because XML is a tree, and is thus a recursive data structure, you see that XMLContent can contain an XMLExpression and vice versa. The depth of the recursion reflects the actual XML being processed.
BTW, the VB background compiler thread is:
0 > 4620 Worker Thread ThreadSyncManager::ThreadProc _KiFastSystemCallRet@0 Normal 0
And it’s stack at idle:
> ntdll.dll!_KiFastSystemCallRet@0()
ntdll.dll!_ZwWaitForMultipleObjects@20() + 0xc bytes
kernel32.dll!_WaitForMultipleObjectsEx@20() - 0x48 bytes
user32.dll!_RealMsgWaitForMultipleObjectsEx@20() + 0xd9 bytes
ole32.dll!CCliModalLoop::BlockFn() + 0x76 bytes
ole32.dll!_CoWaitForMultipleHandles@20() + 0xe6 bytes
msvb7.dll!ThreadSyncManager::ThreadProc() + 0x98 bytes
kernel32.dll!_BaseThreadStart@8() + 0x37 bytes
See also:
Dynamically attaching a debugger
Is a process hijacking your machine?
Comments
- Anonymous
June 09, 2009
The comment has been removed - Anonymous
June 09, 2009
PingBack from http://visualstudio2005.blog-giant.com/2009/05/25/net-web-developer-techsales-llc-phoenix-az/