|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
perfpage.c
Abstract:
This file implements an Performance Object that presents system Page file performance data
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 <assert.h>
#include <ntprfctr.h>
#define PERF_HEAP hLibHeap
#include <perfutil.h>
#include "perfos.h"
#include "perfosmc.h"
#include "datapage.h"
DWORD dwPageOpenCount = 0; // count of "Open" threads
PSYSTEM_PAGEFILE_INFORMATION pSysPageFileInfo = NULL; DWORD dwSysPageFileInfoSize = 0; // size of page file info array
DWORD APIENTRY OpenPageFileObject ( LPWSTR lpDeviceNames )
/*++
Routine Description:
This routine will initialize the data structures used to pass data back to the registry
Arguments:
Pointer to object ID of each device to be opened (PerfGen)
Return Value:
None.
--*/
{ DWORD status = ERROR_SUCCESS; //
// Since WINLOGON is multi-threaded and will call this routine in
// order to service remote performance queries, this library
// must keep track of how many times it has been opened (i.e.
// how many threads have accessed it). the registry routines will
// limit access to the initialization routine to only one thread
// at a time so synchronization (i.e. reentrancy) should not be
// a problem
//
UNREFERENCED_PARAMETER (lpDeviceNames);
if (!dwPageOpenCount) { // allocate the memory for the Page file info
dwSysPageFileInfoSize = LARGE_BUFFER_SIZE;
pSysPageFileInfo = ALLOCMEM (dwSysPageFileInfoSize);
if (pSysPageFileInfo == NULL) { status = ERROR_OUTOFMEMORY; goto OpenExitPoint; } }
dwPageOpenCount++; // increment OPEN counter
status = ERROR_SUCCESS; // for successful exit
OpenExitPoint:
return status; }
DWORD APIENTRY CollectPageFileObjectData ( IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, IN OUT LPDWORD lpNumObjectTypes ) /*++
Routine Description:
This routine will return the data for the XXX 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
DWORD PageFileNumber; DWORD NumPageFileInstances; DWORD dwReturnedBufferSize;
NTSTATUS status;
PSYSTEM_PAGEFILE_INFORMATION pThisPageFile; PPAGEFILE_DATA_DEFINITION pPageFileDataDefinition; PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition; PPAGEFILE_COUNTER_DATA pPFCD; PAGEFILE_COUNTER_DATA TotalPFCD;
//
// Check for sufficient space for the Pagefile object
// and counter type definition records, + one instance and
// one set of counter data
//
#ifdef DBG
STARTTIMING; #endif
TotalLen = sizeof(PAGEFILE_DATA_DEFINITION) + sizeof(PERF_INSTANCE_DEFINITION) + MAX_PATH * sizeof(WCHAR) + sizeof(PAGEFILE_COUNTER_DATA);
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
while ((status = NtQuerySystemInformation( SystemPageFileInformation, // item id
pSysPageFileInfo, // address of buffer to get data
dwSysPageFileInfoSize, // size of buffer
&dwReturnedBufferSize)) == STATUS_INFO_LENGTH_MISMATCH) { dwSysPageFileInfoSize += INCREMENT_BUFFER_SIZE; FREEMEM(pSysPageFileInfo); pSysPageFileInfo = ALLOCMEM (dwSysPageFileInfoSize);
if (pSysPageFileInfo == NULL) { status = STATUS_NO_MEMORY; break; } }
if ( !NT_SUCCESS(status) ) { if (hEventLog != NULL) { ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, 0, PERFOS_UNABLE_QUERY_PAGEFILE_INFO, NULL, 0, sizeof(DWORD), NULL, &status); } *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return RtlNtStatusToDosError(status); } #ifdef DBG
ENDTIMING (("PERFPAGE: %d takes %I64u ms\n", __LINE__, diff)); #endif
pPageFileDataDefinition = (PPAGEFILE_DATA_DEFINITION) *lppData; //
// Define Page File data block
//
memcpy (pPageFileDataDefinition, &PagefileDataDefinition, sizeof(PAGEFILE_DATA_DEFINITION));
// Now load data for each PageFile
// clear the total fields
memset (&TotalPFCD, 0, sizeof(TotalPFCD)); TotalPFCD.CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (PAGEFILE_COUNTER_DATA));
PageFileNumber = 0; NumPageFileInstances = 0;
pThisPageFile = pSysPageFileInfo; // initialize pointer to list of pagefiles
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pPageFileDataDefinition[1];
// the check for NULL pointer is NOT the exit criteria for this loop,
// merely a check to bail out if the first (or any subsequent) pointer
// is NULL. Normally the loop will exit when the NextEntryOffset == 0
while ( pThisPageFile != NULL ) {
// compute the size required for the next instance record
TotalLen = // current bytes already used
(DWORD)((LPBYTE)pPerfInstanceDefinition - (LPBYTE)pPageFileDataDefinition) // + this instance definition
+ sizeof(PERF_INSTANCE_DEFINITION) // + the file (instance) name
+ QWORD_MULTIPLE(pThisPageFile->PageFileName.Length + sizeof(WCHAR)) // + the data block
+ sizeof (PAGEFILE_COUNTER_DATA);
TotalLen = QWORD_MULTIPLE(TotalLen+4); // round up to the next quadword
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
// Build an Instance
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *) &pPFCD, 0, 0, (DWORD)-1, pThisPageFile->PageFileName.Buffer);
//
// Format the pagefile data
//
pPFCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (PAGEFILE_COUNTER_DATA));
pPFCD->PercentInUse = pThisPageFile->TotalInUse; pPFCD->PeakUsageBase = pPFCD->PercentInUseBase = pThisPageFile->TotalSize; pPFCD->PeakUsage = pThisPageFile->PeakUsage;
// update the total accumulators
TotalPFCD.PeakUsageBase = TotalPFCD.PercentInUseBase += pThisPageFile->TotalSize; TotalPFCD.PeakUsage += pThisPageFile->PeakUsage; TotalPFCD.PercentInUse += pThisPageFile->TotalInUse;
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pPFCD[1]; NumPageFileInstances++; PageFileNumber++;
if (pThisPageFile->NextEntryOffset != 0) { pThisPageFile = (PSYSTEM_PAGEFILE_INFORMATION)\ ((BYTE *)pThisPageFile + pThisPageFile->NextEntryOffset); } else { break; } }
if (NumPageFileInstances > 0) { // compute the size required for the next instance record
TotalLen = // current bytes already used
(DWORD)((LPBYTE)pPerfInstanceDefinition - (LPBYTE)pPageFileDataDefinition) // + this instance definition
+ sizeof(PERF_INSTANCE_DEFINITION) // + the file (instance) name
+ QWORD_MULTIPLE((lstrlenW (wszTotal) + 1) * sizeof (WCHAR)) // + the data block
+ sizeof (PAGEFILE_COUNTER_DATA);
TotalLen = QWORD_MULTIPLE(TotalLen+4); // round up to the next quadword
if ( *lpcbTotalBytes < TotalLen ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; }
// Build the Total Instance
MonBuildInstanceDefinition(pPerfInstanceDefinition, (PVOID *)&pPFCD, 0, 0, (DWORD)-1, (LPWSTR)wszTotal);
//
// copy the total data
//
memcpy (pPFCD, &TotalPFCD, sizeof (TotalPFCD));
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) &pPFCD[1]; NumPageFileInstances++; } // Note number of PageFile instances
pPageFileDataDefinition->PagefileObjectType.NumInstances = NumPageFileInstances;
//
// update pointers for return
//
*lpcbTotalBytes = pPageFileDataDefinition->PagefileObjectType.TotalByteLength = (DWORD) QWORD_MULTIPLE(((LPBYTE) pPerfInstanceDefinition) - (LPBYTE) pPageFileDataDefinition); * lppData = (LPVOID) (((LPBYTE) pPageFileDataDefinition) + * lpcbTotalBytes);
#ifdef DBG
if (*lpcbTotalBytes > TotalLen ) { DbgPrint ("\nPERFOS: Paging File Perf Ctr. Instance Size Underestimated:"); DbgPrint ("\nPERFOS: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes); } #endif
*lpNumObjectTypes = 1;
#ifdef DBG
ENDTIMING (("PERFPAGE: %d takes %I64u ms total\n", __LINE__, diff)); #endif
return ERROR_SUCCESS; }
DWORD APIENTRY ClosePageFileObject ( ) /*++
Routine Description:
This routine closes the open handles to the Signal Gen counters.
Arguments:
None.
Return Value:
ERROR_SUCCESS
--*/
{ if (dwPageOpenCount > 0) { if (!(--dwPageOpenCount)) { // when this is the last thread...
// close stuff here
if (hLibHeap != NULL) { if (pSysPageFileInfo != NULL) { FREEMEM (pSysPageFileInfo); pSysPageFileInfo = NULL; } } } } else { // if open count == 0, then this should be null
assert (pSysPageFileInfo == NULL); }
return ERROR_SUCCESS;
}
|