/*++ 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 } }