501 lines
9.7 KiB
C
501 lines
9.7 KiB
C
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
CalcPerf.c
|
||
|
||
Abstract:
|
||
|
||
calculate perfoemance statistics
|
||
|
||
Author:
|
||
|
||
|
||
|
||
Environment:
|
||
|
||
Win32
|
||
|
||
Revision History:
|
||
|
||
10-20-91 Initial version
|
||
|
||
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <assert.h>
|
||
#include "calcperf.h"
|
||
#include "..\pstat.h"
|
||
|
||
//SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
||
//SYSTEM_PERFORMANCE_INFORMATION PreviousPerfInfo;
|
||
|
||
#define INFSIZE 60000
|
||
|
||
HANDLE DriverHandle;
|
||
|
||
ULONG NumberOfProcessors;
|
||
ULONG Buffer[INFSIZE/4];
|
||
|
||
extern ULONG UseGlobalMax, GlobalMax;
|
||
|
||
ULONG
|
||
InitPerfInfo()
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize data for perf measurements
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
Number of system processors (0 if error)
|
||
|
||
Revision History:
|
||
|
||
10-21-91 Initial code
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING DriverName;
|
||
NTSTATUS status;
|
||
OBJECT_ATTRIBUTES ObjA;
|
||
IO_STATUS_BLOCK IOSB;
|
||
SYSTEM_BASIC_INFORMATION BasicInfo;
|
||
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PPerfInfo;
|
||
int i;
|
||
|
||
//
|
||
// Init Nt performance interface
|
||
//
|
||
|
||
NtQuerySystemInformation(
|
||
SystemBasicInformation,
|
||
&BasicInfo,
|
||
sizeof(BasicInfo),
|
||
NULL
|
||
);
|
||
|
||
NumberOfProcessors = BasicInfo.NumberOfProcessors;
|
||
|
||
if (NumberOfProcessors > MAX_PROCESSORS) {
|
||
return(0);
|
||
}
|
||
|
||
|
||
//
|
||
// Open P5Stat driver
|
||
//
|
||
|
||
RtlInitUnicodeString(&DriverName, L"\\Device\\PStat");
|
||
InitializeObjectAttributes(
|
||
&ObjA,
|
||
&DriverName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
0,
|
||
0 );
|
||
|
||
status = NtOpenFile (
|
||
&DriverHandle, // return handle
|
||
SYNCHRONIZE | FILE_READ_DATA, // desired access
|
||
&ObjA, // Object
|
||
&IOSB, // io status block
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
|
||
FILE_SYNCHRONOUS_IO_ALERT // open options
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return 0;
|
||
}
|
||
|
||
InitPossibleEventList();
|
||
|
||
return(NumberOfProcessors);
|
||
}
|
||
|
||
|
||
BOOL
|
||
CalcPerf(
|
||
PDISPLAY_ITEM pPerf1
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
calculate and return %cpu time and time periods
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
|
||
Revision History:
|
||
|
||
10-21-91 Initial code
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
ULONG TotalDataPoint;
|
||
ULONG OldGlobalMax;
|
||
PDISPLAY_ITEM pPerf;
|
||
|
||
//
|
||
// get system performance info
|
||
//
|
||
|
||
OldGlobalMax = GlobalMax;
|
||
GlobalMax = 0;
|
||
UpdateInternalStats();
|
||
|
||
for (pPerf = pPerf1; pPerf; pPerf = pPerf->Next) {
|
||
|
||
TotalDataPoint = 0;
|
||
pPerf->SnapData (pPerf);
|
||
|
||
if (pPerf->AutoTotal) {
|
||
//
|
||
// Automatically calc system total by summing each processor
|
||
//
|
||
|
||
switch (pPerf->DisplayMode) {
|
||
case DISPLAY_MODE_TOTAL:
|
||
case DISPLAY_MODE_BREAKDOWN:
|
||
default:
|
||
|
||
for (i=0; i < NumberOfProcessors; i++) {
|
||
TotalDataPoint += pPerf->CurrentDataPoint[i + 1];
|
||
|
||
UpdatePerfInfo1 (
|
||
pPerf->DataList[i + 1],
|
||
pPerf->CurrentDataPoint[i + 1]
|
||
);
|
||
}
|
||
|
||
pPerf->ChangeScale = UpdatePerfInfo (
|
||
pPerf->DataList[0],
|
||
TotalDataPoint,
|
||
&pPerf->Max
|
||
);
|
||
|
||
break;
|
||
|
||
case DISPLAY_MODE_PER_PROCESSOR:
|
||
for (i=0; i < NumberOfProcessors; i++) {
|
||
|
||
TotalDataPoint += pPerf->CurrentDataPoint[i + 1];
|
||
|
||
pPerf->ChangeScale = UpdatePerfInfo (
|
||
pPerf->DataList[i + 1],
|
||
pPerf->CurrentDataPoint[i + 1],
|
||
&pPerf->Max
|
||
);
|
||
|
||
}
|
||
|
||
UpdatePerfInfo1 (pPerf->DataList[0], TotalDataPoint);
|
||
break;
|
||
}
|
||
} else {
|
||
for (i=0; i < NumberOfProcessors+1; i++) {
|
||
pPerf->ChangeScale = UpdatePerfInfo (
|
||
pPerf->DataList[i],
|
||
pPerf->CurrentDataPoint[i],
|
||
&pPerf->Max
|
||
);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (UseGlobalMax && OldGlobalMax != GlobalMax) {
|
||
for (pPerf = pPerf1; pPerf; pPerf = pPerf->Next) {
|
||
pPerf->ChangeScale = TRUE;
|
||
}
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
VOID
|
||
UpdateInternalStats(VOID)
|
||
{
|
||
IO_STATUS_BLOCK IOSB;
|
||
|
||
NtDeviceIoControlFile(
|
||
DriverHandle,
|
||
(HANDLE) NULL, // event
|
||
(PIO_APC_ROUTINE) NULL,
|
||
(PVOID) NULL,
|
||
&IOSB,
|
||
PSTAT_READ_STATS,
|
||
Buffer, // input buffer
|
||
INFSIZE,
|
||
NULL, // output buffer
|
||
0
|
||
);
|
||
}
|
||
|
||
VOID
|
||
SetCounterEvents (PVOID Events, ULONG length)
|
||
{
|
||
IO_STATUS_BLOCK IOSB;
|
||
|
||
NtDeviceIoControlFile(
|
||
DriverHandle,
|
||
(HANDLE) NULL, // event
|
||
(PIO_APC_ROUTINE) NULL,
|
||
(PVOID) NULL,
|
||
&IOSB,
|
||
PSTAT_SET_CESR,
|
||
Events, // input buffer
|
||
length,
|
||
NULL, // output buffer
|
||
0
|
||
);
|
||
}
|
||
|
||
VOID
|
||
SnapNull (
|
||
IN OUT PDISPLAY_ITEM pPerf
|
||
)
|
||
{
|
||
ULONG i;
|
||
|
||
for (i=0; i < NumberOfProcessors; i++) {
|
||
pPerf->CurrentDataPoint[i + 1] = 0;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
SnapInterrupts (
|
||
IN OUT PDISPLAY_ITEM pPerf
|
||
)
|
||
{
|
||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ProcessorInfo[MAX_PROCESSORS];
|
||
ULONG i, l;
|
||
|
||
NtQuerySystemInformation(
|
||
SystemProcessorPerformanceInformation,
|
||
ProcessorInfo,
|
||
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * MAX_PROCESSORS,
|
||
NULL
|
||
);
|
||
|
||
for (i=0; i < NumberOfProcessors; i++) {
|
||
l = ProcessorInfo[i].InterruptCount - pPerf->LastAccumulator[i+1];
|
||
pPerf->LastAccumulator[i+1] = ProcessorInfo[i].InterruptCount;
|
||
pPerf->CurrentDataPoint[i+1] = l / DELAY_SECONDS;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
SnapPrivateInfo (
|
||
IN OUT PDISPLAY_ITEM pPerf
|
||
)
|
||
{
|
||
ULONG i, j, l, len;
|
||
PULONG PrivateStat;
|
||
|
||
|
||
len = *((PULONG) Buffer);
|
||
PrivateStat = (PULONG) ((PUCHAR) Buffer + sizeof(ULONG) + pPerf->SnapParam1);
|
||
|
||
// accumlating data, take delta
|
||
|
||
for (i=0; i < NumberOfProcessors; i++) {
|
||
if (pPerf->Mega) {
|
||
PULONGLONG li = (PULONGLONG) PrivateStat;
|
||
|
||
*li = *li >> 10;
|
||
}
|
||
|
||
j = *PrivateStat / DELAY_SECONDS;
|
||
l = j - pPerf->LastAccumulator[i+1];
|
||
pPerf->LastAccumulator[i+1] = j;
|
||
|
||
if (l > 0) {
|
||
pPerf->CurrentDataPoint[i+1] = l;
|
||
|
||
} else {
|
||
// item wrapped
|
||
pPerf->CurrentDataPoint[i+1] = 0 - l;
|
||
}
|
||
|
||
PrivateStat = (PULONG)((PUCHAR)PrivateStat + len);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
UpdatePerfInfo(
|
||
PULONG DataPointer,
|
||
ULONG NewDataValue,
|
||
PULONG OldMaxValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shift array of DATA_LIST_LENGTH USORTS and add the new value to the
|
||
start of list
|
||
|
||
Arguments:
|
||
|
||
DataPointer - Pointer to the start of a DATA_LIST_LENGTH array
|
||
NewDataValue - Data element to be added
|
||
OldMaxValue - Scale value
|
||
|
||
Return Value:
|
||
|
||
TRUE is MaxValue must be increased or decreased
|
||
|
||
Revision History:
|
||
|
||
10-21-91 Initial code
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
ULONG ScanMax;
|
||
|
||
//
|
||
// Shift DataArray while keeping track of the max value
|
||
//
|
||
|
||
|
||
//
|
||
// Set temp max to 100 to init a minimum maximum
|
||
//
|
||
|
||
ScanMax = 100;
|
||
|
||
for (Index=DATA_LIST_LENGTH-1;Index>=1;Index--) {
|
||
|
||
DataPointer[Index] = DataPointer[Index-1];
|
||
|
||
|
||
|
||
if (DataPointer[Index] > ScanMax) {
|
||
ScanMax = DataPointer[Index];
|
||
}
|
||
}
|
||
|
||
//
|
||
// add and check first value
|
||
//
|
||
|
||
DataPointer[0] = NewDataValue;
|
||
|
||
if (NewDataValue > ScanMax) {
|
||
ScanMax = NewDataValue;
|
||
}
|
||
|
||
//
|
||
// If Max values changed then undate the new max
|
||
// value and return TRUE.
|
||
//
|
||
|
||
if (ScanMax > GlobalMax) {
|
||
GlobalMax = ScanMax;
|
||
}
|
||
|
||
if (ScanMax != *OldMaxValue) {
|
||
if (ScanMax < *OldMaxValue &&
|
||
*OldMaxValue - ScanMax <= *OldMaxValue / 10) {
|
||
//
|
||
// New ScanMax is smaller, but only by a tiny amount
|
||
//
|
||
|
||
return (FALSE);
|
||
}
|
||
|
||
*OldMaxValue = ScanMax;
|
||
return(TRUE);
|
||
}
|
||
|
||
return(FALSE);
|
||
|
||
}
|
||
|
||
VOID
|
||
UpdatePerfInfo1(
|
||
PULONG DataPointer,
|
||
ULONG NewDataValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shift array of DATA_LIST_LENGTH USORTS and add the new value to the
|
||
start of list
|
||
|
||
Arguments:
|
||
|
||
DataPointer - Pointer to the start of a DATA_LIST_LENGTH array
|
||
NewDataValue - Data element to be added
|
||
OldMaxValue - Scale value
|
||
|
||
Return Value:
|
||
|
||
TRUE is MaxValue must be increased or decreased
|
||
|
||
Revision History:
|
||
|
||
10-21-91 Initial code
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
ULONG ScanMax;
|
||
|
||
//
|
||
// Shift DataArray while keeping track of the max value
|
||
//
|
||
|
||
|
||
//
|
||
// Set temp max to 100 to init a minimum maximum
|
||
//
|
||
|
||
ScanMax = 100;
|
||
|
||
for (Index=DATA_LIST_LENGTH-1;Index>=1;Index--) {
|
||
|
||
DataPointer[Index] = DataPointer[Index-1];
|
||
}
|
||
|
||
//
|
||
// add and check first value
|
||
//
|
||
|
||
DataPointer[0] = NewDataValue;
|
||
|
||
return ;
|
||
}
|
||
|