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