/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: Abstract: History: --*/ // Cooker.cpp #include "precomp.h" #include #include "pdh.h" #include "pdhmsg.h" #include #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 (NULL == ppv) return E_POINTER; if(riid == IID_IUnknown) *ppv = (LPVOID)(IUnknown*)(IWMISimpleCooker*)this; else if(riid == IID_IWMISimpleCooker) *ppv = (LPVOID)(IWMISimpleCooker*)this; else { *ppv = NULL; 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 calc 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 || NULL == pnResult) return 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 || NULL == pnResult) 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 || NULL == pnResult) 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 || NULL == pnResult) 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 || NULL == pnResult) { 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; }