//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#if defined(FORCE_TIMER_ON) || defined(_DEBUG)
#ifndef timer_on
#define timer_on 1
#endif
#else
#undef timer_on
#define timer_on 0
#endif

#define RECURSIVE_TIMERS

#if timer_on

//#pragma message("<<<<Timer ON>>>>")

	typedef struct _TIMER_ENTRY
	{
		__int64 		Start;
		__int64 		SubTime;
	} TIMER_ENTRY;

	typedef struct _TIMER_STACK
	{
		unsigned int	CurrentDepth;		// Our current position in the stack
		unsigned int	LargestDepth;		// How much we would need
		unsigned int	MaxDepth;			// How much we currently have
		TIMER_ENTRY 	*Entries;
	} TIMER_STACK;

	typedef struct _TIMER
	{
		__int64 		Time;
		unsigned int	Count;
		char *			Name;
		struct _TIMER * Next;
		__int64 		SubTime;
		TIMER_STACK *	Stack;
	} TIMER;

#ifndef _WINBASE_
	typedef __int64 LARGE_INTEGER;
#ifdef __cplusplus
extern "C" {
#endif
	extern int __stdcall QueryPerformanceCounter(LARGE_INTEGER*);
	extern int __stdcall QueryPerformanceFrequency(LARGE_INTEGER*);
#ifdef __cplusplus
}
#endif
#endif

#define USE_RDTSC

#ifdef USE_RDTSC
	EXTERN_C int rdtsc_freq;
	__inline int tickrate()
	{
		return rdtsc_freq;
	}

	#define SNAP_TIME_XX(time)		\
	{								\
		{							\
			_asm	pushfd			\
			_asm	pushad			\
		}							\
		{							\
			__int64 *p = &time; 	\
			_asm	_emit 0Fh		\
			_asm	_emit 0A2h		\
			_asm	_emit 0Fh		\
			_asm	_emit 31h		\
			_asm	mov ecx,p		\
			_asm	mov [ecx],eax	\
			_asm	mov [ecx+4],edx \
			_asm	_emit 0Fh		\
			_asm	_emit 0A2h		\
		}							\
		{							\
			_asm	popad			\
			_asm	popfd			\
		}							\
	}

	#define SNAP_TIME(time) 		\
	{								\
			__int64 *p = &time; 	\
			_asm	push	eax 	\
			_asm	push	edx 	\
			_asm	_emit 0Fh		\
			_asm	_emit 31h		\
			_asm	mov ecx,p		\
			_asm	mov [ecx],eax	\
			_asm	mov [ecx+4],edx \
			_asm	pop 	edx 	\
			_asm	pop 	eax 	\
	}

#else
	__inline __int64 tickrate() {__int64 i64; QueryPerformanceFrequency((LARGE_INTEGER*)&i64); return i64;}

	#define SNAP_TIME(time) 	\
	{							\
		QueryPerformanceCounter((LARGE_INTEGER *)&time); \
	}

#endif

	#define DECLARE_TIMER(t,n)	TIMER t = {0,0,n}
	#define EXTERN_TIMER(t)		extern TIMER t
	#define ZERO_TIMER(t)		(t).Time = 0, (t).Count = 0, (t).SubTime = 0

	#define TIME_START(t)		START_TIME(t)
	#define TIME_STOP(t)		STOP_TIME(t)
	#define REGISTER_TIMER(t)	timer_register(&(t),1);

#ifdef RECURSIVE_TIMERS
	#define START_TIME_ALT(t)												\
	{																		\
		if ((t).Stack->CurrentDepth > (t).Stack->LargestDepth)				\
		{																	\
			(t).Stack->LargestDepth = (t).Stack->CurrentDepth;				\
		}																	\
		if ((t).Stack->CurrentDepth < (t).Stack->MaxDepth)					\
		{																	\
			(t).Stack->Entries[(t).Stack->CurrentDepth].SubTime = 0;		\
			SNAP_TIME((t).Stack->Entries[(t).Stack->CurrentDepth].Start)	\
		}																	\
		(t).Stack->CurrentDepth++;											\
	}

	#define STOP_TIME(t)													\
	{																		\
		_int64 time;														\
		--(t).Stack->CurrentDepth;											\
		if ((t).Stack->CurrentDepth < (t).Stack->MaxDepth)					\
		{																	\
			SNAP_TIME(time) 												\
			time -= (t).Stack->Entries[(t).Stack->CurrentDepth].Start;		\
			(t).Stack->Entries[(t).Stack->CurrentDepth-1].SubTime += time;	\
			(t).Time += time;												\
			time = (t).Stack->Entries[(t).Stack->CurrentDepth].SubTime; 	\
			(t).SubTime += time;											\
			(t).Count++;													\
		}																	\
	}

#else	// RECURSIVE_TIMERS

	#define START_TIME_ALT(t)												\
	{																		\
		__int64 time;														\
		SNAP_TIME(time) 													\
		(t).Time -= time;													\
	}

	#define STOP_TIME(t)													\
	{																		\
		__int64 time;														\
		SNAP_TIME(time) 													\
		(t).Time += time;													\
		(t).Count++;														\
	}
#endif	// RECURSIVE_TIMERS

	#define START_TIME(t)			\
	{								\
		if ((t).Next==(TIMER*)0)	\
			timer_register(&(t),1); \
		START_TIME_ALT(t)			\
	}

	#define AVE_MS(t)			((t).Count ? (TOTAL_MS(t) / (t).Count) : 0)
	#define AVE_US(t)			((t).Count ? (TOTAL_US(t) / (t).Count) : 0)
	#define TOTAL_MS(t) 		(int)((t).Time * 1000	 / (int)tickrate())
	#define TOTAL_US(t) 		(int)((t).Time * 1000000 / (int)tickrate())
	#define SUBTIME_TOTAL_MS(t) (int)((t).SubTime * 1000	/ (int)tickrate())
	#define SUBTIME_TOTAL_US(t) (int)((t).SubTime * 1000000 / (int)tickrate())

#else
	#define DECLARE_TIMER(t,n)
	#define EXTERN_TIMER(t)
	#define ZERO_TIMER(t)
	#define START_TIME(t)
	#define START_TIME_ALT(t)
	#define STOP_TIME(t)
	#define TIME_START(t)
	#define TIME_STOP(t)
	#define REGISTER_TIMER(t)
#endif
