//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef SMOOTH_AVERAGE_H #define SMOOTH_AVERAGE_H #ifdef _WIN32 #pragma once #endif #include "utldict.h" // Use this macro around any value, and it'll queue up the results given to it // nTimes and provide a running average. #define SMOOTH_AVERAGE(value, nCount) \ CalcSmoothAverage(value, nCount, __FILE__, __LINE__) // Same as their counterpart functions but they return more info in a // CTimingInfo structure. #define SMOOTH_AVERAGE_STRUCT(value, nCount) \ CalcSmoothAverage_Struct(value, nCount, __FILE__, __LINE__) #define SUM_OVER_TIME_INTERVAL_STRUCT(value, nSeconds) \ SumOverTimeInterval_Struct(value, nSeconds, __FILE__, __LINE__) template class CTimingInfo { public: T m_AverageValue; // Note: this will be the SUM of the values if using // SUM_OVER_TIME_INTERVAL. // The high and low points for m_AverageValue over the time interval. T m_HighAverage; T m_LowAverage; // The high and low points for the value itself over the time interval. T m_HighValue; T m_LowValue; }; template class CAveragesInfo { public: class CEntry { public: T m_Average; T m_Value; }; public: CUtlVector m_Values; int m_iCurValue; }; template class CAveragesInfo_TimeBased { public: class CEntry { public: CCycleCount m_Time; // When this sample was taken. T m_Value; T m_Average; }; CUtlVector m_Values; }; #if 0 template< class T > inline CTimingInfo< T > CalcSmoothAverage_Struct( const T &value, int nTimes, const char *pFilename, int iLine ) { // Find an entry at this file and line. char fullStr[1024]; Q_snprintf( fullStr, sizeof( fullStr ), "%s_%i", pFilename, iLine ); int index = s_SmoothAverages.Find( fullStr ); CAveragesInfo *pInfo; if ( index == s_SmoothAverages.InvalidIndex() ) { pInfo = new CAveragesInfo; index = s_SmoothAverages.Insert( fullStr, pInfo ); } else { pInfo = (CAveragesInfo*)s_SmoothAverages[index]; } // Add the new value. int newValueIndex; CAveragesInfo< T >::CEntry entry; entry.m_Value = value; if ( pInfo->m_Values.Count() < nTimes ) { newValueIndex = pInfo->m_Values.AddToTail( entry ); pInfo->m_iCurValue = 0; } else { newValueIndex = pInfo->m_iCurValue; pInfo->m_Values[pInfo->m_iCurValue] = entry; pInfo->m_iCurValue = (pInfo->m_iCurValue+1) % pInfo->m_Values.Count(); } CTimingInfo< T > info; info.m_AverageValue = pInfo->m_Values[0].m_Value; info.m_HighAverage = pInfo->m_Values[0].m_Average; info.m_LowAverage = pInfo->m_Values[0].m_Average; info.m_HighValue = pInfo->m_Values[0].m_Value; info.m_LowValue = pInfo->m_Values[0].m_Value; for ( int i=1; i < pInfo->m_Values.Count(); i++ ) { if ( i != newValueIndex ) { info.m_HighAverage = max( pInfo->m_Values[i].m_Average, info.m_HighAverage ); info.m_LowAverage = min( pInfo->m_Values[i].m_Average, info.m_LowAverage ); } info.m_HighValue = max( pInfo->m_Values[i].m_Value, info.m_HighValue ); info.m_LowValue = min( pInfo->m_Values[i].m_Value, info.m_LowValue ); info.m_AverageValue += pInfo->m_Values[i].m_Value; } info.m_AverageValue /= pInfo->m_Values.Count(); pInfo->m_Values[newValueIndex].m_Average = info.m_AverageValue; return info; } #endif template inline T CalcSmoothAverage(const T &value, int nTimes, const char *pFilename, int iLine) { CTimingInfo info = CalcSmoothAverage_Struct(value, nTimes, pFilename, iLine); return info.m_AverageValue; }; template inline CTimingInfo SumOverTimeInterval_Struct(const T &value, float nSeconds, const char *pFilename, int iLine) { static CUtlDict *, int> s_SmoothAverages; char fullStr[1024]; Q_snprintf(fullStr, sizeof(fullStr), "%s_%i", pFilename, iLine); int index = s_SmoothAverages.Find(fullStr); CAveragesInfo_TimeBased *pInfo; if (index == s_SmoothAverages.InvalidIndex()) { pInfo = new CAveragesInfo_TimeBased; index = s_SmoothAverages.Insert(fullStr, pInfo); } else { pInfo = s_SmoothAverages[index]; } // Get the current time now. CCycleCount curTime; curTime.Sample(); // Get rid of old samples. while (pInfo->m_Values.Count() > 0 && (curTime.GetSeconds() - pInfo->m_Values[0].m_Time.GetSeconds()) > nSeconds) pInfo->m_Values.Remove(0); // Add on the new sample. typename CAveragesInfo_TimeBased::CEntry newEntry; newEntry.m_Time = curTime; newEntry.m_Value = value; int newValueIndex = pInfo->m_Values.AddToTail(newEntry); CTimingInfo info; info.m_AverageValue = pInfo->m_Values[0].m_Value; info.m_HighAverage = pInfo->m_Values[0].m_Average; info.m_LowAverage = pInfo->m_Values[0].m_Average; info.m_HighValue = pInfo->m_Values[0].m_Value; info.m_LowValue = pInfo->m_Values[0].m_Value; for (int i = 1; i < pInfo->m_Values.Count(); i++) { if (i != newValueIndex) { info.m_HighAverage = max(pInfo->m_Values[i].m_Average, info.m_HighAverage); info.m_LowAverage = min(pInfo->m_Values[i].m_Average, info.m_LowAverage); } info.m_HighValue = max(pInfo->m_Values[i].m_Value, info.m_HighValue); info.m_LowValue = min(pInfo->m_Values[i].m_Value, info.m_LowValue); info.m_AverageValue += pInfo->m_Values[i].m_Value; } info.m_AverageValue /= pInfo->m_Values.Count(); pInfo->m_Values[newValueIndex].m_Average = info.m_AverageValue; return info; } template inline CTimingInfo SumOverTimeInterval(const T &value, float nSeconds, const char *pFilename, int iLine) { CTimingInfo info = SumOverTimeInterval_Struct(value, nSeconds, pFilename, iLine); return info.m_AverageValue; } #endif // SMOOTH_AVERAGE_H