Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

463 lines
13 KiB

/*++
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>
#define PERF_HEAP hLibHeap
#include <perfutil.h>
#include "perfos.h"
#include "perfosmc.h"
#include "datasys.h"
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;
ULONG ProcessBufSize = LARGE_BUFFER_SIZE;
ULONG dwSysOpenCount = 0;
UCHAR *pProcessBuffer = NULL;
DWORD APIENTRY
OpenSystemObject (
LPWSTR lpDeviceNames
)
{
UNREFERENCED_PARAMETER(lpDeviceNames);
dwSysOpenCount++;
return ERROR_SUCCESS;
}
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;
DWORD dwReturnedBufferSize = 0;
#ifdef DBG
DWORD trialcount = 0;
STARTTIMING;
#endif
// reset the caller's buffer
memset (pTDB, 0, sizeof (PERFSYS_THREAD_DATA_BLOCK));
if (pProcessBuffer == NULL) {
ProcessBufSize = LARGE_BUFFER_SIZE;
pProcessBuffer = ALLOCMEM (ProcessBufSize);
#ifdef DBG
trialcount = 1;
#endif
}
if (pProcessBuffer == NULL) {
status = STATUS_NO_MEMORY;
} else {
while( (status = NtQuerySystemInformation(
SystemProcessInformation,
pProcessBuffer,
ProcessBufSize,
&dwReturnedBufferSize)) ==
STATUS_INFO_LENGTH_MISMATCH ) {
if (ProcessBufSize < dwReturnedBufferSize) {
ProcessBufSize = dwReturnedBufferSize;
}
ProcessBufSize = PAGESIZE_MULTIPLE(ProcessBufSize + SMALL_BUFFER_SIZE);
#ifdef DBG
trialcount++;
#endif
FREEMEM(pProcessBuffer);
pProcessBuffer = ALLOCMEM(ProcessBufSize);
if (pProcessBuffer == NULL) {
status = STATUS_NO_MEMORY;
break;
}
}
}
#ifdef DBG
ENDTIMING (("PERFSYS: %d takes %I64u ms size=%d,%d trials=%d\n", __LINE__, diff,
dwReturnedBufferSize, ProcessBufSize, trialcount));
#endif
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 if (hEventLog != NULL) {
ReportEvent (hEventLog,
EVENTLOG_WARNING_TYPE,
0,
PERFOS_UNABLE_QUERY_PROCESS_INFO,
NULL,
0,
sizeof(DWORD),
NULL,
(LPVOID)&status);
}
#ifdef DBG
ENDTIMING (("PERFSYS: %d takes %I64u ms total\n", __LINE__, diff));
#endif
return ERROR_SUCCESS;
}
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
//
#ifdef DBG
STARTTIMING;
#endif
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
if (hEventLog != NULL) {
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) {
if (hEventLog != NULL) {
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)) {
if (hEventLog != NULL) {
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 = QWORD_MULTIPLE(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;
*lpcbTotalBytes =
pSystemDataDefinition->SystemObjectType.TotalByteLength =
(DWORD) QWORD_MULTIPLE(((LPBYTE) (& pSCD[1])) - (LPBYTE) pSystemDataDefinition);
* lppData = (LPVOID) (((LPBYTE) pSystemDataDefinition) + * lpcbTotalBytes);
*lpNumObjectTypes = 1;
#ifdef DBG
ENDTIMING (("PERFSYS: %d takes %I64u ms total\n", __LINE__, diff));
#endif
return ERROR_SUCCESS;
}
DWORD APIENTRY
CloseSystemObject (
)
/*++
Routine Description:
This routine closes the open handles to the Signal Gen counters.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{
UCHAR *pBuffer;
if (dwSysOpenCount > 0) {
if (!(--dwSysOpenCount)) { // when this is the last thread...
// close stuff here
if ((hLibHeap != NULL) && (pProcessBuffer != NULL)) {
pBuffer = pProcessBuffer;
pProcessBuffer = NULL;
FREEMEM (pBuffer);
ProcessBufSize = 0;
}
}
}
return ERROR_SUCCESS;
}