409 lines
8.5 KiB
C++
409 lines
8.5 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1996-2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
// Cooker.cpp
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include <winperf.h>
|
||
|
#include "pdh.h"
|
||
|
#include "pdhmsg.h"
|
||
|
#include <pdhicalc.h>
|
||
|
|
||
|
#include "RawCooker.h"
|
||
|
|
||
|
CCalcTable::CCalcTable()
|
||
|
{
|
||
|
m_lSize = 5;
|
||
|
|
||
|
// Ordered list based on Perf IDs
|
||
|
// ==============================
|
||
|
|
||
|
m_aTable[0].Init( 0x00000001, CRawCooker::_Average );
|
||
|
m_aTable[1].Init( 0x00000002, CRawCooker::_Min );
|
||
|
m_aTable[2].Init( 0x00000003, CRawCooker::_Max );
|
||
|
m_aTable[3].Init( 0x00000004, CRawCooker::_Range );
|
||
|
m_aTable[4].Init( 0x00000005, CRawCooker::_Variance );
|
||
|
|
||
|
}
|
||
|
|
||
|
CCalcTable::~CCalcTable()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CCalcRecord* CCalcTable::GetCalcRecord( DWORD dwCookingType )
|
||
|
{
|
||
|
CCalcRecord* pCalcRecord = NULL;
|
||
|
|
||
|
long left = 0,
|
||
|
right = m_lSize - 1,
|
||
|
mid = right / 2;
|
||
|
|
||
|
DWORD dwMidVal = 0;
|
||
|
|
||
|
bool bFound = FALSE;
|
||
|
|
||
|
while ( !bFound && ( left <= right ) )
|
||
|
{
|
||
|
dwMidVal = m_aTable[mid].GetID();
|
||
|
|
||
|
if ( dwCookingType < dwMidVal )
|
||
|
{
|
||
|
right = mid - 1;
|
||
|
mid = ( left + right ) / 2;
|
||
|
}
|
||
|
else if ( dwCookingType > dwMidVal )
|
||
|
{
|
||
|
left = mid + 1;
|
||
|
mid = ( left + right ) / 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bFound = TRUE;
|
||
|
pCalcRecord = &m_aTable[mid];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pCalcRecord;
|
||
|
}
|
||
|
|
||
|
CRawCooker::CRawCooker() : m_lRef( 1 ), m_pCalcRecord( NULL )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CRawCooker::~CRawCooker()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// COM methods
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
|
||
|
STDMETHODIMP CRawCooker::QueryInterface(REFIID riid, void** ppv)
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Standard QueryInterface
|
||
|
//
|
||
|
// Parameters:
|
||
|
// riid - the ID of the requested interface
|
||
|
// ppv - a pointer to the interface pointer
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//ok
|
||
|
{
|
||
|
if(riid == IID_IUnknown)
|
||
|
*ppv = (LPVOID)(IUnknown*)(IWMISimpleCooker*)this;
|
||
|
else if(riid == IID_IWMISimpleCooker)
|
||
|
*ppv = (LPVOID)(IWMISimpleCooker*)this;
|
||
|
else return E_NOINTERFACE;
|
||
|
|
||
|
((IUnknown*)*ppv)->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CRawCooker::AddRef()
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Standard COM AddRef
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//ok
|
||
|
{
|
||
|
return InterlockedIncrement(&m_lRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CRawCooker::Release()
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Standard COM Release
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//ok
|
||
|
{
|
||
|
long lRef = InterlockedDecrement(&m_lRef);
|
||
|
if(lRef == 0)
|
||
|
delete this;
|
||
|
|
||
|
return lRef;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CRawCooker::CookRawValues(
|
||
|
/*[in] */ DWORD dwCookingType,
|
||
|
/*[in] */ DWORD dwNumSamples,
|
||
|
/*[in] */ __int64* anTimeStamp,
|
||
|
/*[in] */ __int64* anRawValue,
|
||
|
/*[in] */ __int64* anBase,
|
||
|
/*[in] */ __int64 nTimeFrequency,
|
||
|
/*[in] */ long lScale,
|
||
|
/*[out]*/ __int64* pnResult )
|
||
|
{
|
||
|
HRESULT hResult = S_OK;
|
||
|
|
||
|
PDH_STATUS lRet = 0;
|
||
|
LPCOUNTERCALC pCalcFunction = NULL;
|
||
|
LPCOUNTERSTAT pStatFunction = NULL;
|
||
|
PDH_FMT_COUNTERVALUE fmtValue;
|
||
|
memset( &fmtValue, 0, sizeof( PDH_FMT_COUNTERVALUE ) );
|
||
|
|
||
|
if ( AssignCalcFunction( dwCookingType, &pCalcFunction, &pStatFunction ) && ( 2 == dwNumSamples ) )
|
||
|
{
|
||
|
PDH_RAW_COUNTER RawValue1;
|
||
|
PDH_RAW_COUNTER RawValue2;
|
||
|
|
||
|
RawValue1.CStatus = 0;
|
||
|
RawValue1.MultiCount = 0;
|
||
|
|
||
|
RawValue2.CStatus = 0;
|
||
|
RawValue2.MultiCount = 0;
|
||
|
|
||
|
if ((dwCookingType == PERF_RAW_FRACTION) ||
|
||
|
(dwCookingType == PERF_SAMPLE_FRACTION) ||
|
||
|
(dwCookingType == PERF_AVERAGE_TIMER) ||
|
||
|
(dwCookingType == PERF_AVERAGE_BULK)) {
|
||
|
|
||
|
RawValue1.TimeStamp = *(FILETIME*)&anTimeStamp[0];
|
||
|
RawValue1.FirstValue = anRawValue[0];
|
||
|
RawValue1.SecondValue = anBase[0];
|
||
|
|
||
|
RawValue2.TimeStamp = *(FILETIME*)&anTimeStamp[1];
|
||
|
RawValue2.FirstValue = anRawValue[1];
|
||
|
RawValue2.SecondValue = anBase[1];
|
||
|
|
||
|
} else {
|
||
|
|
||
|
RawValue1.TimeStamp = *(FILETIME *)&anBase[0];
|
||
|
RawValue1.FirstValue = anRawValue[0];
|
||
|
RawValue1.SecondValue = anTimeStamp[0];
|
||
|
|
||
|
RawValue2.TimeStamp = *(FILETIME *)&anBase[1];
|
||
|
RawValue2.FirstValue = anRawValue[1];
|
||
|
RawValue2.SecondValue = anTimeStamp[1];
|
||
|
|
||
|
}
|
||
|
|
||
|
DWORD dwFormat = PDH_FMT_LARGE;
|
||
|
// do not scale if lScale is 0
|
||
|
if (!lScale)
|
||
|
{
|
||
|
dwFormat |= PDH_FMT_NOSCALE;
|
||
|
}
|
||
|
|
||
|
lRet = PdhiComputeFormattedValue(
|
||
|
pCalcFunction,
|
||
|
dwCookingType,
|
||
|
lScale,
|
||
|
dwFormat, //PDH_FMT_NOSCALE | PDH_FMT_LARGE,
|
||
|
&RawValue1,
|
||
|
&RawValue2,
|
||
|
&nTimeFrequency,
|
||
|
0,
|
||
|
&fmtValue );
|
||
|
|
||
|
if ( 0 == lRet )
|
||
|
*pnResult = fmtValue.largeValue;
|
||
|
else if (lRet == PDH_CALC_NEGATIVE_VALUE ||
|
||
|
lRet == PDH_CALC_NEGATIVE_DENOMINATOR) {
|
||
|
*pnResult = 0;
|
||
|
} else {
|
||
|
hResult = lRet; //WBEM_E_FAILED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// The last calculation record is cached in an attempt to avoid a new
|
||
|
// search. A cooking type of zero means "use the last clac record"
|
||
|
// ==================================================================
|
||
|
|
||
|
if ( NULL == m_pCalcRecord || ( m_pCalcRecord->GetID() != dwCookingType ) &&
|
||
|
( m_pCalcRecord->GetID() != 0 ) )
|
||
|
{
|
||
|
m_pCalcRecord = m_CalcTable.GetCalcRecord( dwCookingType );
|
||
|
|
||
|
if ( NULL == m_pCalcRecord )
|
||
|
{
|
||
|
hResult = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED( hResult ) )
|
||
|
{
|
||
|
// Calculate the result
|
||
|
// ====================
|
||
|
|
||
|
PERFCALC* pCalc = m_pCalcRecord->GetCalc();
|
||
|
|
||
|
if ( NULL != pCalc )
|
||
|
{
|
||
|
hResult = pCalc( dwNumSamples,
|
||
|
anTimeStamp,
|
||
|
anRawValue,
|
||
|
anBase,
|
||
|
nTimeFrequency,
|
||
|
pnResult );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hResult;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Perf Calculations
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////
|
||
|
|
||
|
WMISTATUS APIENTRY CRawCooker::_Average( DWORD dwNumSamples,
|
||
|
__int64* anTimeStamp,
|
||
|
__int64* anRawValue,
|
||
|
__int64* anBase,
|
||
|
__int64 nTimeFrequency,
|
||
|
__int64* pnResult)
|
||
|
{
|
||
|
WMISTATUS dwStatus = WBEM_NO_ERROR;
|
||
|
|
||
|
__int64 nVal = 0;
|
||
|
|
||
|
if ( 0 == dwNumSamples )
|
||
|
{
|
||
|
dwStatus = WBEM_E_FAILED;
|
||
|
}
|
||
|
|
||
|
for ( DWORD dwSample = 0; SUCCEEDED( dwStatus ) && dwSample < dwNumSamples; dwSample++ )
|
||
|
{
|
||
|
if ( (0x7FFFFFFFFFFFFFFF - nVal) < anRawValue[dwSample] )
|
||
|
dwStatus = WBEM_E_INVALID_OPERATION;
|
||
|
else
|
||
|
nVal += anRawValue[dwSample];
|
||
|
}
|
||
|
|
||
|
*pnResult = nVal / dwNumSamples;
|
||
|
|
||
|
return dwStatus;
|
||
|
}
|
||
|
|
||
|
WMISTATUS APIENTRY CRawCooker::_Min( DWORD dwNumSamples,
|
||
|
__int64* anTimeStamp,
|
||
|
__int64* anRawValue,
|
||
|
__int64* anBase,
|
||
|
__int64 nTimeFrequency,
|
||
|
__int64* pnResult)
|
||
|
{
|
||
|
|
||
|
if ( 0 == dwNumSamples ){
|
||
|
return WBEM_E_FAILED;
|
||
|
};
|
||
|
|
||
|
__int64 nVal = anRawValue[0];
|
||
|
|
||
|
|
||
|
for ( DWORD dwSample = 1; dwSample < dwNumSamples; dwSample++ ){
|
||
|
if ( anRawValue[dwSample] < nVal ){
|
||
|
nVal = anRawValue[dwSample];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pnResult = nVal;
|
||
|
|
||
|
return WBEM_NO_ERROR;
|
||
|
|
||
|
}
|
||
|
|
||
|
WMISTATUS APIENTRY CRawCooker::_Max( DWORD dwNumSamples,
|
||
|
__int64* anTimeStamp,
|
||
|
__int64* anRawValue,
|
||
|
__int64* anBase,
|
||
|
__int64 nTimeFrequency,
|
||
|
__int64* pnResult)
|
||
|
{
|
||
|
|
||
|
if ( 0 == dwNumSamples ){
|
||
|
return WBEM_E_FAILED;
|
||
|
};
|
||
|
|
||
|
__int64 nVal = anRawValue[0];
|
||
|
|
||
|
for ( DWORD dwSample = 1; dwSample < dwNumSamples; dwSample++ ){
|
||
|
if ( anRawValue[dwSample] > nVal ){
|
||
|
nVal = anRawValue[dwSample];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pnResult = nVal;
|
||
|
|
||
|
return WBEM_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
WMISTATUS APIENTRY CRawCooker::_Range( DWORD dwNumSamples,
|
||
|
__int64* anTimeStamp,
|
||
|
__int64* anRawValue,
|
||
|
__int64* anBase,
|
||
|
__int64 nTimeFrequency,
|
||
|
__int64* pnResult)
|
||
|
{
|
||
|
|
||
|
if ( 0 == dwNumSamples ){
|
||
|
return WBEM_E_FAILED;
|
||
|
};
|
||
|
|
||
|
__int64 nValMin = anRawValue[0];
|
||
|
__int64 nValMax = anRawValue[0];
|
||
|
|
||
|
|
||
|
for ( DWORD dwSample = 1; dwSample < dwNumSamples; dwSample++ ){
|
||
|
if ( anRawValue[dwSample] > nValMax ){
|
||
|
nValMax = anRawValue[dwSample];
|
||
|
};
|
||
|
if ( anRawValue[dwSample] < nValMin ){
|
||
|
nValMin = anRawValue[dwSample];
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
*pnResult = (nValMax - nValMin);
|
||
|
|
||
|
return WBEM_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
WMISTATUS APIENTRY CRawCooker::_Variance( DWORD dwNumSamples,
|
||
|
__int64* anTimeStamp,
|
||
|
__int64* anRawValue,
|
||
|
__int64* anBase,
|
||
|
__int64 nTimeFrequency,
|
||
|
__int64* pnResult)
|
||
|
{
|
||
|
|
||
|
if ( 0 == dwNumSamples ){
|
||
|
return WBEM_E_FAILED;
|
||
|
};
|
||
|
|
||
|
double SumX_i = 0;
|
||
|
double Average = 0;
|
||
|
|
||
|
for ( DWORD dwSample = 0; dwSample < dwNumSamples; dwSample++ ){
|
||
|
|
||
|
SumX_i += (anRawValue[dwSample]*anRawValue[dwSample]);
|
||
|
Average += anRawValue[dwSample];
|
||
|
}
|
||
|
|
||
|
double Tmp = (double(SumX_i/dwNumSamples) - (double(Average/dwNumSamples)*double(Average/dwNumSamples)));
|
||
|
*pnResult = __int64(Tmp);
|
||
|
|
||
|
return WBEM_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|