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

460 lines
13 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
pcall.c
Abstract:
This module contains the Windows NT system call display status.
Author:
Lou Perazzoli (LouP) 5-feb-1992.
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMBER_SERVICE_TABLES 2
//
// Define forward referenced routine prototypes.
//
VOID
SortUlongData (
IN ULONG Count,
IN ULONG Index[],
IN ULONG Data[]
);
#define BUFFER_SIZE 1024
#define DELAY_TIME 1000
#define TOP_CALLS 15
extern UCHAR *CallTable[];
ULONG Index[BUFFER_SIZE];
ULONG CountBuffer1[BUFFER_SIZE];
ULONG CountBuffer2[BUFFER_SIZE];
ULONG CallData[BUFFER_SIZE];
SYSTEM_CONTEXT_SWITCH_INFORMATION SystemSwitchInformation1;
SYSTEM_CONTEXT_SWITCH_INFORMATION SystemSwitchInformation2;
int
__cdecl
main(
int argc,
char *argv[]
)
{
BOOLEAN Active;
BOOLEAN CountSort;
NTSTATUS status;
ULONG i;
COORD dest,cp;
SMALL_RECT Sm;
CHAR_INFO ci;
CONSOLE_SCREEN_BUFFER_INFO sbi;
KPRIORITY SetBasePriority;
INPUT_RECORD InputRecord;
HANDLE ScreenHandle;
DWORD NumRead;
SMALL_RECT Window;
PSYSTEM_CALL_COUNT_INFORMATION CallCountInfo[2];
PSYSTEM_CALL_COUNT_INFORMATION CurrentCallCountInfo;
PSYSTEM_CALL_COUNT_INFORMATION PreviousCallCountInfo;
PULONG CallCountTable[2];
PULONG CurrentCallCountTable;
PULONG PreviousCallCountTable;
PSYSTEM_CONTEXT_SWITCH_INFORMATION SwitchInfo[2];
PSYSTEM_CONTEXT_SWITCH_INFORMATION CurrentSwitchInfo;
PSYSTEM_CONTEXT_SWITCH_INFORMATION PreviousSwitchInfo;
ULONG Current;
ULONG Previous;
LARGE_INTEGER TimeDifference;
ULONG ContextSwitches;
ULONG FindAny;
ULONG FindLast;
ULONG IdleAny;
ULONG IdleCurrent;
ULONG IdleLast;
ULONG PreemptAny;
ULONG PreemptCurrent;
ULONG PreemptLast;
ULONG SwitchToIdle;
ULONG TotalSystemCalls;
ULONG SleepTime=1000;
BOOLEAN ConsoleMode=TRUE;
ULONG TopCalls=TOP_CALLS;
BOOLEAN LoopMode = FALSE;
BOOLEAN ShowSwitches = TRUE;
PULONG p;
ULONG NumberOfCounts;
while (argc > 1) {
argv++;
if (_stricmp(argv[0],"-l") == 0) {
LoopMode = TRUE;
ConsoleMode = FALSE;
TopCalls = BUFFER_SIZE;
argc--;
continue;
}
if (_stricmp(argv[0],"-s") == 0) {
ShowSwitches = FALSE;
argc--;
continue;
}
SleepTime = atoi(argv[0]) * 1000;
ConsoleMode = FALSE;
TopCalls = BUFFER_SIZE;
argc--;
}
SetBasePriority = (KPRIORITY)12;
NtSetInformationProcess(
NtCurrentProcess(),
ProcessBasePriority,
(PVOID) &SetBasePriority,
sizeof(SetBasePriority)
);
Current = 0;
Previous = 1;
CallCountInfo[0] = (PVOID)CountBuffer1;
CallCountInfo[1] = (PVOID)CountBuffer2;
CallCountTable[0] = (PULONG)(CallCountInfo[0] + 1) + NUMBER_SERVICE_TABLES;
CallCountTable[1] = (PULONG)(CallCountInfo[1] + 1) + NUMBER_SERVICE_TABLES;
SwitchInfo[0] = &SystemSwitchInformation1;
SwitchInfo[1] = &SystemSwitchInformation2;
Current = 0;
Previous = 1;
CurrentCallCountInfo = CallCountInfo[0];
CurrentCallCountTable = CallCountTable[0];
CurrentSwitchInfo = SwitchInfo[0];
PreviousCallCountInfo = CallCountInfo[1];
PreviousCallCountTable = CallCountTable[1];
PreviousSwitchInfo = SwitchInfo[1];
//
// Query system information and get the initial call count data.
//
status = NtQuerySystemInformation(SystemCallCountInformation,
(PVOID)PreviousCallCountInfo,
BUFFER_SIZE * sizeof(ULONG),
NULL);
if (NT_SUCCESS(status) == FALSE) {
printf("Query count information failed %lx\n",status);
return(status);
}
//
// Make sure that the number of tables reported by the kernel matches
// our list.
//
if (PreviousCallCountInfo->NumberOfTables != NUMBER_SERVICE_TABLES) {
printf("System call table count (%d) doesn't match PCALL's count (%d)\n",
PreviousCallCountInfo->NumberOfTables, NUMBER_SERVICE_TABLES);
return STATUS_UNSUCCESSFUL;
}
//
// Make sure call count information is available for base services.
//
p = (PULONG)(PreviousCallCountInfo + 1);
if (p[0] == 0) {
printf("No system call count information available for base services\n");
return STATUS_UNSUCCESSFUL;
}
//
// If there is a hole in the count information (i.e., one set of services
// doesn't have counting enabled, but a subsequent one does, then our
// indexes will be off, and we'll display the wrong service names.
//
for ( i = 2; i < NUMBER_SERVICE_TABLES; i++ ) {
if ((p[i] != 0) && (p[i-1] == 0)) {
printf("One or more call count tables empty. PCALL can't run\n");
return STATUS_UNSUCCESSFUL;
}
}
NumberOfCounts = (PreviousCallCountInfo->Length
- sizeof(SYSTEM_CALL_COUNT_INFORMATION)
- NUMBER_SERVICE_TABLES * sizeof(ULONG)) / sizeof(ULONG);
//
// Query system information and get the performance data.
//
if (ShowSwitches) {
status = NtQuerySystemInformation(SystemContextSwitchInformation,
(PVOID)PreviousSwitchInfo,
sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION),
NULL);
if (NT_SUCCESS(status) == FALSE) {
printf("Query context switch information failed %lx\n",status);
return(status);
}
}
if (ConsoleMode) {
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi);
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);
}
//
// Display title.
//
printf( " Count System Service\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);
Active = TRUE;
CountSort = TRUE;
while(TRUE) {
Sleep(SleepTime);
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 'p':
case 'P':
Active = FALSE;
break;
case 'q':
case 'Q':
ExitProcess(0);
break;
default:
Active = TRUE;
break;
}
}
}
//
// If not active, then sleep for 1000ms and attempt to get input
// from the keyboard again.
//
if (Active == FALSE) {
Sleep(1000);
continue;
}
if (ConsoleMode) {
//
// Scroll the screen buffer down to make room for the next display.
//
ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE),
&Sm,
NULL,
dest,
&ci);
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cp);
}
//
// Query system information and get the call count data.
//
status = NtQuerySystemInformation(SystemCallCountInformation,
(PVOID)CurrentCallCountInfo,
BUFFER_SIZE * sizeof(ULONG),
NULL);
if (NT_SUCCESS(status) == FALSE) {
printf("Query count information failed %lx\n",status);
return(status);
}
//
// Query system information and get the performance data.
//
if (ShowSwitches) {
status = NtQuerySystemInformation(SystemContextSwitchInformation,
(PVOID)CurrentSwitchInfo,
sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION),
NULL);
if (NT_SUCCESS(status) == FALSE) {
printf("Query context switch information failed %lx\n",status);
return(status);
}
}
//
// Compute number of system calls for each service, the total
// number of system calls, and the total time for each serviced.
//
TotalSystemCalls = 0;
for (i = 0; i < NumberOfCounts; i += 1) {
CallData[i] = CurrentCallCountTable[i] - PreviousCallCountTable[i];
TotalSystemCalls += CallData[i];
}
//
// Sort the system call data.
//
SortUlongData(NumberOfCounts, Index, CallData);
//
// Compute context switch information.
//
if (ShowSwitches) {
ContextSwitches =
CurrentSwitchInfo->ContextSwitches - PreviousSwitchInfo->ContextSwitches;
FindAny = CurrentSwitchInfo->FindAny - PreviousSwitchInfo->FindAny;
FindLast = CurrentSwitchInfo->FindLast - PreviousSwitchInfo->FindLast;
IdleAny = CurrentSwitchInfo->IdleAny - PreviousSwitchInfo->IdleAny;
IdleCurrent = CurrentSwitchInfo->IdleCurrent - PreviousSwitchInfo->IdleCurrent;
IdleLast = CurrentSwitchInfo->IdleLast - PreviousSwitchInfo->IdleLast;
PreemptAny = CurrentSwitchInfo->PreemptAny - PreviousSwitchInfo->PreemptAny;
PreemptCurrent = CurrentSwitchInfo->PreemptCurrent - PreviousSwitchInfo->PreemptCurrent;
PreemptLast = CurrentSwitchInfo->PreemptLast - PreviousSwitchInfo->PreemptLast;
SwitchToIdle = CurrentSwitchInfo->SwitchToIdle - PreviousSwitchInfo->SwitchToIdle;
}
//
// Display the top services.
//
printf("\n");
for (i = 0; i < TopCalls; i += 1) {
if (CallData[Index[i]] == 0) {
break;
}
printf("%8ld %s\n",
CallData[Index[i]],
CallTable[Index[i]]);
}
printf("\n");
printf("Total System Calls %6ld\n", TotalSystemCalls);
if (ShowSwitches) {
printf("\n");
printf("Context Switch Information\n");
printf(" Find any processor %6ld\n", FindAny);
printf(" Find last processor %6ld\n", FindLast);
printf(" Idle any processor %6ld\n", IdleAny);
printf(" Idle current processor %6ld\n", IdleCurrent);
printf(" Idle last processor %6ld\n", IdleLast);
printf(" Preempt any processor %6ld\n", PreemptAny);
printf(" Preempt current processor %6ld\n", PreemptCurrent);
printf(" Preempt last processor %6ld\n", PreemptLast);
printf(" Switch to idle %6ld\n", SwitchToIdle);
printf("\n");
printf(" Total context switches %6ld\n", ContextSwitches);
}
//
// Delay for the sleep interval swap the information buffers and
// perform another iteration.
//
if (!ConsoleMode) {
_flushall();
}
if ((ConsoleMode == FALSE) && (LoopMode == FALSE)) {
ExitProcess(0);
}
Current = 1 - Current;
Previous = 1 - Previous;
CurrentCallCountInfo = CallCountInfo[Current];
CurrentCallCountTable = CallCountTable[Current];
CurrentSwitchInfo = SwitchInfo[Current];
PreviousCallCountInfo = CallCountInfo[Previous];
PreviousCallCountTable = CallCountTable[Previous];
PreviousSwitchInfo = SwitchInfo[Previous];
}
}