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

1115 lines
30 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
lookmon.c
Abstract:
This module contains the NT/Win32 Lookaside List Monitor
Author:
David N. Cutler (davec) 8-Jun-1996
Revision History:
--*/
#include "perfmtrp.h"
#include <search.h>
#include <malloc.h>
#include <limits.h>
#include <stdlib.h>
//
// Define lookaside query information buffer size and buffers.
//
#define BUFFER_SIZE (64 * 1024 / sizeof(ULONG))
ULONG LargeBuffer1[BUFFER_SIZE];
ULONG LargeBuffer2[BUFFER_SIZE];
//
// Define lookaside output structure and lookaside output information buffer.
//
typedef struct _LOOKASIDE_OUTPUT {
USHORT CurrentDepth;
USHORT MaximumDepth;
ULONG Allocates;
ULONG AllocateRate;
ULONG AllocateHits;
ULONG AllocateMisses;
ULONG Frees;
ULONG FreeRate;
ULONG Type;
ULONG Tag;
ULONG Size;
LOGICAL Changed;
} LOOKASIDE_OUTPUT, *PLOOKASIDE_OUTPUT;
LOOKASIDE_OUTPUT OutputBuffer[1000];
//
// Define sort types and default sort type.
//
#define TOTAL_ALLOCATES 0
#define ALLOCATE_HITS 1
#define ALLOCATE_MISSES 2
#define CURRENT_DEPTH 3
#define MAXIMUM_DEPTH 4
#define RATE 5
#define TAG 6
ULONG SortBy = TAG;
//
// Define pool types to include and default pool type.
//
#define NONPAGED 0
#define PAGED 1
#define BOTH 2
UCHAR *PoolType[] = {
"Nonp",
"Page"
};
ULONG DisplayType = BOTH;
//
// Define miscellaneous values.
//
ULONG DelayTimeMsec = 5000;
ULONG NumberOfInputRecords;
INPUT_RECORD InputRecord;
HANDLE InputHandle;
HANDLE OutputHandle;
DWORD OriginalInputMode;
WORD NormalAttribute;
WORD HighlightAttribute;
ULONG NumberOfCols;
ULONG NumberOfRows;
SIZE_T FirstDetailLine = 0;
CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
ULONG NoHighlight;
//
// Define filter structure and filter data.
//
#define MAX_FILTER 64
typedef struct _FILTER {
union {
UCHAR Tag[4];
ULONG TagUlong;
};
BOOLEAN Exclude;
} FILTER, *PFILTER;
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
)
/*++
Routine Description:
This function compares two lookaside entries and returns the comparison
value based on the comparison type.
Arguments:
E1 - Supplies a pointer to a lookaside output entry.
E2 - Supplies a pointer to a lookaside output entry.
Return Value:
A negative value is returned if the first lookaside entry compares less
than the second lookaside entry. A zero value is returned if the two
lookaside entries compare equal. A positive nonzero value is returned if
the first lookaside entry is greater than the second lookaside entry.
--*/
{
PUCHAR C1;
PUCHAR C2;
PLOOKASIDE_OUTPUT L1 = (PLOOKASIDE_OUTPUT)E1;
PLOOKASIDE_OUTPUT L2 = (PLOOKASIDE_OUTPUT)E2;
LONG U1;
C1 = (PUCHAR)&L1->Tag;
C2 = (PUCHAR)&L2->Tag;
switch (SortBy) {
//
// Sort by number of allocations in descending order.
//
case TOTAL_ALLOCATES:
return L2->Allocates - L1->Allocates;
break;
//
// Sort by number of allocate hits in descending order.
//
case ALLOCATE_HITS:
return L2->AllocateHits - L1->AllocateHits;
break;
//
// Sort by number of allocate misses in descending order.
//
case ALLOCATE_MISSES:
return L2->AllocateMisses - L1->AllocateMisses;
break;
//
// Sort by current depth in descending order.
//
case CURRENT_DEPTH:
return L2->CurrentDepth - L1->CurrentDepth;
break;
//
// Sort by maximum depth in descending order.
//
case MAXIMUM_DEPTH:
return L2->MaximumDepth - L1->MaximumDepth;
break;
//
// Sort by allocation rate in descending order.
//
case RATE:
return L2->AllocateRate - L1->AllocateRate;
break;
//
// Sort by tag, type, and size.
//
case TAG:
U1 = *C1++ - *C2++;
if (U1 == 0) {
U1 = *C1++ - *C2++;
if (U1 == 0) {
U1 = *C1++ - *C2++;
if (U1 == 0) {
U1 = *C1 - *C2;
if (U1 == 0) {
U1 = L1->Type - L2->Type;
if (U1 == 0) {
U1 = L1->Size - L2->Size;
}
}
}
}
}
return U1;
break;
}
return 0;
}
LOGICAL
CheckSingleFilter (
PUCHAR Tag,
PUCHAR Filter
)
{
UCHAR Fc;
ULONG Index;
UCHAR Tc;
//
// Check if tag matches filter.
//
for (Index = 0; Index < 4; Index += 1) {
Fc = *Filter++;
Tc = *Tag++;
if (Fc == '*') {
return TRUE;
} else if (Fc == '?') {
continue;
} else if (Fc != Tc) {
return FALSE;
}
}
return TRUE;
}
LOGICAL
CheckFilters (
PUCHAR Tag
)
{
ULONG Index;
LOGICAL Pass;
//
// If there are no filters, then all tags pass. Otherwise, tags pass or
// do not pass based on whether they are included or excluded.
//
Pass = TRUE;
if (FilterCount != 0) {
//
// If the first filter excludes tags, then any tag not explicitly
// specified passes. If the first filter includes tags, then any
// tag not explicitly specified fails.
//
Pass = Filter[0].Exclude;
for (Index = 0; Index < FilterCount; Index += 1) {
if (CheckSingleFilter(Tag, (PUCHAR)&Filter[Index].Tag) != FALSE) {
Pass = !Filter[Index].Exclude;
break;
}
}
}
return Pass;
}
VOID
AddFilter (
BOOLEAN Exclude,
PCHAR FilterString
)
{
PFILTER f;
ULONG i;
PCHAR p;
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 += 1;
return;
}
VOID
ParseArgs (
int argc,
char *argv[]
)
/*++
Routine Description:
This function parses the input arguments and sets global state variables.
Arguments:
argc - Supplies the number of argument strings.
argv - Supplies a pointer to an array of pointers to argument strings.
Return Value:
None.
--*/
{
char *p;
BOOLEAN exclude;
argc -= 1;
argv += 1;
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)) {
printf("filter string too long: %s\n", p);
ExitProcess(1);
}
AddFilter(exclude, p);
break;
default:
printf("unknown switch: %s\n", p);
ExitProcess(2);
}
} else {
printf("unknown switch: %s\n", p);
ExitProcess(2);
}
}
return;
}
LOGICAL
WriteConsoleLine(
HANDLE OutputHandle,
WORD LineNumber,
LPSTR Text,
LOGICAL 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);
}
}
int
__cdecl
main(
int argc,
char *argv[]
)
/*++
Routine Description:
This function is the main program entry.
Arguments:
argc - Supplies the number of argument strings.
argv - Supplies a pointer to an array of pointers to argument strings.
Return Value:
Final execution status.
--*/
{
SIZE_T ActiveNumber;
CHAR Buffer[512];
SYSTEM_BASIC_INFORMATION BasicInfo;
PULONG CurrentBuffer;
ULONG GeneralNonpagedTotal;
ULONG GeneralPagedTotal;
SIZE_T Index;
BOOLEAN Interactive;
ULONG Length;
ULONG LinesInHeader;
PSYSTEM_LOOKASIDE_INFORMATION LookasideNew;
PSYSTEM_LOOKASIDE_INFORMATION LookasideOld;
HANDLE OriginalOutputHandle;
PLOOKASIDE_OUTPUT Output;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
ULONG PoolNonpagedTotal;
ULONG PoolPagedTotal;
PULONG PreviousBuffer;
NTSTATUS Status;
PULONG TempBuffer;
BOOLEAN DoHelp;
BOOLEAN DoQuit;
UCHAR LastKey;
LONG ScrollDelta;
WORD DisplayLine;
UCHAR T1;
UCHAR T2;
UCHAR T3;
UCHAR T4;
//
// Parse command line arguments.
//
DoHelp = FALSE;
DoQuit = FALSE;
Interactive = TRUE;
ParseArgs(argc, argv);
//
// Get input and output handles.
//
InputHandle = GetStdHandle(STD_INPUT_HANDLE);
OriginalOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
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;
}
}
NtQuerySystemInformation(SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL);
//
// If the priority class on the current process is normal, then raise
// the priority class to high.
//
if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
}
//
// Continuously display the lookaside information until an exit signal
// is received.
//
CurrentBuffer = &LargeBuffer1[0];
PreviousBuffer = &LargeBuffer2[0];
while(TRUE) {
Status = NtQuerySystemInformation(SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL);
if (!NT_SUCCESS(Status)) {
printf("Query performance information failed %lx\n", Status);
break;
}
//
// Query system lookaside information.
//
Status = NtQuerySystemInformation(SystemLookasideInformation,
CurrentBuffer,
BUFFER_SIZE,
&Length);
if (!NT_SUCCESS(Status)) {
printf("Query lookaside information failed %lx\n", Status);
break;
}
//
// Compute total memory allocated to paged and nonpaged lookaside
// lists.
//
Length /= sizeof(SYSTEM_LOOKASIDE_INFORMATION);
LookasideNew = (PSYSTEM_LOOKASIDE_INFORMATION)CurrentBuffer;
GeneralNonpagedTotal = 0;
GeneralPagedTotal = 0;
PoolNonpagedTotal = 0;
PoolPagedTotal = 0;
for (Index = 0; Index < Length; Index += 1) {
if ((LookasideNew->Tag == 'looP') ||
(LookasideNew->Tag == 'LooP')) {
if (LookasideNew->Type == NONPAGED) {
PoolNonpagedTotal +=
(LookasideNew->CurrentDepth * LookasideNew->Size);
} else {
PoolPagedTotal +=
(LookasideNew->CurrentDepth * LookasideNew->Size);
}
} else {
if (LookasideNew->Type == NONPAGED) {
GeneralNonpagedTotal +=
(LookasideNew->CurrentDepth * LookasideNew->Size);
} else {
GeneralPagedTotal +=
(LookasideNew->CurrentDepth * LookasideNew->Size);
}
}
LookasideNew += 1;
}
//
// Output total memory and available memory in kbytes.
//
DisplayLine = 0;
sprintf(Buffer,
" Total Memory: %ldkb Available Memory: %ldkb",
BasicInfo.NumberOfPhysicalPages * (BasicInfo.PageSize / 1024),
PerfInfo.AvailablePages * (BasicInfo.PageSize / 1024));
WriteConsoleLine(OutputHandle,
DisplayLine++,
Buffer,
FALSE);
//
// Output total memory reserved for nonpaged and paged pool.
//
sprintf(Buffer,
" Pool Memory - Nonpaged: %ldkb Paged: %ldkb",
PerfInfo.NonPagedPoolPages * (BasicInfo.PageSize / 1024),
PerfInfo.PagedPoolPages * (BasicInfo.PageSize / 1024));
WriteConsoleLine(OutputHandle,
DisplayLine++,
Buffer,
FALSE);
//
// Output total memory allocated for nonpaged and paged lookaside
// lists.
//
sprintf(Buffer,
" Pool Lookaside - Nonpaged: %ldkb Paged: %ldkb",
PoolNonpagedTotal / 1024,
PoolPagedTotal / 1024);
WriteConsoleLine(OutputHandle,
DisplayLine++,
Buffer,
FALSE);
sprintf(Buffer,
" General Lookaside - Nonpaged: %ldkb Paged: %ldkb",
GeneralNonpagedTotal / 1024,
GeneralPagedTotal / 1024);
WriteConsoleLine(OutputHandle,
DisplayLine++,
Buffer,
FALSE);
//
// Output report headings.
//
WriteConsoleLine(OutputHandle,
DisplayLine++,
" Tag Type Size CurDp MaxDp Allocates Rate Frees Rate A-Hits A-Misses",
FALSE);
WriteConsoleLine(OutputHandle,
DisplayLine++,
NULL,
FALSE);
//
// Extract the specified lookaside information.
//
LinesInHeader = DisplayLine;
LookasideNew = (PSYSTEM_LOOKASIDE_INFORMATION)CurrentBuffer;
LookasideOld = (PSYSTEM_LOOKASIDE_INFORMATION)PreviousBuffer;
Output = &OutputBuffer[0];
for (Index = 0; Index < Length; Index += 1) {
//
// Check if the tag should be extracted.
//
if (!CheckFilters((PUCHAR)&LookasideNew[Index].Tag)) {
continue;
}
//
// Check if the lookaside information should be extracted.
//
if ((DisplayType == BOTH) ||
((LookasideNew[Index].Type == 0) && (DisplayType == NONPAGED)) ||
((LookasideNew[Index].Type != 0) && (DisplayType == PAGED))) {
Output->CurrentDepth = LookasideNew[Index].CurrentDepth;
Output->MaximumDepth = LookasideNew[Index].MaximumDepth;
Output->Allocates = LookasideNew[Index].TotalAllocates;
Output->AllocateRate = Output->Allocates - LookasideNew[Index].AllocateMisses;
if (Output->Allocates != 0) {
Output->AllocateRate = (Output->AllocateRate * 100) / Output->Allocates;
}
Output->Frees = LookasideNew[Index].TotalFrees;
Output->FreeRate = Output->Frees - LookasideNew[Index].FreeMisses;
if (Output->Frees != 0) {
Output->FreeRate = (Output->FreeRate * 100) / Output->Frees;
}
Output->Tag = LookasideNew[Index].Tag;
Output->Type = LookasideNew[Index].Type;
Output->Size = LookasideNew[Index].Size;
if (LookasideNew[Index].Tag == LookasideOld[Index].Tag) {
Output->Changed =
LookasideNew[Index].CurrentDepth != LookasideOld[Index].CurrentDepth;
Output->AllocateMisses =
LookasideNew[Index].AllocateMisses - LookasideOld[Index].AllocateMisses;
Output->AllocateHits =
LookasideNew[Index].TotalAllocates - LookasideOld[Index].TotalAllocates - Output->AllocateMisses;
} else {
Output->Changed = FALSE;
Output->AllocateHits = 0;
Output->AllocateMisses = 0;
}
Output += 1;
}
}
//
// Sort the extracted lookaside information.
//
ActiveNumber = Output - &OutputBuffer[0];
qsort((void *)&OutputBuffer,
(size_t)ActiveNumber,
(size_t)sizeof(LOOKASIDE_OUTPUT),
ulcomp);
//
// Display the selected information.
//
for (Index = FirstDetailLine; Index < ActiveNumber; Index += 1) {
if (DisplayLine >= NumberOfRows) {
break;
}
//
// Check to make sure the tag is displayable.
//
if ((OutputBuffer[Index].Tag == 0) ||
(OutputBuffer[Index].Tag == ' ')) {
OutputBuffer[Index].Tag = 'nknU';
}
T1 = (UCHAR)(OutputBuffer[Index].Tag & 0xff);
T2 = (UCHAR)((OutputBuffer[Index].Tag >> 8) & 0xff);
T3 = (UCHAR)((OutputBuffer[Index].Tag >> 16) & 0xff);
T4 = (UCHAR)((OutputBuffer[Index].Tag >> 24) & 0xff);
if (T1 == 0) {
T1 = ' ';
}
if (T2 == 0) {
T2 = ' ';
}
if (T3 == 0) {
T3 = ' ';
}
if (T4 == 0) {
T4 = ' ';
}
if ((!isalpha(T1) && (T1 != ' ')) ||
(!isalpha(T2) && (T2 != ' ')) ||
(!isalpha(T3) && (T3 != ' ')) ||
(!isalpha(T4) && (T4 != ' '))) {
OutputBuffer[Index].Tag = 'nknU';
}
sprintf(Buffer,
" %c%c%c%c %4s %4ld %5ld %5ld %9ld %3ld%% %9ld %3ld%% %6ld %6ld",
T1,
T2,
T3,
T4,
PoolType[OutputBuffer[Index].Type],
OutputBuffer[Index].Size,
OutputBuffer[Index].CurrentDepth,
OutputBuffer[Index].MaximumDepth,
OutputBuffer[Index].Allocates,
OutputBuffer[Index].AllocateRate,
OutputBuffer[Index].Frees,
OutputBuffer[Index].FreeRate,
OutputBuffer[Index].AllocateHits,
OutputBuffer[Index].AllocateMisses);
WriteConsoleLine(OutputHandle,
DisplayLine++,
Buffer,
OutputBuffer[Index].Changed);
}
//
// If the entire screen is not filled by the selected information,
// then fill the rest of the screen with blank lines.
//
while (DisplayLine < NumberOfRows) {
WriteConsoleLine(OutputHandle,
DisplayLine++,
"",
FALSE);
}
//
// Wait for input or timeout.
//
TempBuffer = PreviousBuffer;
PreviousBuffer = CurrentBuffer;
CurrentBuffer = TempBuffer;
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 * NumberOfRows);
break;
case VK_NEXT:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfRows;
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:
if (ActiveNumber <= (NumberOfRows - LinesInHeader)) {
FirstDetailLine = 0;
} else {
FirstDetailLine = ActiveNumber - NumberOfRows + LinesInHeader;
}
break;
}
if (ScrollDelta != 0) {
if (ScrollDelta < 0) {
if (FirstDetailLine <= (ULONG)-ScrollDelta) {
FirstDetailLine = 0;
} else {
FirstDetailLine += ScrollDelta;
}
} else {
if ((ActiveNumber + LinesInHeader) > NumberOfRows) {
FirstDetailLine += ScrollDelta;
if (FirstDetailLine >= (ActiveNumber - NumberOfRows + LinesInHeader)) {
FirstDetailLine = ActiveNumber - NumberOfRows + LinesInHeader;
}
}
}
}
} else {
switch (toupper( LastKey )) {
case 'Q':
DoQuit = TRUE;
break;
case 'A':
SortBy = TOTAL_ALLOCATES;
FirstDetailLine = 0;
break;
case 'C':
SortBy = CURRENT_DEPTH;
FirstDetailLine = 0;
break;
case 'H':
case '?':
DoHelp = TRUE;
break;
case 'L':
NoHighlight = 1 - NoHighlight;
break;
case 'M':
SortBy = MAXIMUM_DEPTH;
FirstDetailLine = 0;
break;
case 'P':
DisplayType += 1;
if (DisplayType > BOTH) {
DisplayType = NONPAGED;
}
FirstDetailLine = 0;
break;
case 'R':
SortBy = RATE;
FirstDetailLine = 0;
break;
case 'S':
SortBy = ALLOCATE_MISSES;
FirstDetailLine = 0;
break;
case 'T':
SortBy = TAG;
FirstDetailLine = 0;
break;
case 'X':
SortBy = ALLOCATE_HITS;
FirstDetailLine = 0;
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++, " Lookaside Monitor Help", FALSE);
WriteConsoleLine(PopupHandle, n++, NULL, FALSE );
WriteConsoleLine(PopupHandle, n++, " columns:", FALSE );
WriteConsoleLine(PopupHandle, n++, " Tag is the four character name of the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " Type is page(d) or nonp(aged)", FALSE);
WriteConsoleLine(PopupHandle, n++, " Size is size of the pool allocation in bytes", FALSE);
WriteConsoleLine(PopupHandle, n++, " CurDp is the current depth of the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " MaxDp is the maximum depth of the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " Allocates is the total number of allocations from the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " Rate is the percent of allocates that hit in the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " Frees is the total number of frees to the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " Rate is the percent of frees that hit in the lookaside list", FALSE);
WriteConsoleLine(PopupHandle, n++, " A-Hits is the number of allocation hits within the display period", FALSE);
WriteConsoleLine(PopupHandle, n++, " A-Misses is the number of allocation misses within the display period", FALSE);
WriteConsoleLine(PopupHandle, n++, NULL, FALSE);
WriteConsoleLine(PopupHandle, n++, " switches:", FALSE);
WriteConsoleLine(PopupHandle, n++, " ? or h - gives this help", FALSE);
WriteConsoleLine(PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE);
WriteConsoleLine(PopupHandle, n++, " q - quits", FALSE);
WriteConsoleLine(PopupHandle, n++, " p - toggles default pool display between both, page(d), and nonp(aged)", FALSE);
WriteConsoleLine(PopupHandle, n++, NULL, FALSE);
WriteConsoleLine(PopupHandle, n++, " sorting switches:", FALSE);
WriteConsoleLine(PopupHandle, n++, " a - sort by total allocations", FALSE);
WriteConsoleLine(PopupHandle, n++, " c - sort by current depth", FALSE);
WriteConsoleLine(PopupHandle, n++, " m - sort by maximum depth", FALSE);
WriteConsoleLine(PopupHandle, n++, " r - sort by allocation hit rate", FALSE);
WriteConsoleLine(PopupHandle, n++, " s - sort by allocate misses", FALSE);
WriteConsoleLine(PopupHandle, n++, " t - sort by tag, type, and size", FALSE);
WriteConsoleLine(PopupHandle, n++, " x - sort by allocate hits", 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++, 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;
}