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.
 
 
 
 
 
 

576 lines
17 KiB

//=================================================================
//
// PerfData.CPP -- Performance Data Helper class
//
// Copyright (c) 1996-2001 Microsoft Corporation, All Rights Reserved
//
// Revisions: 11/23/97 a-sanjes Created
//
//=================================================================
#include "precomp.h"
#include <assertbreak.h>
#include "perfdata.h"
#include <cregcls.h>
#include <createmutexasprocess.h>
#ifdef NTONLY
// Static Initialization
bool CPerformanceData::m_fCloseKey = false;
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::CPerformanceData
//
// Default constructor
//
// Inputs:
// None
//
// Outputs:
// None
//
// Returns:
// None
//
// Comments:
//
//////////////////////////////////////////////////////////
CPerformanceData::CPerformanceData( void )
{
m_pBuff = NULL;
}
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::~CPerformanceData
//
// Destructor
//
// Inputs:
// None
//
// Outputs:
// None
//
// Returns:
// None
//
// Comments:
//
//////////////////////////////////////////////////////////
CPerformanceData::~CPerformanceData( void )
{
if (m_pBuff != NULL)
{
delete [] m_pBuff;
}
}
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::RegQueryValueExExEx
//
// Inputs: HKEY hKey handle of key to query
// LPTSTR lpValueName, address of name of value to query
// LPDWORD lpReserved reserved
// LPDWORD lpType, address of buffer for value type
// LPBYTE lpData address of data buffer
// LPDWORD lpcbData address of data buffer size
//
//
// Returns: everything documented by RegQueryValueEx AND ERROR_SEM_TIMEOUT or ERROR_OPEN_FAILED
//
//////////////////////////////////////////////////////////
LONG CPerformanceData::RegQueryValueExExEx( HKEY hKey, LPTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
LONG ret = -1;
ret = RegQueryValueEx( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
return ret;
}
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::Open
//
// Opens and retrieves data from the performance data
// registry key.
//
// Inputs:
// LPCTSTR pszValue - Value to retrieve
//
// Outputs:
// LPDWORD pdwType - Type returned
// LPBYTE lpData - Buffer
// LPDWORD lpcbData - Amount of data returned
//
// Returns:
// ERROR_SUCCESS if successful
//
// Comments:
//
//////////////////////////////////////////////////////////
DWORD CPerformanceData::Open( LPCTSTR pszValue, LPDWORD pdwType, LPBYTE *lppData, LPDWORD lpcbData )
{
DWORD dwReturn = ERROR_OUTOFMEMORY;
BOOL fStackTrashed = FALSE;
LogMessage(_T("CPerformanceData::Open"));
LPCTSTR pszOldValue = pszValue;
LPDWORD pdwOldType = pdwType;
LPBYTE* lppOldData = lppData;
LPDWORD lpcbOldData = lpcbData;
ASSERT_BREAK(*lppData == NULL);
DWORD dwSize = 16384;
*lpcbData = dwSize;
*lppData = new byte [*lpcbData];
if (*lppData == NULL)
{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
if ( pszOldValue != pszValue
|| pdwOldType != pdwType
|| lppOldData != lppData
|| lpcbOldData != lpcbData )
{
LogErrorMessage(_T("CPerformanceData::stack trashed after malloc"));
fStackTrashed = TRUE;
ASSERT_BREAK(0);
}
else
{
try
{
while ((*lppData != NULL) &&
// remember precedence & associativity?
((dwReturn = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
(LPTSTR)pszValue,
NULL,
pdwType,
(LPBYTE) *lppData,
lpcbData )) == ERROR_MORE_DATA)
)
{
if ( pszOldValue != pszValue
|| pdwOldType != pdwType
|| lppOldData != lppData
|| lpcbOldData != lpcbData )
{
LogErrorMessage(_T("CPerformanceData::stack trashed after RegQueryValueEx"));
fStackTrashed = TRUE;
ASSERT_BREAK(0);
break;
}
// Get a buffer that is big enough.
LogMessage(_T("CPerformanceData::realloc"));
dwSize += 16384;
*lpcbData = dwSize ;
if ( pszOldValue != pszValue
|| pdwOldType != pdwType
|| lppOldData != lppData
|| lpcbOldData != lpcbData )
{
LogErrorMessage(_T("CPerformanceData::stack trashed after size reset"));
fStackTrashed = TRUE;
ASSERT_BREAK(0);
break;
}
delete [] *lppData;
*lppData = new BYTE [*lpcbData];
if (*lppData == NULL)
{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
if ( pszOldValue != pszValue
|| pdwOldType != pdwType
|| lppOldData != lppData
|| lpcbOldData != lpcbData )
{
LogErrorMessage(_T("CPerformanceData::stack trashed after realloc"));
fStackTrashed = TRUE;
ASSERT_BREAK(0);
break;
}
} // While
}
catch ( ... )
{
if (*lppData != NULL)
{
delete [] *lppData;
}
throw ;
}
}
if ( fStackTrashed )
{
dwReturn = ERROR_INVALID_FUNCTION;
}
else
{
// if we got here in an error condition, try to recoup
if ((dwReturn != ERROR_SUCCESS)
&&
(*lppData != NULL))
{
LogErrorMessage(_T("CPerformanceData::failed to alloc enough memory"));
delete [] *lppData;
*lppData = NULL;
}
if (!m_fCloseKey)
{
m_fCloseKey = ( ERROR_SUCCESS == dwReturn );
if (m_fCloseKey)
LogMessage(_T("Opened perf counters"));
}
if ((dwReturn != ERROR_SUCCESS) && IsErrorLoggingEnabled())
{
CHString sTemp;
sTemp.Format(_T("Performance RegQueryValueEx returned %d\n"), dwReturn);
LogErrorMessage(sTemp);
}
if (*lppData == NULL)
{
dwReturn = ERROR_OUTOFMEMORY;
}
}
return dwReturn;
}
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::Close
//
// Closes the performance data registry key if the
// static value is TRUE.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
// Per the KB, calling RegCloseKey on HKEY_PERFORMANCE_DATA
// causes a memory leak, so you do NOT want to do lots of
// these.
//
//////////////////////////////////////////////////////////
#if 0 // From raid 48395
void CPerformanceData::Close( void )
{
if ( m_fCloseKey )
{
if ( m_fCloseKey )
{
RegCloseKey( HKEY_PERFORMANCE_DATA );
m_fCloseKey = FALSE;
LogMessage(_T("Closed Perf Counters"));
}
}
}
#endif
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::GetPerfIndex
//
// Given a perf object name, this function returns
// the perf object number.
//
// Inputs:
// Object name
//
// Outputs:
// None
//
// Returns:
// Associated Number or 0 on error.
//
// Comments:
//
//
//////////////////////////////////////////////////////////
DWORD CPerformanceData::GetPerfIndex(LPCTSTR pszName)
{
DWORD dwRetVal = 0;
if (m_pBuff == NULL)
{
LONG lRet = ERROR_SUCCESS;
if (m_pBuff == NULL)
{
CRegistry RegInfo;
// Hardcoding 009 should be ok since according to the docs:
// "The langid is the ASCII representation of the 3-digit hexadecimal language identifier. "
// "For example, the U.S. English langid is 009. In a non-English version of Windows NT, "
// "counters are stored in both the native language of the system and in English. "
if ((lRet = RegInfo.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"), KEY_QUERY_VALUE)) == ERROR_SUCCESS)
{
// Get the size of the key
DWORD dwSize;
lRet = RegInfo.GetCurrentBinaryKeyValue(_T("Counter"), NULL, &dwSize);
if (lRet == ERROR_SUCCESS)
{
// Allocate a buffer to hold it
m_pBuff = new BYTE[dwSize];
if (m_pBuff != NULL)
{
// Get the actual data
if ((lRet = RegInfo.GetCurrentBinaryKeyValue(_T("Counter"), m_pBuff, &dwSize)) != ERROR_SUCCESS)
{
delete [] m_pBuff;
m_pBuff = NULL;
}
}
else
{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
}
}
}
if (lRet != ERROR_SUCCESS)
{
LogErrorMessage2(L"Failed to read Perflib key: %x", lRet);
}
}
// If we got the registry key
if (m_pBuff != NULL)
{
const TCHAR *pCounter;
const TCHAR *ptemp;
int stringlength;
pCounter = (TCHAR *)m_pBuff;
stringlength = _tcslen((LPCTSTR)pCounter);
// Exit the loop when we hit the end
while(stringlength)
{
// Strings are stored in the form <counternumber>\0<countername>\0.
// What we want to return is the counter number. ptemp will point to the name
ptemp = pCounter + stringlength+1;
stringlength = _tcslen((LPCTSTR)ptemp);
if (stringlength > 0)
{
// Did we find it
if (_tcscmp((TCHAR *)ptemp, pszName) != 0)
{
// Nope, position to the next pair
pCounter = ptemp + stringlength+1;
stringlength = _tcslen((LPCTSTR)pCounter);
}
else
{
// Yup, calculate the value to return
dwRetVal = _ttoi(pCounter);
break;
}
}
}
}
ASSERT_BREAK(dwRetVal > 0);
return dwRetVal;
}
//////////////////////////////////////////////////////////
//
// Function: CPerformanceData::GetValue
//
// Given a perf object index, counter index, and optional
// instance name, returns the value and the time.
//
// Inputs:
// Value, Time
//
// Outputs:
// Value, Time
//
// Returns:
// True if it finds the value
//
// Comments:
//
//
//////////////////////////////////////////////////////////
bool CPerformanceData::GetValue(DWORD dwObjIndex, DWORD dwCtrIndex, const WCHAR *szInstanceName, PBYTE pbData, unsigned __int64 *pTime)
{
PPERF_DATA_BLOCK PerfData = NULL;
DWORD dwBufferSize = 0;
LONG lReturn = 0;
BOOL fReturn = FALSE;
TCHAR szBuff[MAXITOA];
bool bFound = false;
PPERF_INSTANCE_DEFINITION pInstBlock;
DWORD dwInstances;
unsigned __int64 *pbCounterData;
// The subsequent close happens in our destructor (read comment there).
lReturn = Open( _itot(dwObjIndex, szBuff, 10),
NULL,
(LPBYTE *) (&PerfData),
&dwBufferSize );
if ( NULL != PerfData
&& ERROR_SUCCESS == lReturn )
{
try
{
// Surf through the objects returned until we find the one we are looking for.
PPERF_OBJECT_TYPE pPerfObject = (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength);
for ( DWORD dwObjectCtr = 0;
dwObjectCtr < PerfData->NumObjectTypes
&& pPerfObject->ObjectNameTitleIndex != dwObjIndex;
dwObjectCtr++ );
// Did we find the Object?
if ( dwObjectCtr < PerfData->NumObjectTypes )
{
// Now surf through the Counter Definition Data until we locate the
// counter we are hunting for.
PPERF_COUNTER_DEFINITION pPerfCtrDef = (PPERF_COUNTER_DEFINITION)((PBYTE) pPerfObject + pPerfObject->HeaderLength);
for ( DWORD dwCtr = 0;
dwCtr < pPerfObject->NumCounters
&& pPerfCtrDef->CounterNameTitleIndex != dwCtrIndex;
dwCtr++,
// Go to the next counter
pPerfCtrDef = (PPERF_COUNTER_DEFINITION)((PBYTE) pPerfCtrDef + pPerfCtrDef->ByteLength )
);
// Did we find the counter?
if ( dwCtr < pPerfObject->NumCounters )
{
// Finally go to the data offset we retrieved from the counter definitions
// and access the data (finally).
DWORD dwCounterOffset = pPerfCtrDef->CounterOffset;
PPERF_COUNTER_BLOCK pPerfCtrBlock = NULL;
// If we are looking for an instance
if ((szInstanceName == NULL) && (pPerfObject->NumInstances == PERF_NO_INSTANCES))
{
pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE) pPerfObject + pPerfObject->DefinitionLength);
bFound = true;
}
else if (pPerfObject->NumInstances != PERF_NO_INSTANCES)
{
// Walk the instances looking for the requested one
pInstBlock = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pPerfObject + pPerfObject->DefinitionLength);
dwInstances = 1;
while ((dwInstances <= pPerfObject->NumInstances) &&
(wcscmp((WCHAR *)((pInstBlock->NameOffset) + (PBYTE)pInstBlock), szInstanceName) != 0))
{
pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pInstBlock + pInstBlock->ByteLength);
pInstBlock = (PPERF_INSTANCE_DEFINITION)((PBYTE) pInstBlock + (pInstBlock->ByteLength + pPerfCtrBlock->ByteLength));
dwInstances ++;
}
// Did we find it?
if (dwInstances <= pPerfObject->NumInstances)
{
bFound = true;
pPerfCtrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pInstBlock + pInstBlock->ByteLength);
}
}
// Grab the appropriate time field based on the counter definition
if (bFound) {
if (pPerfCtrDef->CounterType & PERF_TIMER_100NS)
{
*pTime = PerfData->PerfTime100nSec.QuadPart;
}
else
{
// Unverified
*pTime = PerfData->PerfTime.QuadPart;
}
// Get a pointer to the data, then copy in the correct number of bytes (based on counter def)
pbCounterData = (unsigned __int64 *)(((PBYTE) pPerfCtrBlock ) + dwCounterOffset);
if (pPerfCtrDef->CounterType & PERF_SIZE_DWORD)
{
memcpy(pbData, pbCounterData, 4);
}
else if (pPerfCtrDef->CounterType & PERF_SIZE_LARGE)
{
memcpy(pbData, pbCounterData, 8);
}
}
} // If Counter Definition found
} // If Object found
} // If memory allocated
catch ( ... )
{
delete [] PerfData ;
throw ;
}
}
// Free up any transient memory
if ( NULL != PerfData )
{
delete [] PerfData ;
}
ASSERT_BREAK(bFound);
return bFound;
}
#endif