windows-nt/Source/XPSP1/NT/sdktools/perfmtr/perfmtr.c
2020-09-26 16:20:57 +08:00

710 lines
23 KiB
C

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