|
|
//========= 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 T > 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 T > class CAveragesInfo { public: class CEntry { public: T m_Average; T m_Value; };
public: CUtlVector< CEntry > m_Values; int m_iCurValue; };
template< class T > class CAveragesInfo_TimeBased { public: class CEntry { public: CCycleCount m_Time; // When this sample was taken.
T m_Value; T m_Average; }; CUtlVector<CEntry> 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<T> *pInfo; if ( index == s_SmoothAverages.InvalidIndex() ) { pInfo = new CAveragesInfo<T>; index = s_SmoothAverages.Insert( fullStr, pInfo ); } else { pInfo = (CAveragesInfo<T>*)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< class T > inline T CalcSmoothAverage( const T &value, int nTimes, const char *pFilename, int iLine ) { CTimingInfo< T > info = CalcSmoothAverage_Struct( value, nTimes, pFilename, iLine ); return info.m_AverageValue; };
template< class T > inline CTimingInfo< T > SumOverTimeInterval_Struct( const T &value, float nSeconds, const char *pFilename, int iLine ) { static CUtlDict< CAveragesInfo_TimeBased< T >*, int > s_SmoothAverages;
char fullStr[1024]; Q_snprintf( fullStr, sizeof( fullStr ), "%s_%i", pFilename, iLine ); int index = s_SmoothAverages.Find( fullStr ); CAveragesInfo_TimeBased<T> *pInfo; if ( index == s_SmoothAverages.InvalidIndex() ) { pInfo = new CAveragesInfo_TimeBased<T>; 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< T >::CEntry newEntry; newEntry.m_Time = curTime; newEntry.m_Value = value; int newValueIndex = pInfo->m_Values.AddToTail( newEntry );
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; }
template< class T > inline CTimingInfo< T > SumOverTimeInterval( const T &value, float nSeconds, const char *pFilename, int iLine ) { CTimingInfo< T > info = SumOverTimeInterval_Struct( value, nSeconds, pFilename, iLine ); return info.m_AverageValue; }
#endif // SMOOTH_AVERAGE_H
|