//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#include "tier1/reliabletimer.h"

int64 CReliableTimer::sm_nPerformanceFrequency = 0;
bool CReliableTimer::sm_bUseQPC = false;

#ifdef _WIN32
#include "winlite.h"
#endif

#ifdef POSIX
#include <time.h>
#endif

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CReliableTimer::CReliableTimer()
{
	m_nPerformanceCounterStart = 0;
	m_nPerformanceCounterEnd = 0;
	m_nPerformanceCounterLimit = 0;

#ifdef _WIN32
	// calculate performance frequency the first time we use a timer
	if ( 0 == sm_nPerformanceFrequency )
	{
		// Are we on a bad CPU?
		sm_bUseQPC = false; // todo
		const CPUInformation &cpu = *GetCPUInformation();
		sm_bUseQPC = ( ( 0 == Q_stricmp( cpu.m_szProcessorID, "AuthenticAMD" ) )
			&& ( cpu.m_nPhysicalProcessors > 1 )
			&& !cpu.m_bSSE41 );

		if ( sm_bUseQPC )
		{
			LARGE_INTEGER li;
			QueryPerformanceFrequency( &li );
			sm_nPerformanceFrequency = li.QuadPart;
		}
		else
		{
			sm_nPerformanceFrequency = g_ClockSpeed;
		}
	}
#elif defined(_PS3)
	// On PowerPC, the time base register increment frequency is implementation dependent, and doesn't have to be constant.
	// On PS3, measured it to be just shy of 80Mhz on the PPU and doesn't seem to change
	if ( sm_nPerformanceFrequency == 0 )
		sm_nPerformanceFrequency = sys_time_get_timebase_frequency(); 
#else
	// calculate performance frequency the first time we use a timer
	if ( 0 == sm_nPerformanceFrequency )
	{
		sm_nPerformanceFrequency = g_ClockSpeed;
	}
#endif
}


//-----------------------------------------------------------------------------
// Purpose: Returns current QueryPerformanceCounter value
//-----------------------------------------------------------------------------
int64 CReliableTimer::GetPerformanceCountNow()
{
	//VPROF_BUDGET( "CReliableTimer::GetPerformanceCountNow", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED );
#ifdef _WIN32
	if ( sm_bUseQPC )
	{
		LARGE_INTEGER li = {0};
		QueryPerformanceCounter( &li );
		return li.QuadPart;
	}
	else
	{
		CCycleCount CycleCount;
		CycleCount.Sample();
		return CycleCount.GetLongCycles();
	}
#elif defined( _PS3 )
	// use handy macro to grab tb
	uint64 ulNow;
	SYS_TIMEBASE_GET( ulNow );
	return ulNow;
#elif (defined( __arm__ ) || defined( __aarch64__ )) && defined (POSIX)
	struct timespec ts;
	clock_gettime(CLOCK_REALTIME, &ts);
	return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
#else
	uint64 un64;
	 __asm__ __volatile__ (
                        "rdtsc\n\t"
                        : "=A" (un64) );
	return (int64)un64;
#endif
}
