Have you ever had a situation where you find yourself debugging a dump from ASP.NET when suddenly you notice you forgot to get the Performance Monitor log?
If sometimes you face this situation, I have great news for you: this script shows you some of the main .NET Performance Monitor counters. It gets the information from the ASP.NET process or dump being debugged.
Take a look at these screenshots:
Source code for GET_PERFMON.TXT:
$$
$$ =============================================================================
$$ Get Performance Monitor counters from mscorsvr.dll or mscorwks.dll.
$$ Compatibility: Win32/Win64 (This is a new version from 01/30/09)
$$ Usage: $$>< to run the program.
$$ Requirements: Public symbols.
$$ If necessary change the filename below to include your path and filename.
$$ By default it uses the WinDbg path and the default file name is GET_PERFMON.TXT
$$ Roberto Alexis Farah
$$ Blog: http://blogs.msdn.com/debuggingtoolbox/
$$ All my scripts are provided "AS IS" with no warranties, and confer no rights.
r @$t0 = 0;
r @$t1 = 0;
.block
{
as ${/v:ScriptName} MYSCRIPTS\\GET_PERFMON.TXT
}
.foreach(obj { lm1m })
.if((0 == $sicmp("${obj}", "mscorsvr")) | (0 == $sicmp("${obj}", "mscorwks")))
r @$t0 = ${obj}!PerfCounters::m_pPrivatePerf;
.if(0 == @$t0)
.printf /D "<b>\nThis is not a .NET application!\n</b>";
.else
as ${/v:GCCounters} .block
r @$t1 = poi(@$t0) + @$ptrsize;
.printf "\n.NET GC Counters\n\n";
.printf "GenCollection 0 = 0n%d\n", poi(@$t1);
.printf "GenCollection 1 = 0n%d\n", poi(@$t1+@$ptrsize);
.printf "GenCollection 2 = 0n%d\n", poi(@$t1+@$ptrsize*2);
.printf "PromotedMemory = 0n%d\n", poi(@$t1+@$ptrsize*3);
.printf "PromotedMemory 1 = 0n%d\n", poi(@$t1+@$ptrsize*4);
.printf "PromotedFinalizationMem 0 = 0n%d\n", poi(@$t1+@$ptrsize*5);
.printf "Process ID = 0n%d\n", poi(@$t1+@$ptrsize*6);
.printf "GenHeapSize 0 = 0n%d\n", poi(@$t1+@$ptrsize*7);
.printf "GenHeapSize 1 = 0n%d\n", poi(@$t1+@$ptrsize*8);
.printf "GenHeapSize 2 = 0n%d\n", poi(@$t1+@$ptrsize*9);
.printf "TotalCommittedBytes = 0n%d\n", poi(@$t1+@$ptrsize*0n10);
.printf "TotalReservedBytes = 0n%d\n", poi(@$t1+@$ptrsize*0n11);
.printf "LargeObjectSize = 0n%d\n", poi(@$t1+@$ptrsize*0n12);
.printf "SurviveFinalize = 0n%d\n", poi(@$t1+@$ptrsize*0n13);
.printf "Handles = 0n%d\n", poi(@$t1+@$ptrsize*0n14);
.printf "Alloc = 0x%x\n", poi(@$t1+@$ptrsize*0n15);
.printf "LargeAlloc = 0x%x\n", poi(@$t1+@$ptrsize*0n16);
.printf "InducedGCs = 0n%d\n", poi(@$t1+@$ptrsize*0n17);
.printf "TimeInGC = 0n%d\n", poi(@$t1+@$ptrsize*0n18);
.printf "TimeInGCBase = 0n%d\n", poi(@$t1+@$ptrsize*0n19);
.printf "PinnedObjects = 0n%d\n", poi(@$t1+@$ptrsize*0n20);
.printf "SinkBlocks = 0n%d\n\n", poi(@$t1+@$ptrsize*0n21);
as ${/v:InteropCounters} .block
r @$t1 = poi(@$t0) + 0x74;
.printf "\n.NET Interop Counters\n\n";
.printf "CCW = 0n%d\n", poi(@$t1);
.printf "Stubs = 0n%d\n", poi(@$t1+0x4);
.printf "Marshalling = 0n%d\n", poi(@$t1+0x8);
.printf "TLBImports = 0n%d\n", poi(@$t1+0xc);
.printf "TLBExports = 0n%d\n\n", poi(@$t1+0x10);
as ${/v:LoadingCounters} .block
r @$t1 = poi(@$t0) + 0x88;
.printf "\n.NET Loading Counters\n\n";
.printf "Current ClassesLoaded = 0n%d\n", poi(@$t1);
.printf "Total ClassesLoaded = 0n%d\n", poi(@$t1+0x4);
.printf "Current AppDomains = 0n%d\n", poi(@$t1+0x8);
.printf "Total AppDomains = 0n%d\n", poi(@$t1+0xc);
.printf "Current Assemblies = 0n%d\n", poi(@$t1+0x10);
.printf "Total Assemblies = 0n%d\n", poi(@$t1+0x14);
.printf "Time Loading = 0n%d\n", poi(@$t1+0x18);
.printf "AsmSearchLen = 0n%d\n", poi(@$t1+0x20);
.printf "Total LoadFailures = 0n%d\n", poi(@$t1+0x24);
.printf "LoaderHeapSize = 0n%d\n", poi(@$t1+0x28);
.printf "AppDomainsUnloaded = 0n%d\n\n", poi(@$t1+0x2c);
as ${/v:ExceptionCounters} .block
r @$t1 = poi(@$t0) + 0xb8;
.printf "\n.NET Exception Counters\n\n";
.printf "Total Exceptions = 0n%d\n", poi(@$t1);
.printf "Filters Executed = 0n%d\n", poi(@$t1+0x4);
.printf "Finallys Executed = 0n%d\n", poi(@$t1+0x8);
.printf "ThrowToCatchStackDepth = 0n%d\n\n", poi(@$t1+0xc);
as ${/v:LockAndThreadCounters} .block
r @$t1 = poi(@$t0) + 0xc8;
.printf "\n.NET Locks and Threads Counters\n\n";
.printf "Total Contention = 0n%d\n", poi(@$t1);
.printf "QueueLength Current = 0n%d\n", poi(@$t1+0x4);
.printf "QueueLength Total = 0n%d\n", poi(@$t1+0x8);
.printf "CurrentThreadsLogical = 0n%d\n", poi(@$t1+0xc);
.printf "CurrentThreadsPhysical = 0n%d\n", poi(@$t1+0x10);
.printf "RecognizedThreads Current = 0n%d\n", poi(@$t1+0x14);
.printf "RecognizedThreads Total = 0n%d\n\n", poi(@$t1+0x18);
as ${/v:JITCounters} .block
r @$t1 = poi(@$t0) + 0xe4;
.printf "\n.NET JIT Counters\n\n";
.printf "Methods Jitted = 0n%d\n", poi(@$t1);
.printf "IL Jitted Current = 0n%d\n", poi(@$t1+0x4);
.printf "IL Jitted Total = 0n%d\n", poi(@$t1+0x8);
.printf "JIT Failures = 0n%d\n", poi(@$t1+0xc);
.printf "Time In JIT = 0n%d\n", poi(@$t1+0x10);
.printf "Time In JIT Base = 0n%d\n\n", poi(@$t1+0x14);
as ${/v:SecurityCounters} .block
r @$t1 = poi(@$t0) + 0xfc;
.printf "\n.NET Security Counters\n\n";
.printf "Total RunTime Checks = 0n%d\n", poi(@$t1);
.printf "Time Authorize = 0n%d\n", poi(@$t1+0x4);
.printf "Link Checks = 0n%d\n", poi(@$t1+0xc);
.printf "Time RunTime Checks = 0n%d\n", poi(@$t1+0x10);
.printf "Time RunTime Checks Base = 0n%d\n", poi(@$t1+0x14);
.printf "Stack Walk Depth = 0n%d\n\n", poi(@$t1+0x18);
.printf /D "<link cmd=\"${GCCounters} ad ${/v:ScriptName};ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET GC Counters</b></link>\n\n"
.printf /D "<link cmd=\"${InteropCounters} ad ${/v:ScriptName};ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET Interop Counters</b></link>\n\n"
.printf /D "<link cmd=\"${LoadingCounters} ad ${/v:ScriptName}; ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET Loading Counters</b></link>\n\n"
.printf /D "<link cmd=\"${ExceptionCounters} ad ${/v:ScriptName}; ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET Exception Counters</b></link>\n\n"
.printf /D "<link cmd=\"${LockAndThreadCounters} ad ${/v:ScriptName}; ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET LocksAndThreads Counters</b></link>\n\n"
.printf /D "<link cmd=\"${JITCounters} ad ${/v:ScriptName}; ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET JIT Counters</b></link>\n\n"
.printf /D "<link cmd=\"${SecurityCounters} ad ${/v:ScriptName}; ad ${/v:GCCounters}; ad ${/v:InteropCounters};ad ${/v:LoadingCounters};ad ${/v:ExceptionCounters};ad ${/v:LockAndThreadCounters};ad ${/v:JITCounters};ad ${/v:SecurityCounters}; $$><${ScriptName}\"><b>.NET Security Counters</b></link>\n\n"
Read me.