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

1126 lines
34 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
poolmon.c
Abstract:
This module contains the NT/Win32 Pool Monitor
Author:
Lou Perazzoli (loup) 13-Sep-1993
Revision History:
--*/
#include "perfmtrp.h"
#include <search.h>
#include <malloc.h>
#include <limits.h>
#include <stdlib.h>
//
// the amount of memory to increase the size
// of the buffer for NtQuerySystemInformation at each step
//
#define BUFFER_SIZE_STEP 65536
#define CPU_USAGE 0
#define QUOTAS 1
#define TAG 0
#define ALLOC 1
#define FREE 2
#define DIFF 3
#define BYTES 4
#define EACH 5
#define LIGHT 6
#define NONPAGED 0
#define PAGED 1
#define BOTH 2
UCHAR *PoolType[] = {
"Nonp ",
"Paged" };
PUCHAR LargeBuffer1 = NULL;
PUCHAR LargeBuffer2 = NULL;
size_t LargeBuffer1Size = 0;
size_t LargeBuffer2Size = 0;
typedef struct _POOLMON_OUT {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
UCHAR NullByte;
BOOLEAN Changed;
ULONG Type;
SIZE_T Allocs;
SIZE_T AllocsDiff;
SIZE_T Frees;
SIZE_T FreesDiff;
SIZE_T Allocs_Frees;
SIZE_T Used;
SIZE_T UsedDiff;
SIZE_T Each;
} POOLMON_OUT, *PPOOLMON_OUT;
POOLMON_OUT OutBuffer[2000];
ULONG DisplayType = BOTH;
ULONG SortBy = TAG;
ULONG Paren;
ULONG DelayTimeMsec = 5000;
BOOLEAN Interactive;
ULONG NumberOfInputRecords;
INPUT_RECORD InputRecord;
HANDLE InputHandle;
HANDLE OriginalOutputHandle;
HANDLE OutputHandle;
DWORD OriginalInputMode;
WORD NormalAttribute;
WORD HighlightAttribute;
ULONG NumberOfCols;
ULONG NumberOfRows;
ULONG NumberOfDetailLines;
SIZE_T FirstDetailLine;
CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
ULONG NoHighlight;
BOOLEAN DisplayTotals = FALSE;
POOLMON_OUT Totals[2];
typedef struct _FILTER {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
BOOLEAN Exclude;
} FILTER, *PFILTER;
#define MAX_FILTER 64
FILTER Filter[MAX_FILTER];
ULONG FilterCount = 0;
VOID
ShowHelpPopup( VOID );
int __cdecl
ulcomp(const void *e1,const void *e2);
int __cdecl
ulcomp(const void *e1,const void *e2)
{
LONG_PTR u1;
switch (SortBy) {
case TAG:
u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2];
if (u1 != 0) {
return u1 > 0 ? 1 : -1;
}
u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3];
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case ALLOC:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->AllocsDiff -
((PPOOLMON_OUT)e1)->AllocsDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Allocs -
((PPOOLMON_OUT)e1)->Allocs;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case FREE:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->FreesDiff -
((PPOOLMON_OUT)e1)->FreesDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Frees -
((PPOOLMON_OUT)e1)->Frees;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case BYTES:
if (Paren & 1) {
u1 = ((PPOOLMON_OUT)e2)->UsedDiff -
((PPOOLMON_OUT)e1)->UsedDiff;
} else {
u1 = ((PPOOLMON_OUT)e2)->Used -
((PPOOLMON_OUT)e1)->Used;
}
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case DIFF:
u1 = ((PPOOLMON_OUT)e2)->Allocs_Frees -
((PPOOLMON_OUT)e1)->Allocs_Frees;
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
case EACH:
u1 = ((PPOOLMON_OUT)e2)->Each -
((PPOOLMON_OUT)e1)->Each;
if (u1 == 0) {
return 0;
} else {
return u1 > 0 ? 1 : -1;
}
break;
default:
return(0);
break;
}
}
BOOLEAN
CheckSingleFilter (
PCHAR Tag,
PCHAR Filter
)
{
ULONG i;
CHAR tc;
CHAR fc;
for ( i = 0; i < 4; i++ ) {
tc = *Tag++;
fc = *Filter++;
if ( fc == '*' ) return TRUE;
if ( fc == '?' ) continue;
if ( tc != fc ) return FALSE;
}
return TRUE;
}
BOOLEAN
CheckFilters (
PSYSTEM_POOLTAG TagInfo
)
{
BOOLEAN pass;
ULONG i;
PCHAR tag;
//
// If there are no filters, all tags pass.
//
if ( FilterCount == 0 ) {
return TRUE;
}
//
// There are filters. If the first filter excludes tags, then any
// tag not explicitly mentioned passes. If the first filter includes
// tags, then any tag not explicitly mentioned fails.
//
if ( Filter[0].Exclude ) {
pass = TRUE;
} else {
pass = FALSE;
}
tag = TagInfo->Tag;
for ( i = 0; i < FilterCount; i++ ) {
if ( CheckSingleFilter( tag, (PCHAR)&Filter[i].Tag ) ) {
pass = !Filter[i].Exclude;
}
}
return pass;
}
VOID
AddFilter (
BOOLEAN Exclude,
PCHAR FilterString
)
{
PFILTER f;
PCHAR p;
ULONG i;
if ( FilterCount == MAX_FILTER ) {
printf( "Too many filters specified. Limit is %d\n", MAX_FILTER );
return;
}
f = &Filter[FilterCount];
p = f->Tag;
for ( i = 0; i < 4; i++ ) {
if ( *FilterString == 0 ) break;
*p++ = *FilterString++;
}
for ( ; i < 4; i++ ) {
*p++ = ' ';
}
f->Exclude = Exclude;
FilterCount++;
return;
}
VOID
ParseArgs (
int argc,
char *argv[]
)
{
char *p;
BOOLEAN exclude;
argc--;
argv++;
while ( argc-- > 0 ) {
p = *argv++;
if ( *p == '-' || *p == '/' ) {
p++;
exclude = TRUE;
switch ( tolower(*p) ) {
case 'i':
exclude = FALSE;
case 'x':
p++;
if ( strlen(p) == 0 ) {
printf( "missing filter string\n" );
ExitProcess( 1 );
} else if ( strlen(p) <= sizeof(ULONG) ) {
AddFilter( exclude, p );
} else {
printf( "filter string too long: %s\n", p );
ExitProcess( 1 );
}
break;
case 'e':
DisplayTotals = TRUE;
break;
case 't':
SortBy = TAG;
break;
case 'a':
SortBy = ALLOC;
break;
case 'u':
case 'b':
SortBy = BYTES;
break;
case 'f':
SortBy = FREE;
break;
case 'd':
SortBy = DIFF;
break;
case 'm':
SortBy = EACH;
case 'l':
NoHighlight = 1 - NoHighlight;
break;
case 'p':
DisplayType += 1;
if (DisplayType > BOTH) {
DisplayType = NONPAGED;
}
break;
case '(':
case ')':
Paren += 1;
break;
default:
printf( "unknown switch: %s\n", p );
ExitProcess( 2 );
}
} else {
printf( "unknown switch: %s\n", p );
ExitProcess( 2 );
}
}
return;
}
BOOL
WriteConsoleLine(
HANDLE OutputHandle,
WORD LineNumber,
LPSTR Text,
BOOL Highlight
)
{
COORD WriteCoord;
DWORD NumberWritten;
DWORD TextLength;
WriteCoord.X = 0;
WriteCoord.Y = LineNumber;
if (!FillConsoleOutputCharacter( OutputHandle,
' ',
NumberOfCols,
WriteCoord,
&NumberWritten
)
) {
return FALSE;
}
if (!FillConsoleOutputAttribute( OutputHandle,
(WORD)((Highlight && !NoHighlight) ? HighlightAttribute : NormalAttribute),
NumberOfCols,
WriteCoord,
&NumberWritten
)
) {
return FALSE;
}
if (Text == NULL || (TextLength = strlen( Text )) == 0) {
return TRUE;
}
else {
return WriteConsoleOutputCharacter( OutputHandle,
Text,
TextLength,
WriteCoord,
&NumberWritten
);
}
}
NTSTATUS
QueryPoolTagInformationIterative(
PUCHAR *CurrentBuffer,
size_t *CurrentBufferSize
)
{
size_t NewBufferSize;
NTSTATUS ReturnedStatus = STATUS_SUCCESS;
if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
return STATUS_INVALID_PARAMETER;
}
//
// there is no buffer allocated yet
//
if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
NewBufferSize = sizeof( UCHAR ) * BUFFER_SIZE_STEP;
*CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// iterate by buffer's size
//
while( *CurrentBuffer != NULL ) {
ReturnedStatus = NtQuerySystemInformation (
SystemPoolTagInformation,
*CurrentBuffer,
(ULONG)*CurrentBufferSize,
NULL );
if( ! NT_SUCCESS(ReturnedStatus) ) {
//
// free the current buffer
//
free( *CurrentBuffer );
*CurrentBuffer = NULL;
if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) {
//
// try with a greater buffer size
//
NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP;
*CurrentBuffer = (PUCHAR) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
//
// allocated new buffer
//
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
*CurrentBufferSize = 0;
}
} else {
*CurrentBufferSize = 0;
}
} else {
//
// NtQuerySystemInformation returned success
//
break;
}
}
return ReturnedStatus;
}
int
__cdecl
main(
int argc,
char *argv[]
)
{
NTSTATUS Status;
ULONG LastCount = 0;
SYSTEM_BASIC_INFORMATION BasicInfo;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
PSYSTEM_POOLTAG_INFORMATION PoolInfo;
PSYSTEM_POOLTAG_INFORMATION PoolInfoOld;
PUCHAR *PreviousBuffer;
PUCHAR *CurrentBuffer;
PUCHAR *TempBuffer;
size_t *PreviousBufferSize;
size_t *CurrentBufferSize;
size_t *TempBufferSize;
BOOLEAN DoHelp;
BOOLEAN DoQuit;
SIZE_T NumberOfPoolTags;
SIZE_T i;
UCHAR LastKey;
PPOOLMON_OUT Out;
LONG ScrollDelta;
WORD DisplayLine, LastDetailRow;
CHAR OutputBuffer[ 512 ];
DoHelp = FALSE;
DoQuit = FALSE;
Interactive = TRUE;
ParseArgs( argc, argv );
InputHandle = GetStdHandle( STD_INPUT_HANDLE );
OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
if (Interactive) {
if (InputHandle == NULL ||
OriginalOutputHandle == NULL ||
!GetConsoleMode( InputHandle, &OriginalInputMode )
) {
Interactive = FALSE;
} else {
OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (OutputHandle == NULL ||
!GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
!SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
!SetConsoleActiveScreenBuffer( OutputHandle ) ||
!SetConsoleMode( InputHandle, 0 )
) {
if (OutputHandle != NULL) {
CloseHandle( OutputHandle );
OutputHandle = NULL;
}
Interactive = FALSE;
} else {
NormalAttribute = 0x1F;
HighlightAttribute = 0x71;
NumberOfCols = OriginalConsoleInfo.dwSize.X;
NumberOfRows = OriginalConsoleInfo.dwSize.Y;
NumberOfDetailLines = NumberOfRows;
}
}
}
NtQuerySystemInformation( SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
}
PreviousBuffer = &LargeBuffer2; // NULL at this point
PreviousBufferSize = &LargeBuffer2Size; // 0 at this point
CurrentBuffer = &LargeBuffer1; // NULL at this point
CurrentBufferSize = &LargeBuffer1Size; // 0 at this point
while(TRUE) {
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Query perf Failed (returned: %lx)\n",
Status);
break;
}
Status = QueryPoolTagInformationIterative(
CurrentBuffer,
CurrentBufferSize
);
if ( !NT_SUCCESS(Status) ) {
printf("Query pooltags failed (returned: %lx)\n"
"Did you remember to enable pool tagging with gflags.exe and reboot?\n",
Status);
break;
}
//
// Calculate pool tags and display information.
//
//
PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)( *CurrentBuffer );
i = PoolInfo->Count;
PoolInfoOld = (PSYSTEM_POOLTAG_INFORMATION)( *PreviousBuffer );
DisplayLine = 0;
sprintf( OutputBuffer,
" Memory:%8ldK Avail:%8ldK PageFlts:%6ld InRam Krnl:%5ldK P:%5ldK",
BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
PerfInfo.PageFaultCount - LastCount,
(PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
(PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
LastCount = PerfInfo.PageFaultCount;
sprintf( OutputBuffer,
" Commit:%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Tag Type Allocs Frees Diff Bytes Per Alloc",
FALSE
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
NULL,
FALSE
);
Out = &OutBuffer[0];
if (DisplayTotals) {
RtlZeroMemory( Totals, sizeof(POOLMON_OUT)*2 );
}
for (i = 0; i < (int)PoolInfo->Count; i++) {
if ( !CheckFilters(&PoolInfo->TagInfo[i]) ) {
continue;
}
if ((PoolInfo->TagInfo[i].NonPagedAllocs != 0) &&
(DisplayType != PAGED)) {
Out->Allocs = PoolInfo->TagInfo[i].NonPagedAllocs;
Out->Frees = PoolInfo->TagInfo[i].NonPagedFrees;
Out->Used = PoolInfo->TagInfo[i].NonPagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[i].NonPagedAllocs -
PoolInfo->TagInfo[i].NonPagedFrees;
Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
Out->Type = NONPAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
if (PoolInfoOld != NULL &&
PoolInfoOld->Count > i &&
PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
) {
Out->AllocsDiff = PoolInfo->TagInfo[i].NonPagedAllocs - PoolInfoOld->TagInfo[i].NonPagedAllocs;
Out->FreesDiff = PoolInfo->TagInfo[i].NonPagedFrees - PoolInfoOld->TagInfo[i].NonPagedFrees;
Out->UsedDiff = PoolInfo->TagInfo[i].NonPagedUsed - PoolInfoOld->TagInfo[i].NonPagedUsed;
if (Out->AllocsDiff != 0 ||
Out->FreesDiff != 0 ||
Out->UsedDiff != 0
) {
Out->Changed = TRUE;
}
} else {
Out->AllocsDiff = 0;
Out->UsedDiff = 0;
Out->FreesDiff = 0;
}
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
if (DisplayTotals) {
Totals[NONPAGED].Allocs += Out->Allocs;
Totals[NONPAGED].AllocsDiff += Out->AllocsDiff;
Totals[NONPAGED].Frees += Out->Frees;
Totals[NONPAGED].FreesDiff += Out->FreesDiff;
Totals[NONPAGED].Allocs_Frees += Out->Allocs_Frees;
Totals[NONPAGED].Used += Out->Used;
Totals[NONPAGED].UsedDiff += Out->UsedDiff;
}
Out += 1;
}
if ((PoolInfo->TagInfo[i].PagedAllocs != 0) &&
(DisplayType != NONPAGED)) {
Out->Allocs = PoolInfo->TagInfo[i].PagedAllocs;
Out->Frees = PoolInfo->TagInfo[i].PagedFrees;
Out->Used = PoolInfo->TagInfo[i].PagedUsed;
Out->Allocs_Frees = PoolInfo->TagInfo[i].PagedAllocs -
PoolInfo->TagInfo[i].PagedFrees;
Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
Out->Type = PAGED;
Out->Changed = FALSE;
Out->NullByte = '\0';
if (PoolInfoOld != NULL &&
PoolInfoOld->Count > i &&
PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
) {
Out->AllocsDiff = PoolInfo->TagInfo[i].PagedAllocs - PoolInfoOld->TagInfo[i].PagedAllocs;
Out->FreesDiff = PoolInfo->TagInfo[i].PagedFrees - PoolInfoOld->TagInfo[i].PagedFrees;
Out->UsedDiff = PoolInfo->TagInfo[i].PagedUsed - PoolInfoOld->TagInfo[i].PagedUsed;
if (Out->AllocsDiff != 0 ||
Out->FreesDiff != 0 ||
Out->UsedDiff != 0
) {
Out->Changed = TRUE;
}
} else {
Out->AllocsDiff = 0;
Out->UsedDiff = 0;
Out->FreesDiff = 0;
}
Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
if (DisplayTotals) {
Totals[PAGED].Allocs += Out->Allocs;
Totals[PAGED].AllocsDiff += Out->AllocsDiff;
Totals[PAGED].Frees += Out->Frees;
Totals[PAGED].FreesDiff += Out->FreesDiff;
Totals[PAGED].Allocs_Frees += Out->Allocs_Frees;
Totals[PAGED].Used += Out->Used;
Totals[PAGED].UsedDiff += Out->UsedDiff;
}
Out += 1;
}
} //end for
//
// Sort the running working set buffer
//
NumberOfPoolTags = Out - &OutBuffer[0];
qsort((void *)&OutBuffer,
(size_t)NumberOfPoolTags,
(size_t)sizeof(POOLMON_OUT),
ulcomp);
LastDetailRow = (WORD)(NumberOfRows - (DisplayTotals ? (DisplayType == BOTH ? 3 : 2) : 0));
for (i = FirstDetailLine; i < NumberOfPoolTags; i++) {
if (DisplayLine >= LastDetailRow) {
break;
}
sprintf( OutputBuffer,
" %4s %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld",
OutBuffer[i].Tag,
PoolType[OutBuffer[i].Type],
OutBuffer[i].Allocs,
OutBuffer[i].AllocsDiff,
OutBuffer[i].Frees,
OutBuffer[i].FreesDiff,
OutBuffer[i].Allocs_Frees,
OutBuffer[i].Used,
OutBuffer[i].UsedDiff,
OutBuffer[i].Each
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
OutBuffer[i].Changed
);
OutBuffer[i].Changed = FALSE;
}
if (DisplayTotals) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
NULL,
FALSE
);
for (i = 0; i < 2; i++) {
if ( (int)DisplayType == i || DisplayType == BOTH ) {
sprintf( OutputBuffer,
"Total %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld",
PoolType[i],
Totals[i].Allocs,
Totals[i].AllocsDiff,
Totals[i].Frees,
Totals[i].FreesDiff,
Totals[i].Allocs_Frees,
Totals[i].Used,
Totals[i].UsedDiff,
Totals[i].Each
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
}
}
}
TempBuffer = PreviousBuffer;
TempBufferSize = PreviousBufferSize;
PreviousBuffer = CurrentBuffer;
PreviousBufferSize = CurrentBufferSize;
CurrentBuffer = TempBuffer;
CurrentBufferSize = TempBufferSize;
while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
//
// Check for input record
//
if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown
) {
LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
if (LastKey < ' ') {
ScrollDelta = 0;
if (LastKey == 'C'-'A'+1) {
DoQuit = TRUE;
} else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
case VK_ESCAPE:
DoQuit = TRUE;
break;
case VK_PRIOR:
ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
break;
case VK_NEXT:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
break;
case VK_UP:
ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_DOWN:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_HOME:
FirstDetailLine = 0;
break;
case VK_END:
FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
break;
}
if (ScrollDelta != 0) {
if (ScrollDelta < 0) {
if (FirstDetailLine <= (ULONG)-ScrollDelta) {
FirstDetailLine = 0;
} else {
FirstDetailLine += ScrollDelta;
}
} else {
FirstDetailLine += ScrollDelta;
if (FirstDetailLine >= (NumberOfPoolTags - NumberOfDetailLines)) {
FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
}
}
}
} else {
switch (toupper( LastKey )) {
case 'Q':
//
// Go to the bottom of the current screen when
// we quit.
//
DoQuit = TRUE;
break;
case 'T':
SortBy = TAG;
FirstDetailLine = 0;
break;
case 'A':
SortBy = ALLOC;
FirstDetailLine = 0;
break;
case 'U':
case 'B':
SortBy = BYTES;
FirstDetailLine = 0;
break;
case 'F':
SortBy = FREE;
FirstDetailLine = 0;
break;
case 'D':
SortBy = DIFF;
FirstDetailLine = 0;
break;
case 'M':
SortBy = EACH;
FirstDetailLine = 0;
break;
case 'L':
NoHighlight = 1 - NoHighlight;
break;
case 'P':
DisplayType += 1;
if (DisplayType > BOTH) {
DisplayType = NONPAGED;
}
FirstDetailLine = 0;
break;
case 'X':
case '(':
case ')':
Paren += 1;
break;
case 'E':
DisplayTotals = !DisplayTotals;
FirstDetailLine = 0;
break;
case 'H':
case '?':
DoHelp = TRUE;
break;
}
}
break;
}
}
if (DoQuit) {
break;
}
if (DoHelp) {
DoHelp = FALSE;
ShowHelpPopup();
}
}
if (Interactive) {
SetConsoleActiveScreenBuffer( OriginalOutputHandle );
SetConsoleMode( InputHandle, OriginalInputMode );
CloseHandle( OutputHandle );
}
ExitProcess( 0 );
return 0;
}
VOID
ShowHelpPopup( VOID )
{
HANDLE PopupHandle;
WORD n;
PopupHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (PopupHandle == NULL) {
return;
}
SetConsoleActiveScreenBuffer( PopupHandle );
n = 0;
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " Poolmon Help", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " columns:", FALSE );
WriteConsoleLine( PopupHandle, n++, " Tag is the 4 byte tag given to the pool allocation", FALSE );
WriteConsoleLine( PopupHandle, n++, " Type is paged or nonp(aged)", FALSE );
WriteConsoleLine( PopupHandle, n++, " Allocs is count of all alloctions", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) is difference in Allocs column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Frees is count of all frees", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) difference in Frees column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Diff is (Allocs - Frees)", FALSE );
WriteConsoleLine( PopupHandle, n++, " Bytes is the total bytes consumed in pool", FALSE );
WriteConsoleLine( PopupHandle, n++, " ( ) difference in Bytes column from last update", FALSE );
WriteConsoleLine( PopupHandle, n++, " Per Alloc is (Bytes / Diff)", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " switches: ", FALSE );
WriteConsoleLine( PopupHandle, n++, " ? or h - gives this help", FALSE );
WriteConsoleLine( PopupHandle, n++, " q - quits", FALSE );
WriteConsoleLine( PopupHandle, n++, " p - toggles default pool display between both, paged, and nonpaged", FALSE );
WriteConsoleLine( PopupHandle, n++, " e - toggles totals lines on and off", FALSE );
WriteConsoleLine( PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " sorting switches:", FALSE );
WriteConsoleLine( PopupHandle, n++, " t - tag a - allocations", FALSE );
WriteConsoleLine( PopupHandle, n++, " f - frees d - difference", FALSE );
WriteConsoleLine( PopupHandle, n++, " b - bytes m - per alloc", FALSE );
WriteConsoleLine( PopupHandle, n++, " (u is the same as b)", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " ) - toggles sort between primary tag and value in ( )", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, " command line switches", FALSE );
WriteConsoleLine( PopupHandle, n++, " -i<tag> - list only matching tags", FALSE );
WriteConsoleLine( PopupHandle, n++, " -x<tag> - list everything except matching tags", FALSE );
WriteConsoleLine( PopupHandle, n++, " <tag> can include * and ?", FALSE );
WriteConsoleLine( PopupHandle, n++, " -peltafdbum) - as listed above", FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
while (TRUE) {
if (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0 &&
ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown &&
InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE
) {
break;
}
}
SetConsoleActiveScreenBuffer( OutputHandle );
CloseHandle( PopupHandle );
return;
}