|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
perfproc.c
Abstract:
This file implements an Performance Object that presents Image details performance object data
Created:
Bob Watson 22-Oct-1996
Revision History
--*/ //
// Include Files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <assert.h>
#include <winperf.h>
#include <ntprfctr.h>
#include <perfutil.h>
#include "perfsprc.h"
#include "perfmsg.h"
#include "dataproc.h"
static BOOL bOldestProcessTime = FALSE; static LARGE_INTEGER OldestProcessTime = {0,0};
DWORD APIENTRY CollectProcessObjectData ( IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes ) /*++
Routine Description:
This routine will return the data for the processor object
Arguments:
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
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition; PPROCESS_DATA_DEFINITION pProcessDataDefinition; PPROCESS_COUNTER_DATA pPCD; PROCESS_COUNTER_DATA pcdTotal;
ULONG NumProcessInstances; BOOLEAN NullProcess;
PUNICODE_STRING pProcessName; ULONG ProcessBufferOffset;
pProcessDataDefinition = (PROCESS_DATA_DEFINITION *) *lppData;
//
// Check for sufficient space for Process object type definition
//
TotalLen = sizeof(PROCESS_DATA_DEFINITION) + sizeof (PERF_INSTANCE_DEFINITION) + MAX_VALUE_NAME_LENGTH + sizeof(PROCESS_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return ERROR_MORE_DATA; }
//
// Define Process data block
//
memcpy(pProcessDataDefinition, &ProcessDataDefinition, sizeof(PROCESS_DATA_DEFINITION));
pProcessDataDefinition->ProcessObjectType.PerfTime = PerfTime;
ProcessBufferOffset = 0;
// Now collect data for each process
NumProcessInstances = 0; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) pProcessBuffer;
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pProcessDataDefinition[1];
// adjust TotalLen to be the size of the buffer already in use
TotalLen = sizeof (PROCESS_DATA_DEFINITION);
// zero the total instance buffer
memset (&pcdTotal, 0, sizeof (pcdTotal));
while ( ProcessInfo != NULL ) {
// see if this instance will fit
TotalLen += sizeof(PERF_INSTANCE_DEFINITION) + ((MAX_PROCESS_NAME_LENGTH+1+sizeof(DWORD)) * sizeof(WCHAR)) + sizeof (PROCESS_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return ERROR_MORE_DATA; }
// check for Live processes
// (i.e. name or threads)
pProcessName = NULL;
if ((ProcessInfo->ImageName.Buffer != NULL) || (ProcessInfo->NumberOfThreads > 0)){ // thread is not Dead
// get process name
if (lProcessNameCollectionMethod == PNCM_MODULE_FILE) { pProcessName = GetProcessSlowName (ProcessInfo); } else { pProcessName = GetProcessShortName (ProcessInfo); } NullProcess = FALSE; } else { // thread is dead
NullProcess = TRUE; }
if ( !NullProcess ) {
// get the old process creation time the first time we are in
// this routine
if (!bOldestProcessTime) { if (OldestProcessTime.QuadPart <= 0) { OldestProcessTime = ProcessInfo->CreateTime; } else if (ProcessInfo->CreateTime.QuadPart > 0) { // both time values are not zero, see which one is smaller
if (OldestProcessTime.QuadPart > ProcessInfo->CreateTime.QuadPart) { OldestProcessTime = ProcessInfo->CreateTime; } } }
// get Pool usage for this process
NumProcessInstances++;
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *) &pPCD, 0, 0, (DWORD)-1, (pProcessName ? pProcessName->Buffer : NULL) );
// test structure for Quadword Alignment
assert (((DWORD)(pPCD) & 0x00000007) == 0);
//
// Format and collect Process data
//
pPCD->CounterBlock.ByteLength = sizeof (PROCESS_COUNTER_DATA); //
// Convert User time from 100 nsec units to counter frequency.
//
pcdTotal.ProcessorTime += pPCD->ProcessorTime = ProcessInfo->KernelTime.QuadPart + ProcessInfo->UserTime.QuadPart; pcdTotal.UserTime += pPCD->UserTime = ProcessInfo->UserTime.QuadPart; pcdTotal.KernelTime += pPCD->KernelTime = ProcessInfo->KernelTime.QuadPart;
pcdTotal.PeakVirtualSize += pPCD->PeakVirtualSize = ProcessInfo->PeakVirtualSize; pcdTotal.VirtualSize += pPCD->VirtualSize = ProcessInfo->VirtualSize;
pcdTotal.PageFaults += pPCD->PageFaults = ProcessInfo->PageFaultCount; pcdTotal.PeakWorkingSet += pPCD->PeakWorkingSet = ProcessInfo->PeakWorkingSetSize; pcdTotal.TotalWorkingSet += pPCD->TotalWorkingSet = ProcessInfo->WorkingSetSize;
#ifdef _DATAPROC_PRIVATE_WS_
pcdTotal.PrivateWorkingSet += pPCD->PrivateWorkingSet = ProcessInfo->PrivateWorkingSetSize; pcdTotal.SharedWorkingSet += pPCD->SharedWorkingSet = ProcessInfo->WorkingSetSize - ProcessInfo->PrivateWorkingSetSize; #endif //_DATAPROC_PRIVATE_WS_
pcdTotal.PeakPageFile += pPCD->PeakPageFile = ProcessInfo->PeakPagefileUsage; pcdTotal.PageFile += pPCD->PageFile = ProcessInfo->PagefileUsage;
pcdTotal.PrivatePages += pPCD->PrivatePages = ProcessInfo->PrivatePageCount;
pcdTotal.ThreadCount += pPCD->ThreadCount = ProcessInfo->NumberOfThreads;
// base priority is not totaled
pPCD->BasePriority = ProcessInfo->BasePriority;
// elpased time is not totaled
if (bOldestProcessTime && (ProcessInfo->CreateTime.QuadPart <= 0)) { pPCD->ElapsedTime = OldestProcessTime.QuadPart; } else { pPCD->ElapsedTime = ProcessInfo->CreateTime.QuadPart; }
pPCD->ProcessId = HandleToUlong(ProcessInfo->UniqueProcessId); pPCD->CreatorProcessId = HandleToUlong(ProcessInfo->InheritedFromUniqueProcessId);
pcdTotal.PagedPool += pPCD->PagedPool = (DWORD)ProcessInfo->QuotaPagedPoolUsage; pcdTotal.NonPagedPool += pPCD->NonPagedPool = (DWORD)ProcessInfo->QuotaNonPagedPoolUsage; pcdTotal.HandleCount += pPCD->HandleCount = (DWORD)ProcessInfo->HandleCount;
// update I/O counters
pcdTotal.ReadOperationCount += pPCD->ReadOperationCount = ProcessInfo->ReadOperationCount.QuadPart; pcdTotal.DataOperationCount += pPCD->DataOperationCount = ProcessInfo->ReadOperationCount.QuadPart; pcdTotal.WriteOperationCount += pPCD->WriteOperationCount = ProcessInfo->WriteOperationCount.QuadPart; pcdTotal.DataOperationCount += ProcessInfo->WriteOperationCount.QuadPart; pPCD->DataOperationCount += ProcessInfo->WriteOperationCount.QuadPart; pcdTotal.OtherOperationCount += pPCD->OtherOperationCount = ProcessInfo->OtherOperationCount.QuadPart;
pcdTotal.ReadTransferCount += pPCD->ReadTransferCount = ProcessInfo->ReadTransferCount.QuadPart; pcdTotal.DataTransferCount += pPCD->DataTransferCount = ProcessInfo->ReadTransferCount.QuadPart; pcdTotal.WriteTransferCount += pPCD->WriteTransferCount = ProcessInfo->WriteTransferCount.QuadPart; pcdTotal.DataTransferCount += ProcessInfo->WriteTransferCount.QuadPart; pPCD->DataTransferCount += ProcessInfo->WriteTransferCount.QuadPart; pcdTotal.OtherTransferCount += pPCD->OtherTransferCount = ProcessInfo->OtherTransferCount.QuadPart; // set perfdata pointer to next byte
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pPCD[1]; } // exit if this was the last process in list
if (ProcessInfo->NextEntryOffset == 0) { break; }
// point to next buffer in list
ProcessBufferOffset += ProcessInfo->NextEntryOffset; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pProcessBuffer[ProcessBufferOffset];
}
if (NumProcessInstances > 0) {
// see if the total instance will fit
TotalLen += sizeof(PERF_INSTANCE_DEFINITION) + (MAX_PROCESS_NAME_LENGTH+1+sizeof(DWORD))* sizeof(WCHAR) + sizeof (PROCESS_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = 0; *lpNumObjectTypes = 0; return ERROR_MORE_DATA; }
// it looks like it will fit so create "total" instance
NumProcessInstances++;
// set the Total Elapsed Time to be the current time so that it will
// show up as 0 when displayed.
pcdTotal.ElapsedTime = pProcessDataDefinition->ProcessObjectType.PerfTime.QuadPart;
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *) &pPCD, 0, 0, (DWORD)-1, wszTotal);
// test structure for Quadword Alignment
assert (((DWORD)(pPCD) & 0x00000007) == 0);
//
// Format and collect Process data
//
memcpy (pPCD, &pcdTotal, sizeof (pcdTotal)); pPCD->CounterBlock.ByteLength = sizeof (PROCESS_COUNTER_DATA); pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pPCD[1];
}
// flag so we don't have to get the oldest Process Creation time again.
bOldestProcessTime = TRUE;
// Note number of process instances
pProcessDataDefinition->ProcessObjectType.NumInstances = NumProcessInstances;
//
// Now we know how large an area we used for the
// Process definition, so we can update the offset
// to the next object definition
//
*lpcbTotalBytes = pProcessDataDefinition->ProcessObjectType.TotalByteLength = (DWORD)((PCHAR) pPerfInstanceDefinition - (PCHAR) pProcessDataDefinition);
#if DBG
if (*lpcbTotalBytes > TotalLen ) { DbgPrint ("\nPERFPROC: Process Perf Ctr. Instance Size Underestimated:"); DbgPrint ("\nPERFPROC: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes); } #endif
*lppData = (LPVOID) pPerfInstanceDefinition;
*lpNumObjectTypes = 1;
return ERROR_SUCCESS; }
|