|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
perfsys.c
Abstract:
This file implements an Performance Object that presents System Performance Object information
Created:
Bob Watson 22-Oct-1996
Revision History
--*/
//
// Include Files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winperf.h>
#include <ntprfctr.h>
#include <perfutil.h>
#include "perfos.h"
#include "perfosmc.h"
#include "datasys.h"
static DWORD dwOpenCount = 0; // count of "Open" threads
typedef struct _PERFSYS_THREAD_DATA_BLOCK { DWORD dwProcessCount; DWORD dwNullProcessCount; DWORD dwThreadCount; DWORD dwReadyThreads; // (1) this is the same as the queue length
DWORD dwTerminatedThreads; // (4)
DWORD dwWaitingThreads; // (5)
DWORD dwTransitionThreads; // (6)
} PERFSYS_THREAD_DATA_BLOCK, * PPERFSYS_THREAD_DATA_BLOCK;
#pragma warning (disable : 4706)
DWORD GetSystemThreadInfo ( PPERFSYS_THREAD_DATA_BLOCK pTDB ) { NTSTATUS status; PSYSTEM_THREAD_INFORMATION ThreadInfo; PSYSTEM_PROCESS_INFORMATION ProcessInfo;
ULONG ProcessNumber; ULONG NumThreadInstances; ULONG ThreadNumber; ULONG ProcessBufferOffset; BOOLEAN NullProcess;
UCHAR *pProcessBuffer, *pOldBuffer; ULONG ProcessBufSize = LARGE_BUFFER_SIZE;
DWORD dwReturnedBufferSize;
// reset the caller's buffer
memset (pTDB, 0, sizeof (PERFSYS_THREAD_DATA_BLOCK));
pProcessBuffer = ALLOCMEM (hLibHeap, 0, ProcessBufSize);
if (pProcessBuffer == NULL) { status = ERROR_OUTOFMEMORY; } else { while( (status = NtQuerySystemInformation( SystemProcessInformation, pProcessBuffer, ProcessBufSize, &dwReturnedBufferSize)) == STATUS_INFO_LENGTH_MISMATCH ) { ProcessBufSize += INCREMENT_BUFFER_SIZE; pOldBuffer = pProcessBuffer; if ( !(pProcessBuffer = REALLOCMEM(hLibHeap, 0, pProcessBuffer, ProcessBufSize)) ) { FREEMEM(hLibHeap, 0, pOldBuffer); status = ERROR_OUTOFMEMORY; break; } } }
if ( NT_SUCCESS(status) ) { // walk processes and threads to count 'ready' threads
ProcessNumber = 0; NumThreadInstances = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer; ProcessBufferOffset = 0;
while ( ProcessInfo != NULL ) { if ( ProcessInfo->ImageName.Buffer != NULL || ProcessInfo->NumberOfThreads > 0 ) { NullProcess = FALSE; pTDB->dwProcessCount++; } else { NullProcess = TRUE; pTDB->dwNullProcessCount++; }
ThreadNumber = 0; // Thread number of this process
ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
while ( !NullProcess && ThreadNumber < ProcessInfo->NumberOfThreads ) {
//
// Format and collect Thread data
//
pTDB->dwThreadCount++;
// update thread state counters
if (ThreadInfo->ThreadState == 1) { // then it's READY
pTDB->dwReadyThreads++; } else if (ThreadInfo->ThreadState == 4) { // then it's TERMINATED
pTDB->dwTerminatedThreads++; } else if (ThreadInfo->ThreadState == 5) { // then it's WAITING
pTDB->dwWaitingThreads++; } else if (ThreadInfo->ThreadState == 6) { // then it's in TRANSITION
pTDB->dwTransitionThreads++; }
ThreadNumber++; ThreadInfo++; }
if (ProcessInfo->NextEntryOffset == 0) { // that was the last process
break; }
ProcessBufferOffset += ProcessInfo->NextEntryOffset; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pProcessBuffer[ProcessBufferOffset];
if ( !NullProcess ) { ProcessNumber++; } }
} else { ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFOS_UNABLE_QUERY_PROCESS_INFO, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&status); }
if (pProcessBuffer != NULL) { FREEMEM (hLibHeap, 0, pProcessBuffer); }
return ERROR_SUCCESS;
} #pragma warning (default : 4706)
DWORD APIENTRY CollectSystemObjectData ( IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes ) /*++
Routine Description:
This routine will return the data for the System object
Arguments:
QuerySystemData - Get data about system
IN OUT LPVOID *lppData IN: pointer to the address of the buffer to receive the completed PerfDataBlock and subordinate structures. This routine will append its data to the buffer starting at the point referenced by *lppData. OUT: points to the first byte after the data structure added by this routine. This routine updated the value at lppdata after appending its data.
IN OUT LPDWORD lpcbTotalBytes IN: the address of the DWORD that tells the size in bytes of the buffer referenced by the lppData argument OUT: the number of bytes added by this routine is writted to the DWORD pointed to by this argument
IN OUT LPDWORD NumObjectTypes IN: the address of the DWORD to receive the number of objects added by this routine OUT: the number of objects added by this routine is writted to the DWORD pointed to by this argument
Returns:
0 if successful, else Win 32 error code of failure
--*/ { DWORD TotalLen; // Length of the total return block
NTSTATUS ntStatus;
PSYSTEM_DATA_DEFINITION pSystemDataDefinition; PSYSTEM_COUNTER_DATA pSCD;
SYSTEM_EXCEPTION_INFORMATION ExceptionInfo; SYSTEM_REGISTRY_QUOTA_INFORMATION RegistryInfo; SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo; PERFSYS_THREAD_DATA_BLOCK TDB;
DWORD dwReturnedBufferSize;
// Check for sufficient space for system data
//
pSystemDataDefinition = (SYSTEM_DATA_DEFINITION *) *lppData;
TotalLen = sizeof(SYSTEM_DATA_DEFINITION) + sizeof(SYSTEM_COUNTER_DATA);
TotalLen = QWORD_MULTIPLE (TotalLen);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
//
// Define system data block
//
memcpy (pSystemDataDefinition, &SystemDataDefinition, sizeof(SYSTEM_DATA_DEFINITION));
//
// Format and collect system data
//
// get the exception data
ntStatus = NtQuerySystemInformation( SystemExceptionInformation, &ExceptionInfo, sizeof(ExceptionInfo), NULL );
if (!NT_SUCCESS(ntStatus)) { // unable to collect the data from the system so
// clear the return data structure to prevent bogus data from
// being returned
ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFOS_UNABLE_QUERY_EXCEPTION_INFO, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&ntStatus); memset (&ExceptionInfo, 0, sizeof(ExceptionInfo)); }
// collect registry quota info
memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION)); ntStatus = NtQuerySystemInformation ( SystemRegistryQuotaInformation, (PVOID)&RegistryInfo, sizeof(RegistryInfo), NULL);
if (ntStatus != STATUS_SUCCESS) { ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFOS_UNABLE_QUERY_REGISTRY_QUOTA_INFO, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&ntStatus); // clear the data fields
memset (&RegistryInfo, 0, sizeof (SYSTEM_REGISTRY_QUOTA_INFORMATION)); }
ntStatus = NtQuerySystemInformation( SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), &dwReturnedBufferSize );
if (!NT_SUCCESS(ntStatus)) { ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, 0, PERFOS_UNABLE_QUERY_SYSTEM_TIME_INFO, NULL, 0, sizeof(DWORD), NULL, (LPVOID)&ntStatus); memset (&SysTimeInfo, 0, sizeof(SysTimeInfo)); }
// get thread info
ntStatus = GetSystemThreadInfo (&TDB); if (!NT_SUCCESS(ntStatus)) { memset (&TDB, 0, sizeof(TDB)); }
// update the object perf time (freq is constant)
pSystemDataDefinition->SystemObjectType.PerfTime = SysTimeInfo.CurrentTime;
pSCD = (PSYSTEM_COUNTER_DATA)&pSystemDataDefinition[1];
pSCD->CounterBlock.ByteLength = sizeof(SYSTEM_COUNTER_DATA);
pSCD->ReadOperations = SysPerfInfo.IoReadOperationCount; pSCD->WriteOperations = SysPerfInfo.IoWriteOperationCount; pSCD->OtherIOOperations = SysPerfInfo.IoOtherOperationCount;
pSCD->ReadBytes = SysPerfInfo.IoReadTransferCount.QuadPart; pSCD->WriteBytes = SysPerfInfo.IoWriteTransferCount.QuadPart; pSCD->OtherIOBytes = SysPerfInfo.IoOtherTransferCount.QuadPart;
pSCD->ContextSwitches = SysPerfInfo.ContextSwitches; pSCD->SystemCalls = SysPerfInfo.SystemCalls;
pSCD->TotalReadWrites = SysPerfInfo.IoReadOperationCount + SysPerfInfo.IoWriteOperationCount;
pSCD->SystemElapsedTime = SysTimeInfo.BootTime.QuadPart - SysTimeInfo.BootTimeBias;
// leave room for the ProcessorQueueLength data
pSCD->ProcessorQueueLength = TDB.dwReadyThreads; pSCD->ProcessCount = TDB.dwProcessCount; pSCD->ThreadCount = TDB.dwThreadCount;
pSCD->AlignmentFixups = ExceptionInfo.AlignmentFixupCount ; pSCD->ExceptionDispatches = ExceptionInfo.ExceptionDispatchCount ; pSCD->FloatingPointEmulations = ExceptionInfo.FloatingEmulationCount ;
pSCD->RegistryQuotaUsed = RegistryInfo.RegistryQuotaUsed; pSCD->RegistryQuotaAllowed = RegistryInfo.RegistryQuotaAllowed;
*lppData = (LPBYTE)&pSCD[1];
// round up buffer to the nearest QUAD WORD
*lppData = ALIGN_ON_QWORD (*lppData);
*lpcbTotalBytes = pSystemDataDefinition->SystemObjectType.TotalByteLength = (DWORD)((LPBYTE)*lppData - (LPBYTE)pSystemDataDefinition);
*lpNumObjectTypes = 1;
return ERROR_SUCCESS; }
|