use Win32::PerfLib;

my $Server;
my $ProcessIndex;


$Server = Win32::NodeName unless( $Server = $ARGV[0] );

print "Collecting process info for $Server...\n";
Win32::PerfLib::GetCounterNames( $Server, \%StringIndex );
map { $String{$StringIndex{$_}} = $_; } ( keys( %StringIndex ) );

$ProcessIndex = $String{Process};

# Connect to the server's performance data
$Perf = new Win32::PerfLib( $Server );
if( ! $Perf )
{
    print "Could not obtain the process list.\n";
    exit();
}
$ProcessList = {};

# get the performance data for the process object
$Perf->GetObjectList( $ProcessObject, $ProcessList );
$Perf->Close();

$InstanceHash = $ProcessList->{Objects}->{$ProcessIndex}->{Instances};

foreach my $ProcessObject ( sort( keys( %{$InstanceHash} ) ) )
{
    my $ProcessCounter = $InstanceHash->{$ProcessObject}->{Counters};
    my %ThisProcess;


    $ThisProcess{Name} = $InstanceHash->{$ProcessObject}->{Name};
    foreach my $Attrib ( keys( %$ProcessCounter ) )
    {
        my $AttribName = $StringIndex{$ProcessCounter->{$Attrib}->{CounterNameTitleIndex}};
        $ThisProcess{$AttribName} = Format( $ProcessCounter->{$Attrib}, $ProcessList->{Objects}->{$ProcessIndex} );
    }
    $ProcessList{$ThisProcess{'ID Process'}} = \%ThisProcess;
}

$~ = PROCESS_HEADER;
write;

$~ = PROCESS_INFO;
foreach $Process ( sort( keys( %ProcessList ) ) )
{
    # Don't make $Proc lexicaly scoped since it is used in a formatted
    # write.
    $Proc = $ProcessList{$Process};

    write;

}


sub Format
{
    my( $Proc, $ObjectList ) = @_;
    my $Value = $Proc->{Counter};
    my $Type  = $Proc->{CounterType};
    my $TB = $ObjectList->{PerfFreq};
    my $Y  = $ObjectList->{PerfTime};

    if( PERF_100NSEC_TIMER == $Type )
    {
        $Value = 100 * ( $Value / 1000000 ) ;
    }
    elsif( PERF_ELAPSED_TIME == $Type )
    {
        my( $Hour, $Min, $Sec );
        # Convert the value into seconds...
        $Value = ( $Y - $Value ) / $TB;

        $Hour = $Value / ( 60 * 60 );
        $Min  = ( $Hour - int( $Hour ) ) * 60;
        $Sec  = ( $Min - int( $Min ) ) * 60;
        $Value = sprintf( "%d:%02d:%02d", int( $Hour ), int( $Min ), int( $Sec ) );
    }
    return( $Value );
}

sub FormatNumber
{
    my( $Number ) = @_;
    my( $Suffix ) = "";

    my $K = 1024;
    if( $K <= $Number )
    {
        $Suffix = " K";
        $Number /= $K;
    }

    $Number =~ s/(\.\d{0,2})\d*$/$1/;

    {} while ($Number =~ s/^(-?\d+)(\d{3})/$1,$2/);

    return( $Number . $Suffix );
}


format PROCESS_HEADER =
@||| @||||| @|||||||||||||||| @|||||| @|||||||||||| @|||||||||||| @||||||
PID, Parent, "Process Name", "Threads", "Memory", "Memory Peak", "Handles"
---- ------ ----------------- ------- ------------- ------------- -------
.

format PROCESS_INFO =
@||| @||||| @<<<<<<<<<<<<<<<< @>>>>>> @>>>>>>>>>>>> @>>>>>>>>>>>> @>>>>>>
$Proc->{'ID Process'}, $Proc->{'Creating Process ID'}, $Proc->{Name}, $Proc->{'Thread Count'}, FormatNumber( $Proc->{'Working Set'} ), FormatNumber( $Proc->{'Working Set Peak'} ), $Proc->{'Handle Count'}
.


print "Finished.\n";

