/*++ Copyright (C) 1995-1999 Microsoft Corporation Module Name: calcfuns.c Abstract: Counter calculation functions --*/ #include #include #include #include #include #include "pdhicalc.h" #include "pdhitype.h" #include "pdhidef.h" #include "pdhmsg.h" BOOL AssignCalcFunction ( IN DWORD dwCounterType, IN LPCOUNTERCALC *pCalcFunc, IN LPCOUNTERSTAT *pStatFunc ) { BOOL bReturn = TRUE; // reset the last error value SetLastError (ERROR_SUCCESS); if (pCalcFunc == NULL || pStatFunc == NULL) { SetLastError(PDH_INVALID_ARGUMENT); return FALSE; } else { __try { * pCalcFunc = PdhiCalcNoData; * pStatFunc = PdhiComputeNoDataStats; } except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } } 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; } 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) { 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) { 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 { // just return 0 & normal status } } 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) { 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 { // just return 0 and a normal status } } 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) { 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) { dwStatus = PDH_CALC_NEGATIVE_VALUE; dReturn = (double)0.0; } else { dReturn = (double)llNumDiff; } } if (pdwStatus != NULL) { *pdwStatus = dwStatus; } return dReturn; } PDH_STATUS PdhiComputeFormattedValue ( IN LPCOUNTERCALC pCalcFunc, IN DWORD dwCounterType, IN LONG lScale, IN DWORD dwFormat, IN PPDH_RAW_COUNTER pRawValue1, IN PPDH_RAW_COUNTER pRawValue2, IN PLONGLONG pTimeBase, IN DWORD dwReserved, IN 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)) { // 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; }