/*++ Copyright (C) 1995-1999 Microsoft Corporation Module Name: calcfuns.c Abstract: Counter calculation functions WMICOOKER.DLL depends on this file also. \nt\admin\wmi\wbem\winmgmt\wmicooker --*/ #include #include #include "strsafe.h" #include #include "pdhitype.h" #include "pdhidef.h" #include "pdhicalc.h" #include "pdhmsg.h" BOOL AssignCalcFunction( DWORD dwCounterType, LPCOUNTERCALC * pCalcFunc, LPCOUNTERSTAT * pStatFunc ) { BOOL bReturn = TRUE; // reset the last error value SetLastError(ERROR_SUCCESS); if (pCalcFunc == NULL || pStatFunc == NULL) { SetLastError(PDH_INVALID_ARGUMENT); bReturn = FALSE; } else { __try { * pCalcFunc = PdhiCalcNoData; * pStatFunc = PdhiComputeNoDataStats; } except (EXCEPTION_EXECUTE_HANDLER) { bReturn = FALSE; } } if (bReturn) { switch (dwCounterType) { case PERF_DOUBLE_RAW: * pCalcFunc = PdhiCalcDouble; * pStatFunc = PdhiComputeRawCountStats; break; case PERF_AVERAGE_TIMER: * pCalcFunc = PdhiCalcAverage; * pStatFunc = PdhiComputeFirstLastStats; break; case PERF_ELAPSED_TIME: * pCalcFunc = PdhiCalcElapsedTime; * pStatFunc = PdhiComputeRawCountStats; break; case PERF_RAW_FRACTION: case PERF_LARGE_RAW_FRACTION: * pCalcFunc = PdhiCalcRawFraction; * pStatFunc = PdhiComputeRawCountStats; break; case PERF_COUNTER_COUNTER: case PERF_COUNTER_BULK_COUNT: case PERF_SAMPLE_COUNTER: * pCalcFunc = PdhiCalcCounter; * pStatFunc = PdhiComputeFirstLastStats; break; case PERF_AVERAGE_BULK: case PERF_COUNTER_TIMER: case PERF_100NSEC_TIMER: case PERF_OBJ_TIME_TIMER: case PERF_COUNTER_QUEUELEN_TYPE: case PERF_COUNTER_LARGE_QUEUELEN_TYPE: case PERF_COUNTER_100NS_QUEUELEN_TYPE: case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE: case PERF_SAMPLE_FRACTION: case PERF_COUNTER_MULTI_TIMER: case PERF_100NSEC_MULTI_TIMER: case PERF_PRECISION_SYSTEM_TIMER: case PERF_PRECISION_100NS_TIMER: case PERF_PRECISION_OBJECT_TIMER: * pCalcFunc = PdhiCalcTimer; * pStatFunc = PdhiComputeFirstLastStats; break; case PERF_COUNTER_TIMER_INV: case PERF_100NSEC_TIMER_INV: case PERF_COUNTER_MULTI_TIMER_INV: case PERF_100NSEC_MULTI_TIMER_INV: * pCalcFunc = PdhiCalcInverseTimer; * pStatFunc = PdhiComputeFirstLastStats; break; case PERF_COUNTER_RAWCOUNT: case PERF_COUNTER_LARGE_RAWCOUNT: case PERF_COUNTER_RAWCOUNT_HEX: case PERF_COUNTER_LARGE_RAWCOUNT_HEX: * pCalcFunc = PdhiCalcRawCounter; * pStatFunc = PdhiComputeRawCountStats; break; case PERF_COUNTER_DELTA: case PERF_COUNTER_LARGE_DELTA: * pCalcFunc = PdhiCalcDelta; * pStatFunc = PdhiComputeRawCountStats; break; case PERF_COUNTER_TEXT: case PERF_SAMPLE_BASE: case PERF_AVERAGE_BASE: case PERF_COUNTER_MULTI_BASE: case PERF_RAW_BASE: //case PERF_LARGE_RAW_BASE: case PERF_COUNTER_HISTOGRAM_TYPE: case PERF_COUNTER_NODATA: case PERF_PRECISION_TIMESTAMP: * pCalcFunc = PdhiCalcNoData; * pStatFunc = PdhiComputeNoDataStats; break; default: // an unrecognized counter type. Define the function, but // return false. * pCalcFunc = PdhiCalcNoData; * pStatFunc = PdhiComputeNoDataStats; SetLastError(PDH_FUNCTION_NOT_FOUND); bReturn = FALSE; break; } } return bReturn; } BOOL PdhiCounterNeedLastValue( DWORD dwCounterType ) { BOOL bReturn = TRUE; switch (dwCounterType) { case PERF_DOUBLE_RAW: case PERF_ELAPSED_TIME: case PERF_RAW_FRACTION: case PERF_LARGE_RAW_FRACTION: case PERF_COUNTER_RAWCOUNT: case PERF_COUNTER_LARGE_RAWCOUNT: case PERF_COUNTER_RAWCOUNT_HEX: case PERF_COUNTER_LARGE_RAWCOUNT_HEX: case PERF_COUNTER_TEXT: case PERF_SAMPLE_BASE: case PERF_AVERAGE_BASE: case PERF_COUNTER_MULTI_BASE: case PERF_RAW_BASE: //case PERF_LARGE_RAW_BASE: case PERF_COUNTER_HISTOGRAM_TYPE: case PERF_COUNTER_NODATA: case PERF_PRECISION_TIMESTAMP: bReturn = FALSE; break; case PERF_AVERAGE_TIMER: case PERF_COUNTER_COUNTER: case PERF_COUNTER_BULK_COUNT: case PERF_SAMPLE_COUNTER: case PERF_AVERAGE_BULK: case PERF_COUNTER_TIMER: case PERF_100NSEC_TIMER: case PERF_OBJ_TIME_TIMER: case PERF_COUNTER_QUEUELEN_TYPE: case PERF_COUNTER_LARGE_QUEUELEN_TYPE: case PERF_COUNTER_100NS_QUEUELEN_TYPE: case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE: case PERF_SAMPLE_FRACTION: case PERF_COUNTER_MULTI_TIMER: case PERF_100NSEC_MULTI_TIMER: case PERF_PRECISION_SYSTEM_TIMER: case PERF_PRECISION_100NS_TIMER: case PERF_PRECISION_OBJECT_TIMER: case PERF_COUNTER_TIMER_INV: case PERF_100NSEC_TIMER_INV: case PERF_COUNTER_MULTI_TIMER_INV: case PERF_100NSEC_MULTI_TIMER_INV: case PERF_COUNTER_DELTA: case PERF_COUNTER_LARGE_DELTA: default: bReturn = TRUE; break; } return bReturn; } double APIENTRY PdhiCalcDouble( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { double dReturn; DWORD dwStatus; UNREFERENCED_PARAMETER(pLastValue); UNREFERENCED_PARAMETER(pllTimeBase); dReturn = * (DOUBLE *) & pThisValue->FirstValue; if (dReturn < 0) { dReturn = 0.0f; dwStatus = PDH_CSTATUS_INVALID_DATA; } else { dwStatus = pThisValue->CStatus; } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcAverage( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llNumDiff; LONGLONG llDenDiff = 0; double dNum; double dDen; double dReturn = 0.0f; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; // test access to the required second parameter (lastValue) __try { if (pLastValue != NULL) { if (IsSuccessSeverity(pLastValue->CStatus)) { llDenDiff = pThisValue->SecondValue - pLastValue->SecondValue; } else { dwStatus = pLastValue->CStatus; } } else { dwStatus = PDH_CSTATUS_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if ((llDenDiff > 0) && (* pllTimeBase > 0)) { llNumDiff = pThisValue->FirstValue - pLastValue->FirstValue; if (llNumDiff < 0) { llNumDiff += MAXDWORD; } if (llNumDiff > 0) { dNum = (double) llNumDiff; dNum /= (double) * pllTimeBase; dDen = (double) llDenDiff; dReturn = (dNum / dDen); } else if (llNumDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_VALUE; } } else { if (llDenDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } else if (* pllTimeBase < 0) { dwStatus = PDH_CALC_NEGATIVE_TIMEBASE; } } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcElapsedTime( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llDiff; double dReturn = 0.0f; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(pLastValue); // test access to the required second parameter (lastValue) __try { if (IsSuccessSeverity(pThisValue->CStatus)) { llDiff = pThisValue->SecondValue - pThisValue->FirstValue; } else { dwStatus = pThisValue->CStatus; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if (* pllTimeBase > 0) { llDiff = pThisValue->SecondValue - pThisValue->FirstValue; if (llDiff > 0) { dReturn = (double) llDiff; dReturn /= (double) * pllTimeBase; } else { if (llDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } } } else { if (* pllTimeBase < 0) { dwStatus = PDH_CALC_NEGATIVE_TIMEBASE; } } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcRawFraction( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llDen; double dReturn = 0.0f; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(pLastValue); UNREFERENCED_PARAMETER(pllTimeBase); if ((llDen = pThisValue->SecondValue) > 0) { dReturn = (double)(pThisValue->FirstValue); dReturn /= (double)llDen; } else { if (llDen < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } dReturn = (double)0.0; } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcCounter( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llNumDiff; LONGLONG llDenDiff = 0; double dNum; double dDen; double dReturn = 0.0f; double dMulti; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; // test access to the required second parameter (lastValue) __try { if (pLastValue != NULL) { if (IsSuccessSeverity(pLastValue->CStatus)) { llDenDiff = pThisValue->SecondValue - pLastValue->SecondValue; } else { dwStatus = pLastValue->CStatus; } } else { dwStatus = PDH_CSTATUS_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if ((llDenDiff > 0) && (* pllTimeBase)) { llNumDiff = pThisValue->FirstValue - pLastValue->FirstValue; if (llNumDiff < 0) { llNumDiff += MAXDWORD; } if (llNumDiff > 0) { dNum = (double) llNumDiff; dDen = (double) llDenDiff; dDen /= (double) * pllTimeBase; dReturn = (dNum / dDen); if (pThisValue->MultiCount > 1) { // don't do this if the count is <= 1 dMulti = (double) pThisValue->FirstValue; dReturn /= dMulti; } } else if (llNumDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_VALUE; } } else { if (llDenDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } else if (* pllTimeBase < 0) { dwStatus = PDH_CALC_NEGATIVE_TIMEBASE; } } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcTimer( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llNumDiff; LONGLONG llDenDiff = 0; double dReturn = 0.0f; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(pllTimeBase); // test access to the required second parameter (lastValue) __try { if (pLastValue != NULL) { if (IsSuccessSeverity(pLastValue->CStatus)) { llDenDiff = pThisValue->SecondValue - pLastValue->SecondValue; } else { dwStatus = pLastValue->CStatus; } } else { // the last value wasn't passed in dwStatus = PDH_CSTATUS_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if (llDenDiff > 0) { llNumDiff = pThisValue->FirstValue - pLastValue->FirstValue; if (llNumDiff < 0) { llNumDiff += MAXDWORD; } if (llNumDiff > 0) { dReturn = (double) llNumDiff; dReturn /= (double) llDenDiff; if (pThisValue->MultiCount > 1) { // don't do this if the count is <= 1 dReturn /= (double)pThisValue->MultiCount; } } else if (llNumDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_VALUE; } } else { if (llDenDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcInverseTimer( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llNumDiff; LONGLONG llDenDiff = 0; double dReturn = 0.0f; double dNumDiff, dDenDiff; double dRatio; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(pllTimeBase); // test access to the required second parameter (lastValue) __try { if (pLastValue != NULL) { if (IsSuccessSeverity(pLastValue->CStatus)) { llDenDiff = pThisValue->SecondValue - pLastValue->SecondValue; } else { dwStatus = pLastValue->CStatus; } } else { dwStatus = PDH_CSTATUS_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if (llDenDiff > 0) { llNumDiff = pThisValue->FirstValue - pLastValue->FirstValue; if (llNumDiff < 0) { llNumDiff += MAXDWORD; } if (llNumDiff >= 0) { dNumDiff = (double)llNumDiff; dDenDiff = (double)llDenDiff; dRatio = dNumDiff; dRatio /= dDenDiff; if (pThisValue->MultiCount <= 1) { dReturn = (double) 1.0; } else { dReturn = (double) pThisValue->MultiCount; } // subtract the result from the multi count to get the // "inverse" time dReturn -= dRatio; if (dReturn < (double) 0.0) { // allow a "fudge" factor before reporting errors if (dReturn < (double) (-0.1)) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } dReturn = (double) 0.0; } } else if (llNumDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_VALUE; } } else { if (llDenDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_DENOMINATOR; } dReturn = (double) 0.0; } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } double APIENTRY PdhiCalcRawCounter( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { UNREFERENCED_PARAMETER(pLastValue); UNREFERENCED_PARAMETER(pllTimeBase); if (pdwStatus != NULL) { * pdwStatus = pThisValue->CStatus; } return (double) pThisValue->FirstValue; } double APIENTRY PdhiCalcNoData( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { UNREFERENCED_PARAMETER(pThisValue); UNREFERENCED_PARAMETER(pLastValue); UNREFERENCED_PARAMETER(pllTimeBase); if (pdwStatus != NULL) { * pdwStatus = PDH_NO_DATA; } return (double) 0.0; } double APIENTRY PdhiCalcDelta( PPDH_RAW_COUNTER pThisValue, PPDH_RAW_COUNTER pLastValue, LONGLONG * pllTimeBase, LPDWORD pdwStatus ) { LONGLONG llNumDiff = 0; double dReturn = 0.0f; DWORD dwStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(pllTimeBase); // test access to the required second parameter (lastValue) __try { if (pLastValue != NULL) { if (IsSuccessSeverity(pLastValue->CStatus)) { llNumDiff = pThisValue->FirstValue - pLastValue->FirstValue; } else { dwStatus = pLastValue->CStatus; } } else { dwStatus = PDH_CSTATUS_INVALID_DATA; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = PDH_INVALID_ARGUMENT; } if (dwStatus == PDH_CSTATUS_VALID_DATA) { if (llNumDiff < 0) { llNumDiff += MAXDWORD; } if (llNumDiff < 0) { dwStatus = PDH_CALC_NEGATIVE_VALUE; dReturn = (double) 0.0; } else { dReturn = (double)llNumDiff; } } if (pdwStatus != NULL) { * pdwStatus = dwStatus; } return dReturn; } PDH_STATUS PdhiComputeFormattedValue( LPCOUNTERCALC pCalcFunc, DWORD dwCounterType, LONG lScale, DWORD dwFormat, PPDH_RAW_COUNTER pRawValue1, PPDH_RAW_COUNTER pRawValue2, PLONGLONG pTimeBase, DWORD dwReserved, PPDH_FMT_COUNTERVALUE pValue ) { double dResult = (double)0.0; double dScale; PDH_STATUS lStatus = ERROR_SUCCESS; DWORD dwValueStatus = PDH_CSTATUS_VALID_DATA; UNREFERENCED_PARAMETER(dwReserved); __try { // make sure the counter values are valid before continuing if (pRawValue1 != NULL) { if ((pRawValue1->CStatus != PDH_CSTATUS_NEW_DATA) && (pRawValue1->CStatus != PDH_CSTATUS_VALID_DATA)) { dwValueStatus = pRawValue1->CStatus; lStatus = PDH_INVALID_DATA; } } else { // this is a required parameter dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } if ((lStatus == ERROR_SUCCESS) && (pRawValue2 != NULL)) { if (PdhiCounterNeedLastValue(dwCounterType) == TRUE) { // this is an optional parameter, but if present, it must be valid if ((pRawValue2->CStatus != PDH_CSTATUS_NEW_DATA) && (pRawValue2->CStatus != PDH_CSTATUS_VALID_DATA)) { dwValueStatus = pRawValue2->CStatus; lStatus = PDH_INVALID_DATA; } } } if (((dwFormat & PDH_FMT_LONG) != 0) && ((dwFormat & PDH_FMT_LARGE) != 0)) { dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } else if (((dwFormat & PDH_FMT_LONG) != 0) || ((dwFormat & PDH_FMT_LARGE) != 0)) { if (dwFormat & PDH_FMT_DOUBLE) { dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } } if (lScale > PDH_MAX_SCALE || lScale < PDH_MIN_SCALE) { dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } if (pTimeBase == NULL) { dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } else { LONGLONG tmpTimeBase = * pTimeBase; * pTimeBase = tmpTimeBase; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwValueStatus = PDH_CSTATUS_INVALID_DATA; lStatus = PDH_INVALID_ARGUMENT; } if (lStatus == ERROR_SUCCESS) { // call the counter's calculation function if the raw value is valid if (IsSuccessSeverity(pRawValue1->CStatus)) { __try { dResult = (* pCalcFunc)(pRawValue1, pRawValue2, pTimeBase, & dwValueStatus); // format returned value if ((dwCounterType & 0xF0000000) == PERF_DISPLAY_PERCENT) { // scale to show percent dResult *= (double) 100.0; // this should probably be controlled by a registry // value as is the case with PERFMON if (! (dwFormat & PDH_FMT_NOCAP100)) { if (dResult > (double) 100.0) dResult = (double) 100.0; } } if (!(dwFormat & PDH_FMT_NOSCALE)) { //now scale dScale = pow(10.0, (double)lScale); dResult *= dScale; } if (dwFormat & PDH_FMT_1000) { //now scale dResult *= (double) 1000.0; } } __except (EXCEPTION_EXECUTE_HANDLER) { // something failed dResult = (double) 0.0; dwValueStatus = PDH_INVALID_ARGUMENT; } } else { dwValueStatus = pRawValue1->CStatus; } if (!IsSuccessSeverity(dwValueStatus)) { // an error occured so pass that on to the caller lStatus = dwValueStatus; } } //end if valid counter data // now format __try { if (dwFormat & PDH_FMT_LONG) { pValue->longValue = (LONG) dResult; } else if (dwFormat & PDH_FMT_LARGE) { pValue->largeValue = (LONGLONG) dResult; } else { // double is the default pValue->doubleValue = dResult; } pValue->CStatus = dwValueStatus; } __except (EXCEPTION_EXECUTE_HANDLER) { lStatus = PDH_INVALID_ARGUMENT; } return lStatus; }