windows-nt/Source/XPSP1/NT/sdktools/pdh/pdhcalc/calcfuns.c
2020-09-26 16:20:57 +08:00

746 lines
21 KiB
C

/*++
Copyright (C) 1995-1999 Microsoft Corporation
Module Name:
calcfuns.c
Abstract:
Counter calculation functions
--*/
#include <windows.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <pdh.h>
#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;
}