windows-nt/Source/XPSP1/NT/sdktools/perfmtr/top.c

890 lines
28 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
top.c
Abstract:
This module contains the NT/Win32 Top threads Meter
Author:
Another Mark Lucovsky (markl) / Lou Perazzoli (loup) production 5-Aug-1991
Revision History:
--*/
#include "perfmtrp.h"
#include <stdlib.h>
#define BUFFER_SIZE 64*1024
#define CPU_THREAD 0
#define CPU_PROCESS 1
#define FAULTS 2
#define WORKING_SET 3
#define CONTEXT_SWITCHES 4
#define SYSTEM_CALLS 5
PUCHAR g_pLargeBuffer1 = NULL;
PUCHAR g_pLargeBuffer2 = NULL;
DWORD g_dwBufSize1;
DWORD g_dwBufSize2;
WCHAR *NoNameFound = L"No Name Found";
UCHAR *StateTable[] = {
"Initialized",
"Ready",
"Running",
"Standby",
"Terminated",
"Wait:",
"Transition",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
UCHAR *WaitTable[] = {
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"EventPairHigh",
"EventPairLow",
"LpcReceive",
"LpcReply",
"Spare1",
"Spare2",
"Spare3",
"Spare4",
"Spare5",
"Spare6",
"Spare7",
"Spare8",
"Spare9",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
UCHAR *Empty = " ";
PSYSTEM_PROCESS_INFORMATION
FindMatchedProcess (
IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
IN PUCHAR SystemInfoBuffer,
IN PULONG Hint
);
PSYSTEM_THREAD_INFORMATION
FindMatchedThread (
IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
);
typedef struct _TOPCPU {
LARGE_INTEGER TotalTime;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_PROCESS_INFORMATION MatchedProcess;
ULONG Value;
} TOPCPU, *PTOPCPU;
TOPCPU TopCpu[1000];
int
__cdecl main( argc, argv )
int argc;
char *argv[];
{
NTSTATUS Status;
int i,j;
ULONG DelayTimeMsec;
ULONG DelayTimeTicks;
COORD dest,cp;
SMALL_RECT Sm;
CHAR_INFO ci;
CONSOLE_SCREEN_BUFFER_INFO sbi;
KPRIORITY SetBasePriority;
INPUT_RECORD InputRecord;
HANDLE ScreenHandle;
BOOLEAN Active;
DWORD NumRead;
SMALL_RECT Window;
PSYSTEM_THREAD_INFORMATION Thread;
PSYSTEM_THREAD_INFORMATION MatchedThread;
PUCHAR PreviousBuffer;
PUCHAR CurrentBuffer;
PUCHAR TempBuffer;
ULONG Hint;
ULONG Offset1;
int num;
int Type;
ULONG ContextSwitches;
PSYSTEM_PROCESS_INFORMATION CurProcessInfo;
PSYSTEM_PROCESS_INFORMATION MatchedProcess;
LARGE_INTEGER LARGE_ZERO={0,0};
LARGE_INTEGER Ktime;
LARGE_INTEGER Utime;
LARGE_INTEGER TotalTime;
TIME_FIELDS TimeOut;
PTOPCPU PTopCpu;
BOOLEAN bToggle = TRUE;
PDWORD pdwBufSize = NULL;
SetBasePriority = (KPRIORITY) 12;
NtSetInformationProcess(
NtCurrentProcess(),
ProcessBasePriority,
(PVOID) &SetBasePriority,
sizeof(SetBasePriority)
);
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&sbi);
DelayTimeMsec = 2500;
DelayTimeTicks = DelayTimeMsec * 10000;
Window.Left = 0;
Window.Top = 0;
Window.Right = 79;
Window.Bottom = 23;
dest.X = 0;
dest.Y = 23;
ci.Char.AsciiChar = ' ';
ci.Attributes = sbi.wAttributes;
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE),
TRUE,
&Window
);
cp.X = 0;
cp.Y = 0;
Sm.Left = 0;
Sm.Top = 0;
Sm.Right = 79;
Sm.Bottom = 22;
ScrollConsoleScreenBuffer(
GetStdHandle(STD_OUTPUT_HANDLE),
&Sm,
NULL,
dest,
&ci
);
SetConsoleCursorPosition(
GetStdHandle(STD_OUTPUT_HANDLE),
cp
);
printf( " %% Pid Tid Pri Key Start Address ImageName\n");
printf( "___________________________________________________________________\n");
cp.X = 0;
cp.Y = 2;
Sm.Left = 0;
Sm.Top = 2;
Sm.Right = 79;
Sm.Bottom = 22;
ScreenHandle = GetStdHandle (STD_INPUT_HANDLE);
// allocate space for the buffer
g_dwBufSize1 = BUFFER_SIZE;
g_dwBufSize2 = BUFFER_SIZE;
g_pLargeBuffer1 = ( PUCHAR )malloc( sizeof( UCHAR ) * g_dwBufSize1 );
if( g_pLargeBuffer1 == NULL )
{
return 0;
}
g_pLargeBuffer2 = ( PUCHAR )malloc( sizeof( UCHAR ) * g_dwBufSize2 );
if( g_pLargeBuffer2 == NULL )
{
return 0;
}
retry0:
Status = NtQuerySystemInformation(
SystemProcessInformation,
g_pLargeBuffer1,
g_dwBufSize1,
NULL
);
if( Status == STATUS_INFO_LENGTH_MISMATCH )
{
g_dwBufSize1 *= 2;
if( g_pLargeBuffer1 != NULL )
{
free( g_pLargeBuffer1 );
}
g_pLargeBuffer1 = ( PUCHAR )malloc( sizeof( UCHAR ) * g_dwBufSize1 );
if( g_pLargeBuffer1 == NULL )
{
return 0;
}
}
if ( !NT_SUCCESS(Status) ) {
printf("Query Failed %lx\n",Status);
goto retry0;
}
Sleep(DelayTimeMsec);
retry01:
NtSetInformationProcess(
NtCurrentProcess(),
ProcessBasePriority,
(PVOID) &SetBasePriority,
sizeof(SetBasePriority)
);
Status = NtQuerySystemInformation(
SystemProcessInformation,
g_pLargeBuffer2,
g_dwBufSize2,
NULL
);
if( Status == STATUS_INFO_LENGTH_MISMATCH )
{
g_dwBufSize2 *= 2;
if( g_pLargeBuffer2 != NULL )
{
free( g_pLargeBuffer2 );
}
g_pLargeBuffer2 = ( PUCHAR )malloc( sizeof( UCHAR ) * g_dwBufSize2 );
if( g_pLargeBuffer2 == NULL )
{
if( g_pLargeBuffer1 != NULL )
{
free( g_pLargeBuffer1 );
}
return 0;
}
}
if ( !NT_SUCCESS(Status) ) {
printf("Query Failed %lx\n",Status);
goto retry01;
}
PreviousBuffer = &g_pLargeBuffer1[0];
CurrentBuffer = &g_pLargeBuffer2[0];
Active = TRUE;
Type = CPU_PROCESS;
while(TRUE) {
waitkey:
while (PeekConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead) && NumRead != 0) {
if (!ReadConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead)) {
break;
}
if (InputRecord.EventType == KEY_EVENT) {
switch (InputRecord.Event.KeyEvent.uChar.AsciiChar) {
case 'q':
case 'Q':
{
if( CurrentBuffer != NULL )
{
free( CurrentBuffer );
}
if( PreviousBuffer != NULL )
{
free( PreviousBuffer );
}
ExitProcess(0);
}
break;
case 'p':
case 'P':
Active = FALSE;
break;
case 'c':
case 'C':
Type = CPU_PROCESS;
break;
case 'f':
case 'F':
Type = FAULTS;
break;
case 's':
case 'S':
Type = CONTEXT_SWITCHES;
break;
case 't':
case 'T':
Type = CPU_THREAD;
break;
case 'w':
case 'W':
Type = WORKING_SET;
break;
default:
Active = TRUE;
break;
}
}
}
if ( !Active ) {
goto waitkey;
}
ScrollConsoleScreenBuffer(
GetStdHandle(STD_OUTPUT_HANDLE),
&Sm,
NULL,
dest,
&ci
);
SetConsoleCursorPosition(
GetStdHandle(STD_OUTPUT_HANDLE),
cp
);
//
// Calculate top CPU users and display information.
//
//
// Cross check previous process/thread info against current
// process/thread info.
//
Offset1 = 0;
num = 0;
Hint = 0;
TotalTime = LARGE_ZERO;
while (TRUE) {
CurProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CurrentBuffer[Offset1];
//
// Find the corresponding process in the previous array.
//
MatchedProcess = FindMatchedProcess (CurProcessInfo,
PreviousBuffer,
&Hint);
switch (Type) {
case CPU_PROCESS:
case CPU_THREAD:
if (MatchedProcess == NULL) {
TopCpu[num].TotalTime = Ktime;
TopCpu[num].TotalTime.QuadPart =
TopCpu[num].TotalTime.QuadPart +
Utime.QuadPart;
TotalTime.QuadPart = TotalTime.QuadPart +
TopCpu[num].TotalTime.QuadPart;
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = NULL;
num += 1;
} else {
Ktime.QuadPart = CurProcessInfo->KernelTime.QuadPart -
MatchedProcess->KernelTime.QuadPart;
Utime.QuadPart = CurProcessInfo->UserTime.QuadPart -
MatchedProcess->UserTime.QuadPart;
if ((Ktime.QuadPart != 0) ||
(Utime.QuadPart != 0)) {
TopCpu[num].TotalTime = Ktime;
TopCpu[num].TotalTime.QuadPart =
TopCpu[num].TotalTime.QuadPart +
Utime.QuadPart;
TotalTime.QuadPart = TotalTime.QuadPart +
TopCpu[num].TotalTime.QuadPart;
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = MatchedProcess;
num += 1;
}
}
if (CurProcessInfo->NextEntryOffset == 0) {
for (i=0;i<num;i++) {
PTopCpu = &TopCpu[i];
Ktime.QuadPart =
PTopCpu->ProcessInfo->KernelTime.QuadPart +
PTopCpu->ProcessInfo->UserTime.QuadPart;
RtlTimeToTimeFields ( &Ktime, &TimeOut);
printf( "%4ld%% %p %7ld %7ld %7ld %3ld:%02ld:%02ld.%03ld %ws\n",
(PTopCpu->TotalTime.LowPart*100)/TotalTime.LowPart,
PTopCpu->ProcessInfo->UniqueProcessId,
PTopCpu->ProcessInfo->PageFaultCount,
PTopCpu->ProcessInfo->WorkingSetSize,
PTopCpu->ProcessInfo->PrivatePageCount,
TimeOut.Hour,
TimeOut.Minute,
TimeOut.Second,
TimeOut.Milliseconds,
(PTopCpu->ProcessInfo->ImageName.Buffer != NULL) ?
PTopCpu->ProcessInfo->ImageName.Buffer :
NoNameFound);
Thread = (PSYSTEM_THREAD_INFORMATION)(TopCpu[i].ProcessInfo + 1);
if (Type == CPU_THREAD) {
for (j = 0;
j < (int)TopCpu[i].ProcessInfo->NumberOfThreads;
j++) {
if (TopCpu[i].MatchedProcess == NULL) {
MatchedThread = NULL;
} else {
MatchedThread = FindMatchedThread (
Thread,
TopCpu[i].MatchedProcess
);
}
if (MatchedThread == NULL) {
Ktime.QuadPart =
Thread->KernelTime.QuadPart +
Thread->UserTime.QuadPart;
} else {
Ktime.QuadPart =
Thread->KernelTime.QuadPart -
MatchedThread->KernelTime.QuadPart;
Utime.QuadPart =
Thread->UserTime.QuadPart -
MatchedThread->UserTime.QuadPart;
Ktime.QuadPart =
Ktime.QuadPart +
Utime.QuadPart;
}
if (Ktime.LowPart != 0) {
printf(" %4ld%% TID%p Cs %5ld\n",
(Ktime.LowPart*100)/TotalTime.LowPart,
Thread->ClientId.UniqueThread,
Thread->ContextSwitches);
}
Thread += 1;
}
}
}
}
break;
case FAULTS:
if (MatchedProcess == NULL) {
TopCpu[num].Value = CurProcessInfo->PageFaultCount;
TopCpu[num].ProcessInfo = CurProcessInfo;
num += 1;
} else {
TopCpu[num].Value = CurProcessInfo->PageFaultCount -
MatchedProcess->PageFaultCount;
if (TopCpu[num].Value != 0) {
TopCpu[num].ProcessInfo = CurProcessInfo;
num += 1;
}
}
if (CurProcessInfo->NextEntryOffset == 0) {
for (i=0;i<num;i++) {
PTopCpu = &TopCpu[i];
Ktime.QuadPart =
PTopCpu->ProcessInfo->KernelTime.QuadPart +
PTopCpu->ProcessInfo->UserTime.QuadPart;
RtlTimeToTimeFields ( &Ktime, &TimeOut);
printf( "Pf: %4ld %p %7ld %7ld %7ld %3ld:%02ld:%02ld.%03ld %ws\n",
PTopCpu->Value,
PTopCpu->ProcessInfo->UniqueProcessId,
PTopCpu->ProcessInfo->PageFaultCount,
PTopCpu->ProcessInfo->WorkingSetSize,
PTopCpu->ProcessInfo->PrivatePageCount,
TimeOut.Hour,
TimeOut.Minute,
TimeOut.Second,
TimeOut.Milliseconds,
(PTopCpu->ProcessInfo->ImageName.Buffer != NULL) ?
PTopCpu->ProcessInfo->ImageName.Buffer :
NoNameFound);
}
}
break;
case WORKING_SET:
if (MatchedProcess == NULL) {
TopCpu[num].Value = CurProcessInfo->PageFaultCount;
TopCpu[num].ProcessInfo = CurProcessInfo;
num += 1;
} else {
if (CurProcessInfo->WorkingSetSize !=
MatchedProcess->WorkingSetSize) {
TopCpu[num].Value =
(ULONG)(CurProcessInfo->WorkingSetSize - MatchedProcess->WorkingSetSize);
TopCpu[num].ProcessInfo = CurProcessInfo;
num += 1;
}
}
if (CurProcessInfo->NextEntryOffset == 0) {
for (i=0;i<num;i++) {
PTopCpu = &TopCpu[i];
Ktime.QuadPart =
PTopCpu->ProcessInfo->KernelTime.QuadPart +
PTopCpu->ProcessInfo->UserTime.QuadPart;
RtlTimeToTimeFields ( &Ktime, &TimeOut);
printf( "Ws: %4ld %p %7ld %7ld %7ld %3ld:%02ld:%02ld.%03ld %ws\n",
PTopCpu->Value,
PTopCpu->ProcessInfo->UniqueProcessId,
PTopCpu->ProcessInfo->PageFaultCount,
PTopCpu->ProcessInfo->WorkingSetSize,
PTopCpu->ProcessInfo->PrivatePageCount,
TimeOut.Hour,
TimeOut.Minute,
TimeOut.Second,
TimeOut.Milliseconds,
(PTopCpu->ProcessInfo->ImageName.Buffer != NULL) ?
PTopCpu->ProcessInfo->ImageName.Buffer :
NoNameFound);
}
}
break;
case CONTEXT_SWITCHES:
Thread = (PSYSTEM_THREAD_INFORMATION)(CurProcessInfo + 1);
TopCpu[num].Value = 0;
if (MatchedProcess == NULL) {
for (j = 0; j < (int)CurProcessInfo->NumberOfThreads; j++ ) {
TopCpu[num].Value += Thread->ContextSwitches;
Thread += 1;
}
if (TopCpu[num].Value != 0) {
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = NULL;
num += 1;
}
} else {
for (j = 0; j < (int)CurProcessInfo->NumberOfThreads; j++ ) {
MatchedThread = FindMatchedThread (
Thread,
MatchedProcess
);
if (MatchedThread == NULL) {
TopCpu[num].Value += Thread->ContextSwitches;
} else {
TopCpu[num].Value +=
Thread->ContextSwitches - MatchedThread->ContextSwitches;
}
Thread += 1;
}
if (TopCpu[num].Value != 0) {
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = MatchedProcess;
num += 1;
}
}
if (CurProcessInfo->NextEntryOffset == 0) {
for (i=0;i<num;i++) {
PTopCpu = &TopCpu[i];
Ktime.QuadPart =
PTopCpu->ProcessInfo->KernelTime.QuadPart +
PTopCpu->ProcessInfo->UserTime.QuadPart;
RtlTimeToTimeFields ( &Ktime, &TimeOut);
printf( "Cs: %4ld %p %7ld %7ld %7ld %3ld:%02ld:%02ld.%03ld %ws\n",
PTopCpu->Value,
PTopCpu->ProcessInfo->UniqueProcessId,
PTopCpu->ProcessInfo->PageFaultCount,
PTopCpu->ProcessInfo->WorkingSetSize,
PTopCpu->ProcessInfo->PrivatePageCount,
TimeOut.Hour,
TimeOut.Minute,
TimeOut.Second,
TimeOut.Milliseconds,
(PTopCpu->ProcessInfo->ImageName.Buffer != NULL) ?
PTopCpu->ProcessInfo->ImageName.Buffer :
NoNameFound);
Thread = (PSYSTEM_THREAD_INFORMATION)(TopCpu[i].ProcessInfo + 1);
for (j = 0;
j < (int)TopCpu[i].ProcessInfo->NumberOfThreads;
j++) {
ContextSwitches = 0;
if (TopCpu[i].MatchedProcess == NULL) {
MatchedThread = NULL;
} else {
MatchedThread = FindMatchedThread (
Thread,
TopCpu[i].MatchedProcess
);
}
if (MatchedThread == NULL) {
ContextSwitches = Thread->ContextSwitches;
} else {
ContextSwitches =
Thread->ContextSwitches -
MatchedThread->ContextSwitches;
}
if (ContextSwitches != 0) {
printf("\t TID%p Cs %5ld%+3ld\n",
Thread->ClientId.UniqueThread,
Thread->ContextSwitches,
ContextSwitches);
}
Thread += 1;
}
}
}
break;
default:
break;
} //end switch
if (CurProcessInfo->NextEntryOffset == 0) {
break;
}
Offset1 += CurProcessInfo->NextEntryOffset;
} //end while
/*
two snapshot buffers are maintained and swapped around
since these buffers are now dynamic keep the bufsize in
sync
*/
TempBuffer = PreviousBuffer;
PreviousBuffer = CurrentBuffer;
CurrentBuffer = TempBuffer;
pdwBufSize = bToggle ? &g_dwBufSize1 : &g_dwBufSize2;
bToggle = !bToggle;
retry1:
Sleep(DelayTimeMsec);
NtSetInformationProcess(
NtCurrentProcess(),
ProcessBasePriority,
(PVOID) &SetBasePriority,
sizeof(SetBasePriority)
);
Status = NtQuerySystemInformation(
SystemProcessInformation,
( PVOID)CurrentBuffer,
*pdwBufSize,
NULL
);
if( Status == STATUS_INFO_LENGTH_MISMATCH )
{
*pdwBufSize *= 2;
if( CurrentBuffer != NULL )
{
free( CurrentBuffer );
}
CurrentBuffer = ( PUCHAR )malloc( sizeof( UCHAR ) * ( *pdwBufSize ) );
if( CurrentBuffer == NULL )
{
if( PreviousBuffer != NULL )
{
free( PreviousBuffer );
}
return 0;
}
}
if ( !NT_SUCCESS(Status) ) {
printf("Query Failed %lx\n",Status);
goto retry1;
}
}
return(0);
}
PSYSTEM_PROCESS_INFORMATION
FindMatchedProcess (
IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
IN PUCHAR SystemInfoBuffer,
IN OUT PULONG Hint
)
/*++
Routine Description:
This procedure finds the process which corresponds to the ProcessToMatch.
It returns the address of the matching Process, or NULL if no
matching process was found.
Arguments:
ProcessToMatch - Supplies a pointer to the target thread to match.
SystemInfoBuffer - Supples a pointer to the system information
buffer in which to locate the process.
Hint - Supplies and returns a hint for optimizing the searches.
Return Value:
Address of the corresponding Process or NULL.
--*/
{
PSYSTEM_PROCESS_INFORMATION Process;
ULONG Offset2;
Offset2 = *Hint;
while (TRUE) {
Process = (PSYSTEM_PROCESS_INFORMATION)&SystemInfoBuffer[Offset2];
if ((Process->UniqueProcessId ==
ProcessToMatch->UniqueProcessId) &&
((Process->CreateTime.QuadPart ==
ProcessToMatch->CreateTime.QuadPart))) {
*Hint = Offset2 + Process->NextEntryOffset;
return(Process);
}
Offset2 += Process->NextEntryOffset;
if (Offset2 == *Hint) {
*Hint = 0;
return(NULL);
}
if (Process->NextEntryOffset == 0) {
if (*Hint == 0) {
return(NULL);
}
Offset2 = 0;
}
}
}
PSYSTEM_THREAD_INFORMATION
FindMatchedThread (
IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
)
/*++
Routine Description:
This procedure finds thread which corresponds to the ThreadToMatch.
It returns the address of the matching thread, or NULL if no
matching thread was found.
Arguments:
ThreadToMatch - Supplies a pointer to the target thread to match.
MatchedProcess - Supples a pointer to the process which contains
the target thread. The thread information
must follow this process, i.e., this block was
obtain from a NtQuerySystemInformation specifying
PROCESS_INFORMATION.
Return Value:
Address of the corresponding thread from MatchedProcess or NULL.
--*/
{
PSYSTEM_THREAD_INFORMATION Thread;
ULONG i;
Thread = (PSYSTEM_THREAD_INFORMATION)(MatchedProcess + 1);
for (i = 0; i < MatchedProcess->NumberOfThreads; i++) {
if ((Thread->ClientId.UniqueThread ==
ThreadToMatch->ClientId.UniqueThread) &&
((Thread->CreateTime.QuadPart ==
ThreadToMatch->CreateTime.QuadPart))) {
return(Thread);
}
Thread += 1;
}
return(NULL);
}