2021-11-05 17:34:23 +00:00
/***
Copyright ( C ) 2021 J Reece Wilson ( a / k / a " Reece " ) . All rights reserved .
File : SocketStatAverageBps . hpp
Date : 2021 - 10 - 31
Author : Reece
* * */
# pragma once
namespace Aurora : : IO : : Net
{
struct SocketStatAverageBps
{
inline AuUInt32 GetBytesPerMS ( AuUInt32 timeNow )
{
2021-11-07 20:17:02 +00:00
if ( ! frameLastEnd ) return bytesTransferred ;
return ( double ( bytesTransferred ) / ( double ( timeNow - frameLastEnd ) + std : : numeric_limits < double > : : epsilon ( ) ) ) ;
2021-11-05 17:34:23 +00:00
}
inline AuUInt32 GetBytesPerSecondNormalized ( AuUInt32 timeNow )
{
AU_LOCK_GUARD ( lock ) ;
// If timeNow isn't at least that of one socket frame, then we just have to return some old data
if ( frameZero ) return GetLastBytesPerSecond ( ) ;
// Cool we can extrapolate usage using a time weight at least that of one server frame
// Some useful variables...
auto frameAtPoint = GetBytesPerMS ( timeNow ) ;
2021-11-07 20:17:02 +00:00
auto timeElapsed = timeNow - frameLastEnd ; // time elapsed since last packet dispatch finish. makes sense to use this is the packet delta of a high bandwidth stream
2021-11-05 17:34:23 +00:00
2021-11-07 20:17:02 +00:00
// Edge case: we aren't receiving much data. if we have more than 1 second of data, we should use the stream average
if ( timeElapsed > 1000 ) return frameAtPoint * 1000 ; // from ms
2021-11-05 17:34:23 +00:00
// else assume constant usage will continue to trend for at least another second
// the actual extrapolation
auto weight = double ( 1000 ) / double ( timeElapsed ) ;
return double ( frameAtPoint ) * weight ;
}
inline AuUInt32 GetLastBytesPerSecond ( )
{
AU_LOCK_GUARD ( lock ) ;
2021-11-07 20:17:02 +00:00
return double ( lastBytesTransferred ) / ( double ( frameLastEnd - frameLastStart ) + std : : numeric_limits < double > : : epsilon ( ) ) * 1000.f ;
2021-11-05 17:34:23 +00:00
}
inline void Reset ( )
{
bytesTransferred = 0 ;
frameStart = 0 ;
frameLastEnd = 0 ;
frameLastStart = 0 ;
2021-11-07 20:17:02 +00:00
frameZero = true ;
2021-11-05 17:34:23 +00:00
lastBytesTransferred = 0 ;
}
inline void Add ( AuUInt32 timeNow , AuUInt32 bytes )
{
AU_LOCK_GUARD ( lock ) ;
auto nextTick = frameLastEnd + 1000 ;
if ( nextTick < timeNow )
{
frameLastEnd = timeNow ;
frameLastStart = std : : exchange ( frameStart , timeNow ) ;
lastBytesTransferred = std : : exchange ( bytesTransferred , bytes ) ;
frameZero = true ;
}
else
{
frameZero = false ;
bytesTransferred + = bytes ;
}
}
AuThreadPrimitives : : SpinLock lock ;
AuUInt32 frameStart { } ;
AuUInt32 bytesTransferred { } ;
AuUInt32 frameLastStart { } ;
AuUInt32 frameLastEnd { } ;
AuUInt32 lastBytesTransferred { } ;
bool frameZero { true } ;
} ;
}