/*++ Copyright (c) 1990 Microsoft Corporation Module Name: CalcPerf.c Abstract: calculate perfoemance statistics Author: Environment: Win32 Revision History: 10-20-91 Initial version --*/ #include #include #include #include #include #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)) { DriverHandle = NULL; 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; if (! DriverHandle) { return; } 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; if (! DriverHandle) { return; } 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 ; }