641 lines
14 KiB
C
641 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
perfhist.c
|
||
|
||
Abstract:
|
||
|
||
This file implements the extensible objects for the HISTGRAM object type
|
||
|
||
Author:
|
||
|
||
Stephane Plante (2/2/95)
|
||
|
||
--*/
|
||
|
||
//
|
||
// Include Files
|
||
//
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <ntstatus.h>
|
||
#include <windows.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <winperf.h>
|
||
#include <winioctl.h>
|
||
#include <malloc.h>
|
||
#include <stdio.h>
|
||
#include "histctrs.h"
|
||
#include "perfmsg.h"
|
||
#include "perfutil.h"
|
||
#include "datahist.h"
|
||
|
||
#define BUFF_SIZE 650
|
||
|
||
//
|
||
// References to constants which initialize the object type definitions
|
||
//
|
||
|
||
extern HISTGRAM_DATA_DEFINITION HistGramDataDefinition;
|
||
|
||
//
|
||
// Histgram Data Structures
|
||
//
|
||
|
||
typedef struct _HIST_DEVICE_DATA {
|
||
HANDLE hFileHandle;
|
||
UNICODE_STRING DeviceName;
|
||
} HIST_DEVICE_DATA, *PHIST_DEVICE_DATA;
|
||
|
||
PHIST_DEVICE_DATA pHistDeviceData = NULL;
|
||
ULONG MaxHistDeviceName = 0;
|
||
ULONG NumberOfHistDevices = 0;
|
||
|
||
PVOID pHistDataBuffer = NULL;
|
||
ULONG HistDataBufferSize = 0;
|
||
|
||
|
||
//
|
||
// Function Prototypes
|
||
//
|
||
//
|
||
// These are used to insure that the data collection functions
|
||
// accessed by the perflib will have the correct calling format.
|
||
//
|
||
|
||
PM_OPEN_PROC OpenHistGramPerformanceData;
|
||
PM_COLLECT_PROC CollectHistGramPerformanceData;
|
||
PM_CLOSE_PROC CloseHistGramPerformanceData;
|
||
|
||
DWORD APIENTRY OpenHistGramPerformanceData(LPWSTR);
|
||
DWORD APIENTRY CollectHistGramPerformanceData(LPWSTR, LPVOID *, LPDWORD, LPDWORD);
|
||
DWORD APIENTRY CloseHistGramPerformanceData(void);
|
||
|
||
|
||
DWORD APIENTRY
|
||
OpenHistGramPerformanceData(
|
||
IN LPWSTR lpDeviceNames
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will open the necessarry file handles to obtain performance data from
|
||
the HISTGRAM device driver. It will then call the device driver and determine
|
||
how much memory must be allocated for the histogram.
|
||
|
||
Arguments:
|
||
|
||
lpDeviceNames
|
||
Pointer to Object ID of each device to be opened
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
PUCHAR SubKeyLinkage="system\\currentcontrolset\\services\\histgram\\linkage";
|
||
PUCHAR Linkage="Export";
|
||
CHAR pBuffer[BUFF_SIZE];
|
||
CHAR *lpLocalDeviceNames = pBuffer;
|
||
LONG status;
|
||
LONG status2;
|
||
LONG Type;
|
||
ULONG Size;
|
||
HKEY Key;
|
||
HANDLE hFileHandle;
|
||
UNICODE_STRING fileString;
|
||
STRING nameString;
|
||
NTSTATUS ntStatus;
|
||
PHIST_DEVICE_DATA pTemp;
|
||
DWORD dwFirstCounter;
|
||
DWORD dwFirstHelp;
|
||
|
||
MonOpenEventLog();
|
||
|
||
REPORT_INFORMATION(HIST_OPEN_ENTERED, LOG_VERBOSE);
|
||
|
||
MaxHistDeviceName = 0;
|
||
NumberOfHistDevices = 0;
|
||
HistDataBufferSize = 0;
|
||
|
||
Size = BUFF_SIZE;
|
||
|
||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
SubKeyLinkage,
|
||
0,
|
||
KEY_READ,
|
||
&Key);
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
status = RegQueryValueEx(Key,
|
||
Linkage,
|
||
NULL,
|
||
&Type,
|
||
pBuffer,
|
||
&Size);
|
||
|
||
if (status == ERROR_SUCCESS) {
|
||
|
||
status2 = RegCloseKey(Key);
|
||
|
||
} else {
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
status = RegOpenKeyEx(
|
||
HKEY_LOCAL_MACHINE,
|
||
"SYSTEM\\CurrentControlSet\\Services\\Histgram\\Performance",
|
||
0L,
|
||
KEY_ALL_ACCESS,
|
||
&Key);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
Size = sizeof (DWORD);
|
||
|
||
status = RegQueryValueEx(
|
||
Key,
|
||
"First Counter",
|
||
0L,
|
||
&Type,
|
||
(LPBYTE)&dwFirstCounter,
|
||
&Size);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
|
||
RegCloseKey(Key);
|
||
return status;
|
||
|
||
}
|
||
|
||
Size = sizeof (DWORD);
|
||
|
||
status = RegQueryValueEx(
|
||
Key,
|
||
"First Help",
|
||
0L,
|
||
&Type,
|
||
(LPBYTE)&dwFirstHelp,
|
||
&Size);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
|
||
RegCloseKey(Key);
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the TitleIndex and HelpIndex in the HistGramDataDefinition to the
|
||
// correct value
|
||
//
|
||
|
||
HistGramDataDefinition.HistGramObjectType.ObjectNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.HistGramObjectType.ObjectHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.Median.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.Median.CounterHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.MedianRead.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.MedianRead.CounterHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.MedianWrite.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.MedianWrite.CounterHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.Request.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.Request.CounterHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.RequestRead.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.RequestRead.CounterHelpTitleIndex += dwFirstHelp;
|
||
HistGramDataDefinition.RequestWrite.CounterNameTitleIndex += dwFirstCounter;
|
||
HistGramDataDefinition.RequestWrite.CounterHelpTitleIndex += dwFirstHelp;
|
||
|
||
while (TRUE) {
|
||
|
||
if (*lpLocalDeviceNames == '\0') {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
hFileHandle = CreateFile(lpLocalDeviceNames,
|
||
GENERIC_READ,
|
||
0,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
0,
|
||
NULL);
|
||
|
||
if (hFileHandle != INVALID_HANDLE_VALUE) {
|
||
|
||
if (NumberOfHistDevices == 0 && pHistDeviceData == NULL) {
|
||
|
||
//
|
||
// Allocate Memory to hold the device data
|
||
//
|
||
|
||
pHistDeviceData = RtlAllocateHeap(RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
sizeof(HIST_DEVICE_DATA) );
|
||
|
||
if (pHistDeviceData == NULL) {
|
||
|
||
CloseHandle(hFileHandle);
|
||
|
||
REPORT_ERROR(HIST_OPEN_OUT_OF_MEMORY, LOG_USER);
|
||
|
||
return ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
pTemp = RtlReAllocateHeap(RtlProcessHeap(), 0,
|
||
pHistDeviceData,
|
||
sizeof(HIST_DEVICE_DATA) * (NumberOfHistDevices + 1) );
|
||
|
||
if (pTemp == NULL) {
|
||
|
||
CloseHandle(hFileHandle);
|
||
|
||
REPORT_ERROR(HIST_OPEN_OUT_OF_MEMORY, LOG_USER);
|
||
|
||
return ERROR_OUTOFMEMORY;
|
||
|
||
} else {
|
||
|
||
pHistDeviceData = pTemp;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
RtlInitString(&nameString,lpLocalDeviceNames);
|
||
RtlAnsiStringToUnicodeString(&fileString,&nameString,TRUE);
|
||
|
||
pHistDeviceData[NumberOfHistDevices].hFileHandle = hFileHandle;
|
||
pHistDeviceData[NumberOfHistDevices].DeviceName.MaximumLength = fileString.MaximumLength;
|
||
pHistDeviceData[NumberOfHistDevices].DeviceName.Length = fileString.Length;
|
||
pHistDeviceData[NumberOfHistDevices].DeviceName.Buffer = fileString.Buffer;
|
||
|
||
NumberOfHistDevices++;
|
||
|
||
if (fileString.MaximumLength > MaxHistDeviceName) {
|
||
|
||
MaxHistDeviceName = fileString.MaximumLength;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Increment string pointer to point to the next device we should look at
|
||
//
|
||
|
||
lpLocalDeviceNames += (strlen(lpLocalDeviceNames) + 1);
|
||
|
||
} // while
|
||
|
||
REPORT_SUCCESS(HIST_OPEN_PERFORMANCE_DATA, LOG_DEBUG);
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
DWORD APIENTRY
|
||
CollectHistGramPerformanceData(
|
||
IN LPWSTR lpValueName,
|
||
IN OUT LPVOID *lppData,
|
||
IN OUT LPDWORD lpcbTotalBytes,
|
||
IN OUT LPDWORD lpNumObjectTypes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will return the data for the histgram counters.
|
||
|
||
Arguments:
|
||
|
||
LPWSTR lpValueName
|
||
IN: Pointer to a wide character string passed by registry
|
||
|
||
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 at the point referenced *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.
|
||
|
||
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 written to the
|
||
DWORD pointed to by this argument.
|
||
|
||
LPDWORD lpNumObjectTypes
|
||
IN: the addres of the DWORD to receive the number of objects added
|
||
by this routine.
|
||
OUT: the number of objects added by this routine is written to the
|
||
DWORD pointed ot by this argument.
|
||
|
||
Return Values:
|
||
|
||
ERROR_MORE_DATA if buffere passes is too small to hold data. any error
|
||
conditions encountered are reported to the event log if event logging
|
||
is enabled.
|
||
|
||
ERROR_SUCCESS if success or any other error. Errors are however reported
|
||
to the event log.
|
||
|
||
--*/
|
||
{
|
||
|
||
HISTGRAM_DATA_DEFINITION *pHistDataDefinition;
|
||
ULONG spaceNeeded;
|
||
PPERF_OBJECT_TYPE pHistObject;
|
||
PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
|
||
PERF_COUNTER_BLOCK *pPerfCounterBlock;
|
||
NTSTATUS ntStatus;
|
||
DWORD dwDataReturn[2];
|
||
DWORD numBytes;
|
||
DISK_HISTOGRAM diskHist;
|
||
ULONG i;
|
||
ULONG j;
|
||
ULONG count;
|
||
ULONG max;
|
||
LARGE_INTEGER loc;
|
||
LARGE_INTEGER locRead;
|
||
LARGE_INTEGER locWrite;
|
||
LARGE_INTEGER req;
|
||
LARGE_INTEGER reqRead;
|
||
LARGE_INTEGER reqWrite;
|
||
LARGE_INTEGER UNALIGNED *pliCounter;
|
||
|
||
|
||
if (lpValueName == NULL) {
|
||
|
||
REPORT_INFORMATION(HIST_COLLECT_ENTERED, LOG_VERBOSE);
|
||
|
||
} else {
|
||
|
||
REPORT_INFORMATION_DATA(HIST_COLLECT_ENTERED, LOG_VERBOSE,
|
||
lpValueName, (lstrlenW(lpValueName) * sizeof(WCHAR) ) );
|
||
|
||
}
|
||
|
||
//
|
||
// Define Pointer for Object Data structure (hist object def.)
|
||
//
|
||
|
||
pHistDataDefinition = (HISTGRAM_DATA_DEFINITION *) *lppData;
|
||
pHistObject = (PPERF_OBJECT_TYPE) pHistDataDefinition;
|
||
|
||
//
|
||
// Check to see that we have been opened successfully
|
||
//
|
||
|
||
if (!pHistDeviceData || NumberOfHistDevices == 0) {
|
||
|
||
REPORT_ERROR(HIST_COLLECT_INIT_ERROR, LOG_USER);
|
||
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
if (!pHistDataBuffer) {
|
||
|
||
HistDataBufferSize = 64L;
|
||
pHistDataBuffer = RtlAllocateHeap(RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
HistDataBufferSize);
|
||
|
||
if (!pHistDataBuffer) {
|
||
|
||
*lpcbTotalBytes = (DWORD) 0;
|
||
*lpNumObjectTypes = (DWORD) 0;
|
||
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
REPORT_SUCCESS(HIST_COLLECT_INIT_SUCCESS, LOG_VERBOSE);
|
||
|
||
//
|
||
// Is hit space calculation correct? I'm not sure I need the '19' in there...
|
||
//
|
||
|
||
spaceNeeded = sizeof(HISTGRAM_DATA_DEFINITION) +
|
||
(NumberOfHistDevices *
|
||
(sizeof(PERF_INSTANCE_DEFINITION) +
|
||
DWORD_MULTIPLE(( 19 * sizeof(WCHAR)) +
|
||
sizeof(UNICODE_NULL) +
|
||
MaxHistDeviceName) +
|
||
SIZE_OF_HISTGRAM_DATA) );
|
||
|
||
if ( (ULONG) *lpcbTotalBytes < spaceNeeded) {
|
||
|
||
dwDataReturn[0] = *lpcbTotalBytes;
|
||
dwDataReturn[1] = spaceNeeded;
|
||
|
||
REPORT_WARNING_DATA( HIST_DATA_BUFFER_SIZE, LOG_DEBUG,
|
||
&dwDataReturn, sizeof(dwDataReturn) );
|
||
|
||
return ERROR_MORE_DATA;
|
||
}
|
||
|
||
RtlMoveMemory(pHistDataDefinition, &HistGramDataDefinition,
|
||
sizeof(HISTGRAM_DATA_DEFINITION) );
|
||
|
||
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *) (pHistDataDefinition + 1);
|
||
|
||
for (i = 0 ; i < (ULONG) NumberOfHistDevices; i++) {
|
||
|
||
if (pHistDeviceData[i].hFileHandle == 0 ||
|
||
pHistDeviceData[i].hFileHandle == INVALID_HANDLE_VALUE) {
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
if (!DeviceIoControl(pHistDeviceData[i].hFileHandle,
|
||
IOCTL_DISK_HISTOGRAM_STRUCTURE,
|
||
NULL,
|
||
0,
|
||
&diskHist,
|
||
sizeof(diskHist),
|
||
&numBytes,
|
||
NULL)) {
|
||
|
||
CloseHandle(pHistDeviceData[i].hFileHandle);
|
||
continue;
|
||
|
||
}
|
||
|
||
loc.QuadPart = diskHist.Average.QuadPart;
|
||
locRead.QuadPart = diskHist.AverageRead.QuadPart;
|
||
locWrite.QuadPart = diskHist.AverageWrite.QuadPart;
|
||
|
||
if (!DeviceIoControl(pHistDeviceData[i].hFileHandle,
|
||
IOCTL_DISK_REQUEST_STRUCTURE,
|
||
NULL,
|
||
0,
|
||
&diskHist,
|
||
sizeof(diskHist),
|
||
&numBytes,
|
||
NULL)) {
|
||
|
||
CloseHandle(pHistDeviceData[i].hFileHandle);
|
||
continue;
|
||
|
||
}
|
||
|
||
req.QuadPart = diskHist.Average.QuadPart;
|
||
reqRead.QuadPart = diskHist.AverageRead.QuadPart;
|
||
reqWrite.QuadPart = diskHist.AverageWrite.QuadPart;
|
||
|
||
//
|
||
// Load Instance data into buffer
|
||
//
|
||
|
||
MonBuildInstanceDefinition(pPerfInstanceDefinition,
|
||
(PVOID *) &pPerfCounterBlock,
|
||
0,
|
||
0,
|
||
(DWORD) PERF_NO_UNIQUE_ID, // No Unique ID, use name instead
|
||
&pHistDeviceData[i].DeviceName);
|
||
|
||
//
|
||
// adjust object size values to include new instance
|
||
//
|
||
|
||
pHistObject->NumInstances++;
|
||
|
||
//
|
||
// Initialize this instance's counter block
|
||
//
|
||
|
||
pPerfCounterBlock->ByteLength = SIZE_OF_HISTGRAM_DATA;
|
||
|
||
pliCounter = (LARGE_INTEGER UNALIGNED * ) (pPerfCounterBlock + 1);
|
||
|
||
*(pliCounter++) = loc;
|
||
*(pliCounter++) = locRead;
|
||
*(pliCounter++) = locWrite;
|
||
*(pliCounter++) = req;
|
||
*(pliCounter++) = reqRead;
|
||
*(pliCounter++) = reqWrite;
|
||
|
||
//
|
||
// Update Pointer for next instance
|
||
//
|
||
|
||
pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
|
||
(((PBYTE) pPerfCounterBlock) + SIZE_OF_HISTGRAM_DATA);
|
||
|
||
|
||
} // for i < NumberOfHistDevices
|
||
|
||
*lppData = (LPVOID)pliCounter;
|
||
|
||
*lpNumObjectTypes = HISTGRAM_NUM_PERF_OBJECT_TYPES;
|
||
*lpcbTotalBytes = (DWORD) ((LPBYTE)pliCounter - (LPBYTE)pHistObject);
|
||
|
||
pHistDataDefinition->HistGramObjectType.TotalByteLength = *lpcbTotalBytes;
|
||
|
||
REPORT_INFORMATION( HIST_COLLECT_DATA_SUCCESS, LOG_DEBUG);
|
||
|
||
return ERROR_SUCCESS;
|
||
} // end CollectHistGramPerformanceData
|
||
|
||
|
||
DWORD APIENTRY
|
||
CloseHistGramPerformanceData(
|
||
)
|
||
/*++
|
||
|
||
Routine description:
|
||
|
||
This routine closes the open handles
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Returne Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
{
|
||
|
||
ULONG i;
|
||
|
||
REPORT_INFORMATION(HIST_CLOSE_ENTERED, LOG_VERBOSE);
|
||
|
||
if (pHistDeviceData) {
|
||
|
||
for (i = 0; i < NumberOfHistDevices; i++) {
|
||
|
||
if (pHistDeviceData[i].DeviceName.Buffer) {
|
||
|
||
RtlFreeUnicodeString(&(pHistDeviceData[i].DeviceName) );
|
||
|
||
}
|
||
|
||
if (pHistDeviceData[i].hFileHandle) {
|
||
|
||
NtClose(pHistDeviceData[i].hFileHandle);
|
||
|
||
}
|
||
}
|
||
|
||
RtlFreeHeap(RtlProcessHeap(),
|
||
0,
|
||
pHistDeviceData);
|
||
|
||
pHistDeviceData = NULL;
|
||
NumberOfHistDevices = 0;
|
||
MaxHistDeviceName = 0;
|
||
|
||
}
|
||
|
||
if (pHistDataBuffer) {
|
||
|
||
RtlFreeHeap(RtlProcessHeap(),
|
||
0,
|
||
pHistDataBuffer);
|
||
|
||
pHistDataBuffer = NULL;
|
||
HistDataBufferSize = 0;
|
||
|
||
}
|
||
|
||
MonCloseEventLog();
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|