#include "stdafx.h"
#include <cassert>
#include <iostream>
#include <iomanip>
#include <string>
#include <functional>
#include <cmath>
#include <limits>
#include "statisticalTimer.CPU.h"
#include "../library/private.h"
#if defined( __GNUC__ )
#include <sys/time.h>
#endif
template< typename T > std::basic_string<TCHAR> commatize (T number)
{
static TCHAR scratch [8*sizeof(T)];
register TCHAR * ptr = scratch + countOf( scratch );
*(--ptr) = 0;
for (int digits = 3; ; )
{
*(--ptr) = '0' + int (number % 10);
number /= 10;
if (0 == number)
break;
if (--digits <= 0)
{
*(--ptr) = ',';
digits = 3;
}
}
return std::basic_string<TCHAR> (ptr);
}
template< typename T >
struct Accumulator: public std::unary_function< T, void >
{
T acc;
Accumulator( ): acc( 0 ) {}
void operator( )(T x) { acc += x; }
};
template< typename RangeType, typename ValType >
struct PruneRange
{
RangeType lower, upper;
PruneRange( RangeType mean, RangeType stdev ): lower( mean-stdev ), upper( mean+stdev ) {}
bool operator( )( ValType val )
{
if( static_cast< RangeType >( val ) < lower )
return true;
else if( static_cast< RangeType >( val ) > upper )
return true;
return false;
}
};
CpuStatTimer&
CpuStatTimer::getInstance( )
{
static CpuStatTimer timer;
return timer;
}
CpuStatTimer::CpuStatTimer( ): nEvents( 0 ), nSamples( 0 ), normalize( true )
{
#if defined( _WIN32 )
::QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &clkFrequency ) );
#else
res.tv_sec = 0;
res.tv_nsec = 0;
clkFrequency = 0;
{
clkFrequency = 1000000;
}
#endif
}
CpuStatTimer::~CpuStatTimer( )
{}
void
CpuStatTimer::Clear( )
{
labelID.clear( );
clkStart.clear( );
clkTicks.clear( );
}
void
CpuStatTimer::Reset( )
{
if( nEvents == 0 || nSamples == 0 )
throw std::runtime_error( "StatisticalTimer::Reserve( ) was not called before Reset( )" );
clkStart.clear( );
clkTicks.clear( );
clkStart.resize( nEvents );
clkTicks.resize( nEvents );
for( cl_uint i = 0; i < nEvents; ++i )
{
clkTicks.at( i ).reserve( nSamples );
}
return;
}
void
CpuStatTimer::Reserve( size_t nEvents, size_t nSamples )
{
this->nEvents = std::max< size_t >( 1, nEvents );
this->nSamples = std::max< size_t >( 1, nSamples );
Clear( );
labelID.reserve( nEvents );
clkStart.resize( nEvents );
clkTicks.resize( nEvents );
for( cl_uint i = 0; i < nEvents; ++i )
{
clkTicks.at( i ).reserve( nSamples );
}
}
void
CpuStatTimer::setNormalize( bool norm )
{
normalize = norm;
}
void
CpuStatTimer::Start( size_t id )
{
#if defined( _WIN32 )
::QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &clkStart.at( id ) ) );
#else
if( clkFrequency )
{
struct timeval s;
gettimeofday( &s, 0 );
clkStart.at( id ) = (cl_ulong)s.tv_sec * 1000000 + (cl_ulong)s.tv_usec;
}
else
{
}
#endif
}
void
CpuStatTimer::Stop( size_t id )
{
cl_ulong n;
#if defined( _WIN32 )
::QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &n ) );
#else
struct timeval s;
gettimeofday( &s, 0 );
n = (cl_ulong)s.tv_sec * 1000000 + (cl_ulong)s.tv_usec;
#endif
n -= clkStart.at( id );
clkStart.at( id ) = 0;
AddSample( id, n );
}
void
CpuStatTimer::AddSample( const size_t id, const cl_ulong n )
{
clkTicks.at( id ).push_back( n );
}
size_t
CpuStatTimer::getUniqueID( const std::string& label, cl_uint groupID )
{
labelPair sItem = std::make_pair( label, groupID );
stringVector::iterator iter;
iter = std::find( labelID.begin(), labelID.end(), sItem );
if( iter != labelID.end( ) )
return std::distance( labelID.begin( ), iter );
labelID.push_back( sItem );
return labelID.size( ) - 1;
}
cl_double
CpuStatTimer::getMean( size_t id ) const
{
if( clkTicks.empty( ) )
return 0;
size_t N = clkTicks.at( id ).size( );
Accumulator<cl_ulong> sum = std::for_each( clkTicks.at( id ).begin(), clkTicks.at( id ).end(), Accumulator<cl_ulong>() );
return static_cast<cl_double>( sum.acc ) / N;
}
cl_double
CpuStatTimer::getVariance( size_t id ) const
{
if( clkTicks.empty( ) )
return 0;
cl_double mean = getMean( id );
size_t N = clkTicks.at( id ).size( );
cl_double sum = 0;
for( cl_uint i = 0; i < N; ++i )
{
cl_double diff = clkTicks.at( id ).at( i ) - mean;
diff *= diff;
sum += diff;
}
return sum / N;
}
cl_double
CpuStatTimer::getStdDev( size_t id ) const
{
cl_double variance = getVariance( id );
return sqrt( variance );
}
cl_double
CpuStatTimer::getAverageTime( size_t id ) const
{
if( normalize )
return getMean( id ) / clkFrequency;
else
return getMean( id );
}
cl_double
CpuStatTimer::getMinimumTime( size_t id ) const
{
clkVector::const_iterator iter = std::min_element( clkTicks.at( id ).begin( ), clkTicks.at( id ).end( ) );
if( iter != clkTicks.at( id ).end( ) )
{
if( normalize )
return static_cast<cl_double>( *iter ) / clkFrequency;
else
return static_cast<cl_double>( *iter );
}
else
return 0;
}
std::vector< size_t >
CpuStatTimer::pruneOutliers( size_t id , cl_double multiple )
{
return std::vector< size_t >( );
}
size_t
CpuStatTimer::pruneOutliers( cl_double multiple )
{
size_t tCount = 0;
return tCount;
}
void
CpuStatTimer::Print( )
{
}
std::ostream&
operator<<( std::ostream& os, const CpuStatTimer& st )
{
if( st.clkTicks.empty( ) )
return os;
std::ios::fmtflags bckup = os.flags( );
for( cl_uint l = 0; l < st.labelID.size( ); ++l )
{
cl_ulong min = 0;
CpuStatTimer::clkVector::const_iterator iter = std::min_element( st.clkTicks.at( l ).begin( ), st.clkTicks.at( l ).end( ) );
if( iter != st.clkTicks.at( l ).end( ) )
min = *iter;
os << st.labelID[l].first << ", " << st.labelID[l].second << std::fixed << std::endl;
os << "Min:," << min << std::endl;
os << "Mean:," << st.getMean( l ) << std::endl;
os << "StdDev:," << st.getStdDev( l ) << std::endl;
os << "AvgTime:," << st.getAverageTime( l ) << std::endl;
os << "MinTime:," << st.getMinimumTime( l ) << std::endl;
os << "\n" << std::endl;
}
os.flags( bckup );
return os;
}