Win32::PerfMon is unable to enum objects with multiple instances
23 November, 2007 – 11:48 amI’ve been looking for some easy ways to enumerate all of the available performance counters on a Win32 platform programatically.
Rather than trawl through the PerfMon counter GUI, or regress back into the millions of raw counters available via WMI, I was looking for a solution somewhere in between.
The ActiveState version of Perl has a Win32::PerfMon module which lets you enumerate cooked performance counter metrics on a Win32 platform. So I started to write a simple script that would list all Objects->Instances->Counters recursively. Sounds simple right?
Unfortunately I found that the module appears faulty when trying to enum Objects that have multiple instances, such as PhysicalDisk and LogicalDisk. Naturally, these are the counters I’m most interested in! After googling to the end of the known universe, I couldn’t find a solution to this problem.
Windows comes with a command line utility called Typeperf which is great for what I ultimately need to script (an unattended batch job that collects performance metrics).
But in order to develop a list of ALL available counters I wrote a mashup in Perl using the Win32::Perfmon module and calls to Typeperf to discover performance counters related to any particular object. That way, I can top and tail the output to my chosen performance counters and not have to worry about the exact typing of these finicky little buggers.
To use:
discoverCounters.pl <serverName>
Output:
.NET CLR Data
.NET CLR Networking
.NET Data Provider for Oracle
.NET Data Provider for SqlServer
.NET CLR Memory
.NET CLR Memory(_Global_)\# Gen 0 Collections
.NET CLR Memory(_Global_)\# Gen 1 Collections
.NET CLR Memory(_Global_)\# Gen 2 Collections
...
Code:
use Win32::PerfMon;
my $server = $ARGV[0] || "VIRTUAL";
my $PerfObj = Win32::PerfMon->new("\\\\$server");
my $Objects = $PerfObj->ListObjects();
foreach $Object (@$Objects)
{
if($Object=~/\bPaging File\b|\bThread\b|\bProcess\b/){
# I prefer to skip counters related to the following objects
# Paging File
# Thread
# Process
print "$Object\n";
} else {
# The following is a list of the possible formats:
# object(parent/instance#index)\counter
$cmd1="typeperf \"$Object(*\/*#*)\\*\" -sc 1";
# object(parent/instance)\counter
$cmd2="typeperf \"$Object(*\/*)\\*\" -sc 1";
# object(instance#index)\counter
$cmd3="typeperf \"$Object(*#*)\\*\" -sc 1";
# object(instance)\counter
$cmd4="typeperf \"$Object(*)\\*\" -sc 1";
# object\counter
$cmd5="typeperf \"$Object\\*\" -sc 1";
# Using typeperf, enum the possible counters
undef $val;
$val=`$cmd1`;
if($val=~/No valid counters/) { $val=`$cmd2`; }
if($val=~/No valid counters/) { $val=`$cmd3`; }
if($val=~/No valid counters/) { $val=`$cmd4`; }
if($val=~/No valid counters/) { $val=`$cmd5`; }
# Clean up and print available counters to display
if($val=~/No valid counters/) {
print "$Object\n";
} elsif ($val=~/$Object/) {
print "$Object\n";
@values = split(',', $val);
foreach $value(@values) {
if($value=~/$Object/) {
$value=~s/"\\\\$server\\//;
$value=~s/"\n.*//;
$value=~s/"$//;
print "\t$value\n";
}
}
}
}
}








