|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
perfmtr.c
Abstract:
This module contains the NT/Win32 Performance Meter
Author:
Mark Lucovsky (markl) 28-Mar-1991
Revision History:
--*/
#include "perfmtrp.h"
#define CPU_USAGE 0
#define VM_USAGE 1
#define POOL_USAGE 2
#define IO_USAGE 3
#define SRV_USAGE 4
#define CACHE_READS 5
#define VDM_USAGE 6
#define FILE_CACHE 7
#define RESIDENT_MEM 8
//
// Hi-Tech macro to figure out how much a field has changed by.
//
#define delta(FLD) (PerfInfo.FLD - PreviousPerfInfo.FLD)
#define vdelta(FLD) (VdmInfo.FLD - PreviousVdmInfo.FLD)
//
// Delta combining Wait and NoWait cases.
//
#define deltac(FLD) (delta(FLD##Wait) + delta(FLD##NoWait))
//
// Hit Rate Macro (includes a rare trip to MulDivia...)
//
#define hitrate(FLD) (((Changes = delta(FLD)) == 0) ? 0 : \
((Changes < (Misses = delta(FLD##Miss))) ? 0 : \ ((Changes - Misses) * 100 / Changes)))
//
// Hit Rate Macro combining Wait and NoWait cases
//
#define hitratec(FLD) (((Changes = deltac(FLD)) == 0) ? 0 : \
((Changes < (Misses = delta(FLD##WaitMiss) + delta(FLD##NoWaitMiss))) ? 0 : \ ((Changes - Misses) * 100 / Changes)))
//
// Arbitrary percent calculation.
//
#define percent(PART,TOTAL) (((TOTAL) == 0) ? 0 : ((PART) * 100 / (TOTAL)))
int __cdecl main( argc, argv ) int argc; char *argv[]; {
SYSTEM_PERFORMANCE_INFORMATION PerfInfo; SYSTEM_PERFORMANCE_INFORMATION PreviousPerfInfo;
#ifdef i386
SYSTEM_VDM_INSTEMUL_INFO VdmInfo; SYSTEM_VDM_INSTEMUL_INFO PreviousVdmInfo; #endif
LARGE_INTEGER EndTime, BeginTime, ElapsedTime; ULONG DelayTimeMsec; ULONG DelayTimeTicks; ULONG PercentIdle; ULONG IdleDots; ULONG ProcessCount, ThreadCount, FileCount; ULONG Changes, Misses; POBJECT_TYPE_INFORMATION ObjectInfo; WCHAR Buffer[ 256 ]; SYSTEM_FILECACHE_INFORMATION FileCacheInfo; SYSTEM_BASIC_INFORMATION BasicInfo; ULONG PreviousFileCacheFaultCount; BOOLEAN PrintHelp = TRUE; BOOLEAN PrintHeader = TRUE; ULONG DisplayType = CPU_USAGE; INPUT_RECORD InputRecord; HANDLE ScreenHandle; UCHAR LastKey; ULONG NumberOfInputRecords;
SRV_STATISTICS ServerInfo; SRV_STATISTICS PreviousServerInfo; HANDLE ServerDeviceHandle = NULL; IO_STATUS_BLOCK IoStatusBlock; NTSTATUS Status; BOOLEAN ZeroServerStats; STRING DeviceName; UNICODE_STRING DeviceNameU; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE NullDeviceHandle = NULL;
DelayTimeMsec = 2500; DelayTimeTicks = DelayTimeMsec * 10000;
RtlInitString( &DeviceName, "\\Device\\Null" ); RtlAnsiStringToUnicodeString(&DeviceNameU, &DeviceName, TRUE); InitializeObjectAttributes( &ObjectAttributes, &DeviceNameU, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenFile( &NullDeviceHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_NONALERT );
RtlFreeUnicodeString(&DeviceNameU);
if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { printf( "NtOpenFile (NULL device object) failed: %X\n", Status ); return 0; }
ScreenHandle = GetStdHandle (STD_INPUT_HANDLE); if (ScreenHandle == NULL) { printf("Error obtaining screen handle, error was: 0x%lx\n", GetLastError()); return 0; }
Status = NtQuerySystemInformation( SystemBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL );
if (NT_ERROR(Status)) { printf("Basic info failed x%lx\n",Status); return 0; }
NtQuerySystemInformation( SystemPerformanceInformation, &PerfInfo, sizeof(PerfInfo), NULL );
PreviousPerfInfo = PerfInfo; #ifdef i386
NtQuerySystemInformation( SystemVdmInstemulInformation, &VdmInfo, sizeof(VdmInfo), NULL ); PreviousVdmInfo = VdmInfo; #endif
if ( argc > 1 ) { if ( argv[1][0] == '-' || argv[1][0] == '/') { switch ( argv[1][1] ) { case 'C': case 'c': DisplayType = CPU_USAGE; PrintHelp = FALSE; break;
case 'F': case 'f': DisplayType = FILE_CACHE; PrintHelp = FALSE; PreviousFileCacheFaultCount = 0; break;
case 'v': case 'V': DisplayType = VM_USAGE; PrintHelp = FALSE; break;
case 'P': case 'p': DisplayType = POOL_USAGE; PrintHelp = FALSE; break;
case 'I': case 'i': DisplayType = IO_USAGE; PrintHelp = FALSE; break;
#ifdef i386
case 'X': case 'x': DisplayType = VDM_USAGE; PrintHelp = FALSE; break; #endif
case 'S': case 's': DisplayType = SRV_USAGE; PrintHelp = FALSE; ZeroServerStats = TRUE; break;
case 'R': case 'r': DisplayType = CACHE_READS; PrintHelp = FALSE; break;
case '?': default: PrintHelp = FALSE; printf("\nType :\n" "\t'C' for CPU usage\n" "\t'V' for VM usage\n" "\t'F' for File Cache usage\n" "\t'R' for Cache Manager reads and writes\n" "\t'P' for POOL usage\n" "\t'I' for I/O usage\n" #ifdef i386
"\t'X' for x86 Vdm Stats\n" #endif
"\t'S' for Server Stats\n" "\t'H' for header\n" "\t'Q' to quit\n\n"); } } }
while(TRUE) {
while (WaitForSingleObject( ScreenHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
//
// Check for input record
//
if (ReadConsoleInput( ScreenHandle, &InputRecord, 1, &NumberOfInputRecords ) && InputRecord.EventType == KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown ) { LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
//
// Ignore control characters.
//
if (LastKey >= ' ') {
switch (toupper( LastKey )) {
case 'C': DisplayType = CPU_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; break;
case 'F': DisplayType = FILE_CACHE; PrintHeader = TRUE; PrintHelp = FALSE; PreviousFileCacheFaultCount = 0; break;
case 'H': PrintHeader = TRUE; PrintHelp = FALSE; break;
case 'V': DisplayType = VM_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; PreviousPerfInfo = PerfInfo; break;
case 'P': DisplayType = POOL_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; break;
case 'I': DisplayType = IO_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; break;
#ifdef i386
case 'X': DisplayType = VDM_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; break; #endif
case 'S': DisplayType = SRV_USAGE; PrintHeader = TRUE; PrintHelp = FALSE; ZeroServerStats = TRUE; break;
case 'R': DisplayType = CACHE_READS; PrintHeader = TRUE; PrintHelp = FALSE; break;
case 'Q': if (ServerDeviceHandle != NULL) { NtClose(ServerDeviceHandle); } ExitProcess(0);
default: break; } } } } if (PrintHelp) { printf("\nType :\n" "\t'C' for CPU usage\n" "\t'V' for VM usage\n" "\t'F' for File Cache usage\n" "\t'R' for Cache Manager reads and writes\n" "\t'P' for POOL usage\n" "\t'I' for I/O usage\n" #ifdef i386
"\t'X' for x86 Vdm Stats\n" #endif
"\t'S' for Server Stats\n" "\t'H' for header\n" "\t'Q' to quit\n\n"); PrintHelp = FALSE; }
NtQuerySystemInformation( SystemPerformanceInformation, &PerfInfo, sizeof(PerfInfo), NULL ); #ifdef i386
NtQuerySystemInformation( SystemVdmInstemulInformation, &VdmInfo, sizeof(VdmInfo), NULL ); #endif
ObjectInfo = (POBJECT_TYPE_INFORMATION)Buffer; NtQueryObject( NtCurrentProcess(), ObjectTypeInformation, ObjectInfo, sizeof( Buffer ), NULL ); ProcessCount = ObjectInfo->TotalNumberOfObjects;
NtQueryObject( NtCurrentThread(), ObjectTypeInformation, ObjectInfo, sizeof( Buffer ), NULL ); ThreadCount = ObjectInfo->TotalNumberOfObjects;
NtQueryObject( NullDeviceHandle, ObjectTypeInformation, ObjectInfo, sizeof( Buffer ), NULL ); FileCount = ObjectInfo->TotalNumberOfObjects;
switch (DisplayType) {
case CPU_USAGE:
EndTime = *(PLARGE_INTEGER)&PerfInfo.IdleProcessTime; BeginTime = *(PLARGE_INTEGER)&PreviousPerfInfo.IdleProcessTime;
ElapsedTime.QuadPart = EndTime.QuadPart - BeginTime.QuadPart; PercentIdle = ((ElapsedTime.LowPart/BasicInfo.NumberOfProcessors)*100) / DelayTimeTicks;
//
// Sometimes it takes significantly longer than 2.5 seconds
// to make a round trip.
//
if ( PercentIdle > 100 ) {
PercentIdle = 100; }
IdleDots = DOT_BUFF_LEN - (PercentIdle / 10 );
memset(DotBuff,' ',DOT_BUFF_LEN); DotBuff[DOT_BUFF_LEN] = '|'; DotBuff[DOT_BUFF_LEN+1] = '\0'; memset(DotBuff,DOT_CHAR,IdleDots);
if (PrintHeader) { printf("CPU Usage Page Page Page InCore NonP Pgd Incore Pgd Incore Incore Proc Thd\n"); printf(" Flts Aval Pool PgPool Pool Krnl Krnl Drvr Drvr Cache Cnt Cnt\n"); PrintHeader = FALSE; }
printf( "%s", DotBuff ); printf( "%4ld %4ld %4ld (%4ld) %4ld %4ld (%4ld) %4ld (%4ld) (%4ld) %3ld %4ld\n", PerfInfo.PageFaultCount - PreviousPerfInfo.PageFaultCount, PerfInfo.AvailablePages, PerfInfo.PagedPoolPages, PerfInfo.ResidentPagedPoolPage, PerfInfo.NonPagedPoolPages, PerfInfo.TotalSystemCodePages, PerfInfo.ResidentSystemCodePage, PerfInfo.TotalSystemDriverPages, PerfInfo.ResidentSystemDriverPage, PerfInfo.ResidentSystemCachePage, ProcessCount, ThreadCount ); break;
case VM_USAGE:
if (PrintHeader) { printf("avail page COW Tran Cache Demd Read Read Cache Cache Page Write Map Map\n"); printf("pages faults Tran zero flts I/Os flts I/Os writ I/Os write I/O\n"); PrintHeader = FALSE; }
printf( "%5ld %5ld %4ld %5ld %5ld %5ld %5ld %5ld %5ld%5ld%5ld%5ld%6ld%5ld\n", PerfInfo.AvailablePages, PerfInfo.PageFaultCount - PreviousPerfInfo.PageFaultCount, PerfInfo.CopyOnWriteCount - PreviousPerfInfo.CopyOnWriteCount, PerfInfo.TransitionCount - PreviousPerfInfo.TransitionCount, PerfInfo.CacheTransitionCount - PreviousPerfInfo.CacheTransitionCount, PerfInfo.DemandZeroCount - PreviousPerfInfo.DemandZeroCount, PerfInfo.PageReadCount - PreviousPerfInfo.PageReadCount, PerfInfo.PageReadIoCount - PreviousPerfInfo.PageReadIoCount, PerfInfo.CacheReadCount - PreviousPerfInfo.CacheReadCount, PerfInfo.CacheIoCount - PreviousPerfInfo.CacheIoCount, PerfInfo.DirtyPagesWriteCount - PreviousPerfInfo.DirtyPagesWriteCount, PerfInfo.DirtyWriteIoCount - PreviousPerfInfo.DirtyWriteIoCount, PerfInfo.MappedPagesWriteCount - PreviousPerfInfo.MappedPagesWriteCount, PerfInfo.MappedWriteIoCount - PreviousPerfInfo.MappedWriteIoCount );
break;
case CACHE_READS:
if (PrintHeader) { PrintHeader = FALSE; printf(" Map Cnv Pin Copy Mdl Read Fast Fast Fast Lazy Lazy\n"); printf(" Read To Read Read Read Ahed Read Read Read Wrts Wrt\n"); printf(" Hit Pin Hit Hit Hit I/Os Calls Resc Not I/Os Pgs\n"); printf("Count Rate Rate Count Rate Count Rate Count Rate Miss Poss \n"); }
printf("%05ld %4ld %4ld %05ld %4ld %05ld %4ld %05ld %4ld %4ld %5ld %4ld %4ld %4ld %4ld\n", deltac(CcMapData), hitratec(CcMapData), percent(delta(CcPinMappedDataCount),deltac(CcMapData)), deltac(CcPinRead), hitratec(CcPinRead), deltac(CcCopyRead), hitratec(CcCopyRead), deltac(CcMdlRead), hitratec(CcMdlRead), delta(CcReadAheadIos), deltac(CcFastRead), delta(CcFastReadResourceMiss), delta(CcFastReadNotPossible), delta(CcLazyWriteIos), delta(CcLazyWritePages)); break; #ifdef i386
case VDM_USAGE:
if (PrintHeader) { PrintHeader = FALSE; printf("PUSHF POPF IRET HLT CLI STI BOP SEGNOTP\n"); }
printf("%5d %5d %5d %5d %5d %5d %5d %7d\n", vdelta(OpcodePUSHF), vdelta(OpcodePOPF), vdelta(OpcodeIRET), vdelta(OpcodeHLT), vdelta(OpcodeCLI), vdelta(OpcodeSTI), vdelta(BopCount), vdelta(SegmentNotPresent) ); break; #endif
case POOL_USAGE:
if (PrintHeader) { printf("Paged Paged Paged Non Non Non Page Paged Non Commit Commit SysPte\n"); printf("Alloc Freed A-F Alloc Freed A-F Aval Pages Pages Pages Limit Free\n"); PrintHeader = FALSE; }
printf( "%5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %6ld %6ld %7ld\n", PerfInfo.PagedPoolAllocs - PreviousPerfInfo.PagedPoolAllocs, PerfInfo.PagedPoolFrees - PreviousPerfInfo.PagedPoolFrees, PerfInfo.PagedPoolAllocs - PerfInfo.PagedPoolFrees, PerfInfo.NonPagedPoolAllocs - PreviousPerfInfo.NonPagedPoolAllocs, PerfInfo.NonPagedPoolFrees - PreviousPerfInfo.NonPagedPoolFrees, PerfInfo.NonPagedPoolAllocs - PerfInfo.NonPagedPoolFrees, PerfInfo.AvailablePages, PerfInfo.PagedPoolPages, PerfInfo.NonPagedPoolPages, PerfInfo.CommittedPages, PerfInfo.CommitLimit, PerfInfo.FreeSystemPtes );
break;
case IO_USAGE:
if (PrintHeader) { printf(" Read Write Other Read Write Other File File\n"); printf(" I/Os I/Os I/Os Xfer Xfer Xfer Objects Handles\n"); PrintHeader = FALSE; }
printf( "%5ld %5ld %5ld %8ld %8ld %8ld %8ld %8ld\n", PerfInfo.IoReadOperationCount - PreviousPerfInfo.IoReadOperationCount, PerfInfo.IoWriteOperationCount - PreviousPerfInfo.IoWriteOperationCount, PerfInfo.IoOtherOperationCount - PreviousPerfInfo.IoOtherOperationCount, PerfInfo.IoReadTransferCount.QuadPart - PreviousPerfInfo.IoReadTransferCount.QuadPart, PerfInfo.IoWriteTransferCount.QuadPart - PreviousPerfInfo.IoWriteTransferCount.QuadPart, PerfInfo.IoOtherTransferCount.QuadPart - PreviousPerfInfo.IoOtherTransferCount.QuadPart, FileCount, ObjectInfo->TotalNumberOfHandles );
break;
case SRV_USAGE:
if (ServerDeviceHandle == NULL) { RtlInitString( &DeviceName, SERVER_DEVICE_NAME ); RtlAnsiStringToUnicodeString(&DeviceNameU, &DeviceName, TRUE); InitializeObjectAttributes( &ObjectAttributes, &DeviceNameU, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenFile( &ServerDeviceHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_NONALERT );
RtlFreeUnicodeString(&DeviceNameU);
if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { printf( "NtOpenFile (server device object) failed: %X\n", Status ); break; }
}
Status = NtFsControlFile( ServerDeviceHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_SRV_GET_STATISTICS, NULL, 0, &ServerInfo, sizeof(ServerInfo) ); if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { printf( "NtFsControlFile failed: %X\n", Status ); ServerDeviceHandle = NULL; break; }
if (PrintHeader) { printf( " Bytes Bytes Paged NonPaged Logn WItm\n"); printf( " Rcvd Sent Pool Pool Sess File Srch Errs Shtg\n"); PrintHeader = FALSE; }
if (ZeroServerStats) { PreviousServerInfo = ServerInfo; ZeroServerStats = FALSE; }
{ LARGE_INTEGER BytesReceived, BytesSent;
BytesReceived.QuadPart = ServerInfo.TotalBytesReceived.QuadPart - PreviousServerInfo.TotalBytesReceived.QuadPart; BytesSent.QuadPart = ServerInfo.TotalBytesSent.QuadPart - PreviousServerInfo.TotalBytesSent.QuadPart;
printf( "%7ld %7ld %8ld %8ld %4ld %4ld %4ld %4ld %4ld\n", BytesReceived.LowPart, BytesSent.LowPart, ServerInfo.CurrentPagedPoolUsage, ServerInfo.CurrentNonPagedPoolUsage, ServerInfo.CurrentNumberOfSessions, ServerInfo.CurrentNumberOfOpenFiles, ServerInfo.CurrentNumberOfOpenSearches, ServerInfo.LogonErrors, ServerInfo.WorkItemShortages ); }
PreviousServerInfo = ServerInfo; break;
case FILE_CACHE:
if (PrintHeader) { printf("Avail Page Current Peak Fault Fault\n"); printf("Pages Faults Size Kb Size Total Count\n"); PrintHeader = FALSE; }
NtQuerySystemInformation( SystemFileCacheInformation, &FileCacheInfo, sizeof(FileCacheInfo), NULL );
printf( "%5ld %5ld %7ld %7ld %8ld %8ld\n", PerfInfo.AvailablePages, PerfInfo.PageFaultCount - PreviousPerfInfo.PageFaultCount, FileCacheInfo.CurrentSize / 1024, FileCacheInfo.PeakSize / 1024, FileCacheInfo.PageFaultCount, FileCacheInfo.PageFaultCount - PreviousFileCacheFaultCount );
PreviousFileCacheFaultCount = FileCacheInfo.PageFaultCount; break;
} PreviousPerfInfo = PerfInfo; #ifdef i386
PreviousVdmInfo = VdmInfo; #endif
} }
|